Merge commit '60b30c0363' as 'lib/lufa'

This commit is contained in:
Jack Humbert 2017-07-07 11:55:23 -04:00
commit 8655d4f494
1455 changed files with 394541 additions and 0 deletions

View file

@ -0,0 +1,87 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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
*
* Address Resolution Protocol (ARP) packet handling routines. This protocol handles the
* conversion of physical MAC addresses to protocol IP addresses between the host and the
* device.
*/
#include "ARP.h"
/** Processes an ARP packet inside an Ethernet frame, and writes the appropriate response
* to the output Ethernet frame if the host is requesting the IP or MAC address of the
* virtual server device on the network.
*
* \param[in] InDataStart Pointer to the start of the incoming packet's ARP header
* \param[out] OutDataStart Pointer to the start of the outgoing packet's ARP header
*
* \return The number of bytes written to the out Ethernet frame if any, NO_RESPONSE otherwise
*/
int16_t ARP_ProcessARPPacket(void* InDataStart,
void* OutDataStart)
{
DecodeARPHeader(InDataStart);
ARP_Header_t* ARPHeaderIN = (ARP_Header_t*)InDataStart;
ARP_Header_t* ARPHeaderOUT = (ARP_Header_t*)OutDataStart;
/* Ensure that the ARP request is a IPv4 request packet */
if ((SwapEndian_16(ARPHeaderIN->ProtocolType) == ETHERTYPE_IPV4) &&
(SwapEndian_16(ARPHeaderIN->Operation) == ARP_OPERATION_REQUEST))
{
/* If the ARP packet is requesting the MAC or IP of the virtual webserver, return the response */
if (IP_COMPARE(&ARPHeaderIN->TPA, &ServerIPAddress) ||
MAC_COMPARE(&ARPHeaderIN->THA, &ServerMACAddress))
{
/* Fill out the ARP response header */
ARPHeaderOUT->HardwareType = ARPHeaderIN->HardwareType;
ARPHeaderOUT->ProtocolType = ARPHeaderIN->ProtocolType;
ARPHeaderOUT->HLEN = ARPHeaderIN->HLEN;
ARPHeaderOUT->PLEN = ARPHeaderIN->PLEN;
ARPHeaderOUT->Operation = SwapEndian_16(ARP_OPERATION_REPLY);
/* Copy over the sender MAC/IP to the target fields for the response */
ARPHeaderOUT->THA = ARPHeaderIN->SHA;
ARPHeaderOUT->TPA = ARPHeaderIN->SPA;
/* Copy over the new sender MAC/IP - MAC and IP addresses of the virtual webserver */
ARPHeaderOUT->SHA = ServerMACAddress;
ARPHeaderOUT->SPA = ServerIPAddress;
/* Return the size of the response so far */
return sizeof(ARP_Header_t);
}
}
return NO_RESPONSE;
}

View file

@ -0,0 +1,76 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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 ARP.c.
*/
#ifndef _ARP_H_
#define _ARP_H_
/* Includes: */
#include <avr/io.h>
#include <string.h>
#include "EthernetProtocols.h"
#include "Ethernet.h"
#include "ProtocolDecoders.h"
/* Macros: */
/** ARP header operation constant, indicating a request from a host for an address translation. */
#define ARP_OPERATION_REQUEST 1
/** ARP header operation constant, indicating a reply from a host giving an address translation. */
#define ARP_OPERATION_REPLY 2
/* Type Defines: */
/** Type define for an ARP packet inside an Ethernet frame. */
typedef struct
{
uint16_t HardwareType; /**< Hardware type constant, indicating the hardware used */
uint16_t ProtocolType; /**< Protocol being resolved, usually ETHERTYPE_IPV4 */
uint8_t HLEN; /**< Length in bytes of the source/destination hardware addresses */
uint8_t PLEN; /**< Length in bytes of the source/destination protocol addresses */
uint16_t Operation; /**< Type of operation, either ARP_OPERATION_REQUEST or ARP_OPERATION_REPLY */
MAC_Address_t SHA; /**< Sender's hardware address */
IP_Address_t SPA; /**< Sender's protocol address */
MAC_Address_t THA; /**< Target's hardware address */
IP_Address_t TPA; /**< Target's protocol address */
} ARP_Header_t;
/* Function Prototypes: */
int16_t ARP_ProcessARPPacket(void* InDataStart,
void* OutDataStart);
#endif

View file

@ -0,0 +1,129 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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
*
* Dynamic Host Configuration Protocol (DHCP) packet handling routines. This protocol
* handles the automatic IP negotiation to the host, so that the host will use the provided
* IP address given to it by the device.
*/
#include "DHCP.h"
/** Processes a DHCP packet inside an Ethernet frame, and writes the appropriate response
* to the output Ethernet frame if the host is requesting or accepting an IP address.
*
* \param[in] IPHeaderInStart Pointer to the start of the incoming packet's IP header
* \param[in] DHCPHeaderInStart Pointer to the start of the incoming packet's DHCP header
* \param[out] DHCPHeaderOutStart Pointer to the start of the outgoing packet's DHCP header
*
* \return The number of bytes written to the out Ethernet frame if any, NO_RESPONSE otherwise
*/
int16_t DHCP_ProcessDHCPPacket(void* IPHeaderInStart,
void* DHCPHeaderInStart,
void* DHCPHeaderOutStart)
{
IP_Header_t* IPHeaderIN = (IP_Header_t*)IPHeaderInStart;
DHCP_Header_t* DHCPHeaderIN = (DHCP_Header_t*)DHCPHeaderInStart;
DHCP_Header_t* DHCPHeaderOUT = (DHCP_Header_t*)DHCPHeaderOutStart;
uint8_t* DHCPOptionsINStart = ((uint8_t*)DHCPHeaderInStart + sizeof(DHCP_Header_t));
uint8_t* DHCPOptionsOUTStart = ((uint8_t*)DHCPHeaderOutStart + sizeof(DHCP_Header_t));
DecodeDHCPHeader(DHCPHeaderInStart);
/* Zero out the response DHCP packet, as much of it is legacy and left at 0 */
memset(DHCPHeaderOUT, 0, sizeof(DHCP_Header_t));
/* Fill out the response DHCP packet */
DHCPHeaderOUT->HardwareType = DHCPHeaderIN->HardwareType;
DHCPHeaderOUT->Operation = DHCP_OP_BOOTREPLY;
DHCPHeaderOUT->HardwareAddressLength = DHCPHeaderIN->HardwareAddressLength;
DHCPHeaderOUT->Hops = 0;
DHCPHeaderOUT->TransactionID = DHCPHeaderIN->TransactionID;
DHCPHeaderOUT->ElapsedSeconds = 0;
DHCPHeaderOUT->Flags = DHCPHeaderIN->Flags;
DHCPHeaderOUT->YourIP = ClientIPAddress;
memmove(&DHCPHeaderOUT->ClientHardwareAddress, &DHCPHeaderIN->ClientHardwareAddress, sizeof(MAC_Address_t));
DHCPHeaderOUT->Cookie = SwapEndian_32(DHCP_MAGIC_COOKIE);
/* Alter the incoming IP packet header so that the corrected IP source and destinations are used - this means that
when the response IP header is generated, it will use the corrected addresses and not the null/broatcast addresses */
IPHeaderIN->SourceAddress = ClientIPAddress;
IPHeaderIN->DestinationAddress = ServerIPAddress;
/* Process the incoming DHCP packet options */
while (DHCPOptionsINStart[0] != DHCP_OPTION_END)
{
/* Find the Message Type DHCP option, to determine the type of DHCP packet */
if (DHCPOptionsINStart[0] == DHCP_OPTION_MESSAGETYPE)
{
if ((DHCPOptionsINStart[2] == DHCP_MESSAGETYPE_DISCOVER) || (DHCPOptionsINStart[2] == DHCP_MESSAGETYPE_REQUEST))
{
/* Fill out the response DHCP packet options for a DHCP OFFER or ACK response */
*(DHCPOptionsOUTStart++) = DHCP_OPTION_MESSAGETYPE;
*(DHCPOptionsOUTStart++) = 1;
*(DHCPOptionsOUTStart++) = (DHCPOptionsINStart[2] == DHCP_MESSAGETYPE_DISCOVER) ? DHCP_MESSAGETYPE_OFFER
: DHCP_MESSAGETYPE_ACK;
*(DHCPOptionsOUTStart++) = DHCP_OPTION_SUBNETMASK;
*(DHCPOptionsOUTStart++) = sizeof(IP_Address_t);
*(DHCPOptionsOUTStart++) = 0xFF;
*(DHCPOptionsOUTStart++) = 0xFF;
*(DHCPOptionsOUTStart++) = 0xFF;
*(DHCPOptionsOUTStart++) = 0x00;
*(DHCPOptionsOUTStart++) = DHCP_OPTION_LEASETIME;
*(DHCPOptionsOUTStart++) = sizeof(uint32_t);
/* Lease Time 86400s (ONE_DAY) */
*(DHCPOptionsOUTStart++) = 0x00;
*(DHCPOptionsOUTStart++) = 0x01;
*(DHCPOptionsOUTStart++) = 0x51;
*(DHCPOptionsOUTStart++) = 0x80;
*(DHCPOptionsOUTStart++) = DHCP_OPTION_DHCPSERVER;
*(DHCPOptionsOUTStart++) = sizeof(IP_Address_t);
memcpy(DHCPOptionsOUTStart, &ServerIPAddress, sizeof(IP_Address_t));
DHCPOptionsOUTStart += sizeof(IP_Address_t);
*(DHCPOptionsOUTStart++) = DHCP_OPTION_END;
return (sizeof(DHCP_Header_t) + 18 + sizeof(IP_Address_t));
}
}
/* Go to the next DHCP option - skip one byte if option is a padding byte, else skip the complete option's size */
DHCPOptionsINStart += ((DHCPOptionsINStart[0] == DHCP_OPTION_PAD) ? 1 : (DHCPOptionsINStart[1] + 2));
}
return NO_RESPONSE;
}

View file

@ -0,0 +1,131 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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 DHCP.c.
*/
#ifndef _DHCP_H_
#define _DHCP_H_
/* Includes: */
#include <avr/io.h>
#include <string.h>
#include "EthernetProtocols.h"
#include "Ethernet.h"
#include "ProtocolDecoders.h"
/* Macros: */
/** DHCP operation constant, indicating a request from a host to a DHCP server. */
#define DHCP_OP_BOOTREQUEST 0x01
/** DHCP operation constant, indicating a reply from a DHCP server to a host. */
#define DHCP_OP_BOOTREPLY 0x02
/** Hardware type constant, indicating Ethernet as a carrier. */
#define DHCP_HTYPE_ETHERNET 0x01
/** Magic boot protocol "cookie", inserted into all BOOTP packets (BOOTP is the carrier of DHCP). */
#define DHCP_MAGIC_COOKIE 0x63825363
/** DHCP option list entry header, indicating that a subnet mask will follow. */
#define DHCP_OPTION_SUBNETMASK 1
/** DHCP option list entry header, indicating that the Lease Time will follow. */
#define DHCP_OPTION_LEASETIME 51
/** DHCP option list entry header, indicating that the DHCP message type constant will follow. */
#define DHCP_OPTION_MESSAGETYPE 53
/** DHCP option list entry header, indicating that the IP address of the DHCP server will follow. */
#define DHCP_OPTION_DHCPSERVER 54
/** DHCP option list entry header, used to pad out option data. */
#define DHCP_OPTION_PAD 0
/** DHCP option list entry header, indicating the end of option data. */
#define DHCP_OPTION_END 255
/** Message type constant, used in the DHCP option data field, requesting that a DHCP server offer an IP address. */
#define DHCP_MESSAGETYPE_DISCOVER 1
/** Message type constant, used in the DHCP option data field, indicating that a DHCP server is offering an IP address. */
#define DHCP_MESSAGETYPE_OFFER 2
/** Message type constant, used in the DHCP option data field, requesting that a DHCP server lease a given IP address. */
#define DHCP_MESSAGETYPE_REQUEST 3
/** Message type constant, used in the DHCP option data field, declining an offered DHCP server IP address lease. */
#define DHCP_MESSAGETYPE_DECLINE 4
/** Message type constant, used in the DHCP option data field, ACKing a host IP lease request. */
#define DHCP_MESSAGETYPE_ACK 5
/** Message type constant, used in the DHCP option data field, NACKing a host IP lease request. */
#define DHCP_MESSAGETYPE_NACK 6
/** Message type constant, used in the DHCP option data field, indicating that a host is releasing a leased IP address. */
#define DHCP_MESSAGETYPE_RELEASE 7
/* Type Defines: */
/** Type define for a DHCP packet inside an Ethernet frame. */
typedef struct
{
uint8_t Operation; /**< DHCP operation, either DHCP_OP_BOOTREQUEST or DHCP_OP_BOOTREPLY */
uint8_t HardwareType; /**< Hardware carrier type constant */
uint8_t HardwareAddressLength; /**< Length in bytes of a hardware (MAC) address on the network */
uint8_t Hops; /**< Number of hops required to reach the server, unused */
uint32_t TransactionID; /**< Unique ID of the DHCP packet, for positive matching between sent and received packets */
uint16_t ElapsedSeconds; /**< Elapsed seconds since the request was made */
uint16_t Flags; /**< BOOTP packet flags */
IP_Address_t ClientIP; /**< Client IP address, if already leased an IP */
IP_Address_t YourIP; /**< Client IP address */
IP_Address_t NextServerIP; /**< Legacy BOOTP protocol field, unused for DHCP */
IP_Address_t RelayAgentIP; /**< Legacy BOOTP protocol field, unused for DHCP */
uint8_t ClientHardwareAddress[16]; /**< Hardware (MAC) address of the client making a request to the DHCP server */
uint8_t ServerHostnameString[64]; /**< Legacy BOOTP protocol field, unused for DHCP */
uint8_t BootFileName[128]; /**< Legacy BOOTP protocol field, unused for DHCP */
uint32_t Cookie; /**< Magic BOOTP protocol cookie to indicate a valid packet */
} DHCP_Header_t;
/* Function Prototypes: */
int16_t DHCP_ProcessDHCPPacket(void* IPHeaderInStart,
void* DHCPHeaderInStart,
void* DHCPHeaderOutStart);
#endif

View file

@ -0,0 +1,132 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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
*
* Ethernet frame packet handling routines. This protocol handles the processing of raw Ethernet
* frames sent and received, deferring the processing of sub-packet protocols to the appropriate
* protocol handlers, such as DHCP or ARP.
*/
#include "Ethernet.h"
/** Constant for convenience when checking against or setting a MAC address to the virtual server MAC address. */
const MAC_Address_t ServerMACAddress = {SERVER_MAC_ADDRESS};
/** Constant for convenience when checking against or setting an IP address to the virtual server IP address. */
const IP_Address_t ServerIPAddress = {SERVER_IP_ADDRESS};
/** Constant for convenience when checking against or setting a MAC address to the broadcast MAC address. */
const MAC_Address_t BroadcastMACAddress = {BROADCAST_MAC_ADDRESS};
/** Constant for convenience when checking against or setting a IP address to the broadcast IP address. */
const IP_Address_t BroadcastIPAddress = {BROADCAST_IP_ADDRESS};
/** Constant for convenience when checking against or setting an IP address to the client (host) IP address. */
const IP_Address_t ClientIPAddress = {CLIENT_IP_ADDRESS};
/** Processes an incoming Ethernet frame, and writes the appropriate response to the output Ethernet
* frame buffer if the sub protocol handlers create a valid response.
*/
void Ethernet_ProcessPacket(Ethernet_Frame_Info_t* const FrameIN,
Ethernet_Frame_Info_t* const FrameOUT)
{
DecodeEthernetFrameHeader(FrameIN->FrameData);
/* Cast the incoming Ethernet frame to the Ethernet header type */
Ethernet_Frame_Header_t* FrameINHeader = (Ethernet_Frame_Header_t*)&FrameIN->FrameData;
Ethernet_Frame_Header_t* FrameOUTHeader = (Ethernet_Frame_Header_t*)&FrameOUT->FrameData;
int16_t RetSize = NO_RESPONSE;
/* Ensure frame is addressed to either all (broadcast) or the virtual webserver, and is a type II frame */
if ((MAC_COMPARE(&FrameINHeader->Destination, &ServerMACAddress) ||
MAC_COMPARE(&FrameINHeader->Destination, &BroadcastMACAddress)) &&
(SwapEndian_16(FrameIN->FrameLength) > ETHERNET_VER2_MINSIZE))
{
/* Process the packet depending on its protocol */
switch (SwapEndian_16(FrameINHeader->EtherType))
{
case ETHERTYPE_ARP:
RetSize = ARP_ProcessARPPacket(&FrameIN->FrameData[sizeof(Ethernet_Frame_Header_t)],
&FrameOUT->FrameData[sizeof(Ethernet_Frame_Header_t)]);
break;
case ETHERTYPE_IPV4:
RetSize = IP_ProcessIPPacket(FrameIN,
&FrameIN->FrameData[sizeof(Ethernet_Frame_Header_t)],
&FrameOUT->FrameData[sizeof(Ethernet_Frame_Header_t)]);
break;
}
/* Protocol processing routine has filled a response, complete the ethernet frame header */
if (RetSize > 0)
{
/* Fill out the response Ethernet frame header */
FrameOUTHeader->Source = ServerMACAddress;
FrameOUTHeader->Destination = FrameINHeader->Source;
FrameOUTHeader->EtherType = FrameINHeader->EtherType;
/* Set the response length in the buffer and indicate that a response is ready to be sent */
FrameOUT->FrameLength = (sizeof(Ethernet_Frame_Header_t) + RetSize);
}
}
/* Check if the packet was processed */
if (RetSize != NO_PROCESS)
{
/* Clear the frame buffer */
FrameIN->FrameLength = 0;
}
}
/** Calculates the appropriate ethernet checksum, consisting of the addition of the one's
* compliment of each word, complimented.
*
* \param[in] Data Pointer to the packet buffer data whose checksum must be calculated
* \param[in] Bytes Number of bytes in the data buffer to process
*
* \return A 16-bit Ethernet checksum value
*/
uint16_t Ethernet_Checksum16(void* Data,
uint16_t Bytes)
{
uint16_t* Words = (uint16_t*)Data;
uint32_t Checksum = 0;
for (uint16_t CurrWord = 0; CurrWord < (Bytes >> 1); CurrWord++)
Checksum += Words[CurrWord];
while (Checksum & 0xFFFF0000)
Checksum = ((Checksum & 0xFFFF) + (Checksum >> 16));
return ~Checksum;
}

View file

@ -0,0 +1,101 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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 Ethernet.c.
*/
#ifndef _ETHERNET_H_
#define _ETHERNET_H_
/* Includes: */
#include <avr/io.h>
#include <string.h>
#include <LUFA/Drivers/USB/USB.h>
#include "Config/AppConfig.h"
#include "EthernetProtocols.h"
#include "ProtocolDecoders.h"
#include "ICMP.h"
#include "TCP.h"
#include "UDP.h"
#include "DHCP.h"
#include "ARP.h"
#include "IP.h"
/* Macros: */
/** Physical MAC address of the network broadcast address. */
#define BROADCAST_MAC_ADDRESS {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
/** Performs a comparison between two MAC addresses, indicating if they are identical.
*
* \param[in] MAC1 First MAC address
* \param[in] MAC2 Second MAC address
*
* \return True if the addresses match, \c false otherwise
*/
#define MAC_COMPARE(MAC1, MAC2) (memcmp(MAC1, MAC2, sizeof(MAC_Address_t)) == 0)
/** Minimum size of an Ethernet packet in bytes, to conform to the Ethernet V2 packet standard. */
#define ETHERNET_VER2_MINSIZE 0x0600
/** Return value for all sub protocol handling routines, indicating that no response packet has been generated. */
#define NO_RESPONSE 0
/** Return value for all sub protocol handling routines, indicating that the packet has not yet been handled. */
#define NO_PROCESS -1
/* Type Defines: */
/** Type define for an Ethernet frame header. */
typedef struct
{
MAC_Address_t Destination; /**< Physical MAC address of the packet recipient */
MAC_Address_t Source; /**< Physics MAC address of the packet source */
uint16_t EtherType; /**< Ethernet packet sub-protocol type, for Ethernet V2 packets */
} Ethernet_Frame_Header_t;
/* External Variables: */
extern const MAC_Address_t ServerMACAddress;
extern const IP_Address_t ServerIPAddress;
extern const MAC_Address_t BroadcastMACAddress;
extern const IP_Address_t BroadcastIPAddress;
extern const IP_Address_t ClientIPAddress;
/* Function Prototypes: */
void Ethernet_ProcessPacket(Ethernet_Frame_Info_t* const FrameIN,
Ethernet_Frame_Info_t* const FrameOUT);
uint16_t Ethernet_Checksum16(void* Data,
uint16_t Bytes);
#endif

View file

@ -0,0 +1,92 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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
*
* General Ethernet protocol constants and type defines, for use by
* all network protocol portions of the TCP/IP stack.
*/
#ifndef _ETHERNET_PROTOCOLS_H_
#define _ETHERNET_PROTOCOLS_H_
/* Includes: */
#include <LUFA/Drivers/USB/USB.h>
/* Macros: */
#define ETHERTYPE_IPV4 0x0800
#define ETHERTYPE_ARP 0x0806
#define ETHERTYPE_RARP 0x8035
#define ETHERTYPE_APPLETALK 0x809b
#define ETHERTYPE_APPLETALKARP 0x80f3
#define ETHERTYPE_IEEE8021Q 0x8100
#define ETHERTYPE_NOVELLIPX 0x8137
#define ETHERTYPE_NOVELL 0x8138
#define ETHERTYPE_IPV6 0x86DD
#define ETHERTYPE_COBRANET 0x8819
#define ETHERTYPE_PROVIDERBRIDGING 0x88a8
#define ETHERTYPE_MPLSUNICAST 0x8847
#define ETHERTYPE_MPLSMULTICAST 0x8848
#define ETHERTYPE_PPPoEDISCOVERY 0x8863
#define ETHERTYPE_PPPoESESSION 0x8864
#define ETHERTYPE_EAPOVERLAN 0x888E
#define ETHERTYPE_HYPERSCSI 0x889A
#define ETHERTYPE_ATAOVERETHERNET 0x88A2
#define ETHERTYPE_ETHERCAT 0x88A4
#define ETHERTYPE_SERCOSIII 0x88CD
#define ETHERTYPE_CESoE 0x88D8
#define ETHERTYPE_MACSECURITY 0x88E5
#define ETHERTYPE_FIBRECHANNEL 0x8906
#define ETHERTYPE_QINQ 0x9100
#define ETHERTYPE_VLLT 0xCAFE
#define PROTOCOL_ICMP 1
#define PROTOCOL_IGMP 2
#define PROTOCOL_TCP 6
#define PROTOCOL_UDP 17
#define PROTOCOL_OSPF 89
#define PROTOCOL_SCTP 132
/* Type Defines: */
/** Type define for an Ethernet frame buffer data and information structure. */
typedef struct
{
uint8_t FrameData[ETHERNET_FRAME_SIZE_MAX]; /**< Ethernet frame contents. */
uint16_t FrameLength; /**< Length in bytes of the Ethernet frame stored in the buffer. */
} Ethernet_Frame_Info_t;
/** Type define for a protocol IP address of a device on a network. */
typedef struct
{
uint8_t Octets[4]; /**< Individual bytes of an IP address */
} IP_Address_t;
#endif

View file

@ -0,0 +1,83 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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
*
* Internet Control Message Protocol (ICMP) packet handling routines. This protocol handles
* Echo requests from the host, to indicate a successful network connection between the host
* and the virtual server.
*/
#include "ICMP.h"
/** Processes an ICMP packet inside an Ethernet frame, and writes the appropriate response
* to the output Ethernet frame if the host is issuing a ICMP ECHO request.
*
* \param[in] FrameIN Pointer to the incoming Ethernet frame information structure
* \param[in] InDataStart Pointer to the start of the incoming packet's ICMP header
* \param[out] OutDataStart Pointer to the start of the outgoing packet's ICMP header
*
* \return The number of bytes written to the out Ethernet frame if any, NO_RESPONSE otherwise
*/
int16_t ICMP_ProcessICMPPacket(Ethernet_Frame_Info_t* const FrameIN,
void* InDataStart,
void* OutDataStart)
{
ICMP_Header_t* ICMPHeaderIN = (ICMP_Header_t*)InDataStart;
ICMP_Header_t* ICMPHeaderOUT = (ICMP_Header_t*)OutDataStart;
DecodeICMPHeader(InDataStart);
/* Determine if the ICMP packet is an echo request (ping) */
if (ICMPHeaderIN->Type == ICMP_TYPE_ECHOREQUEST)
{
/* Fill out the ICMP response packet */
ICMPHeaderOUT->Type = ICMP_TYPE_ECHOREPLY;
ICMPHeaderOUT->Code = 0;
ICMPHeaderOUT->Checksum = 0;
ICMPHeaderOUT->Id = ICMPHeaderIN->Id;
ICMPHeaderOUT->Sequence = ICMPHeaderIN->Sequence;
intptr_t DataSize = FrameIN->FrameLength - ((((intptr_t)InDataStart + sizeof(ICMP_Header_t)) - (intptr_t)FrameIN->FrameData));
/* Copy the remaining payload to the response - echo requests should echo back any sent data */
memmove(&((uint8_t*)OutDataStart)[sizeof(ICMP_Header_t)],
&((uint8_t*)InDataStart)[sizeof(ICMP_Header_t)],
DataSize);
ICMPHeaderOUT->Checksum = Ethernet_Checksum16(ICMPHeaderOUT, (DataSize + sizeof(ICMP_Header_t)));
/* Return the size of the response so far */
return (DataSize + sizeof(ICMP_Header_t));
}
return NO_RESPONSE;
}

View file

@ -0,0 +1,83 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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 ICMP.c.
*/
#ifndef _ICMP_H_
#define _ICMP_H_
/* Includes: */
#include <avr/io.h>
#include <string.h>
#include "EthernetProtocols.h"
#include "Ethernet.h"
#include "ProtocolDecoders.h"
/* Macros: */
/** ICMP message type constant, indicating an ICMP ECHO Reply message. */
#define ICMP_TYPE_ECHOREPLY 0
/** ICMP message type constant, indicating a packet destination is unreachable. */
#define ICMP_TYPE_DESTINATIONUNREACHABLE 3
/** ICMP message type constant, indicating an ICMP Source Quench message. */
#define ICMP_TYPE_SOURCEQUENCH 4
/** ICMP message type constant, indicating an ICMP Redirect message. */
#define ICMP_TYPE_REDIRECTMESSAGE 5
/** ICMP message type constant, indicating an ICMP ECHO Request message. */
#define ICMP_TYPE_ECHOREQUEST 8
/** ICMP message type constant, indicating an ICMP Time Exceeded message. */
#define ICMP_TYPE_TIMEEXCEEDED 11
/* Type Defines: */
/** Type define for an ICMP message header. */
typedef struct
{
uint8_t Type; /**< ICMP message type, an \c ICMP_TYPE_* constant */
uint8_t Code; /**< ICMP message code, indicating the message value */
uint16_t Checksum; /**< Ethernet checksum of the ICMP message */
uint16_t Id; /**< Id of the ICMP message */
uint16_t Sequence; /**< Sequence number of the ICMP message, to link together message responses */
} ICMP_Header_t;
/* Function Prototypes: */
int16_t ICMP_ProcessICMPPacket(Ethernet_Frame_Info_t* const FrameIN,
void* InDataStart,
void* OutDataStart);
#endif

View file

@ -0,0 +1,116 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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
*
* Internet Protocol (IP) packet handling routines. This protocol handles IP packets from the
* host which typically encapsulate other protocols such as ICMP, UDP and TCP.
*/
#include "IP.h"
/** Processes an IP packet inside an Ethernet frame, and writes the appropriate response
* to the output Ethernet frame if one is created by a sub-protocol handler.
*
* \param[in] FrameIN Pointer to the incoming Ethernet frame information structure
* \param[in] InDataStart Pointer to the start of the incoming packet's IP header
* \param[out] OutDataStart Pointer to the start of the outgoing packet's IP header
*
* \return The number of bytes written to the out Ethernet frame if any, NO_RESPONSE if no
* response was generated, NO_PROCESS if the packet processing was deferred until the
* next Ethernet packet handler iteration
*/
int16_t IP_ProcessIPPacket(Ethernet_Frame_Info_t* const FrameIN,
void* InDataStart,
void* OutDataStart)
{
DecodeIPHeader(InDataStart);
IP_Header_t* IPHeaderIN = (IP_Header_t*)InDataStart;
IP_Header_t* IPHeaderOUT = (IP_Header_t*)OutDataStart;
/* Header length is specified in number of longs in the packet header, convert to bytes */
uint16_t HeaderLengthBytes = (IPHeaderIN->HeaderLength * sizeof(uint32_t));
int16_t RetSize = NO_RESPONSE;
/* Check to ensure the IP packet is addressed to the virtual webserver's IP or the broadcast IP address */
if (!(IP_COMPARE(&IPHeaderIN->DestinationAddress, &ServerIPAddress)) &&
!(IP_COMPARE(&IPHeaderIN->DestinationAddress, &BroadcastIPAddress)))
{
return NO_RESPONSE;
}
/* Pass off the IP payload to the appropriate protocol processing routine */
switch (IPHeaderIN->Protocol)
{
case PROTOCOL_ICMP:
RetSize = ICMP_ProcessICMPPacket(FrameIN,
&((uint8_t*)InDataStart)[HeaderLengthBytes],
&((uint8_t*)OutDataStart)[sizeof(IP_Header_t)]);
break;
case PROTOCOL_TCP:
RetSize = TCP_ProcessTCPPacket(InDataStart,
&((uint8_t*)InDataStart)[HeaderLengthBytes],
&((uint8_t*)OutDataStart)[sizeof(IP_Header_t)]);
break;
case PROTOCOL_UDP:
RetSize = UDP_ProcessUDPPacket(InDataStart,
&((uint8_t*)InDataStart)[HeaderLengthBytes],
&((uint8_t*)OutDataStart)[sizeof(IP_Header_t)]);
break;
}
/* Check to see if the protocol processing routine has filled out a response */
if (RetSize > 0)
{
/* Fill out the response IP packet header */
IPHeaderOUT->TotalLength = SwapEndian_16(sizeof(IP_Header_t) + RetSize);
IPHeaderOUT->TypeOfService = 0;
IPHeaderOUT->HeaderLength = (sizeof(IP_Header_t) / sizeof(uint32_t));
IPHeaderOUT->Version = 4;
IPHeaderOUT->Flags = 0;
IPHeaderOUT->FragmentOffset = 0;
IPHeaderOUT->Identification = 0;
IPHeaderOUT->HeaderChecksum = 0;
IPHeaderOUT->Protocol = IPHeaderIN->Protocol;
IPHeaderOUT->TTL = DEFAULT_TTL;
IPHeaderOUT->SourceAddress = IPHeaderIN->DestinationAddress;
IPHeaderOUT->DestinationAddress = IPHeaderIN->SourceAddress;
IPHeaderOUT->HeaderChecksum = Ethernet_Checksum16(IPHeaderOUT, sizeof(IP_Header_t));
/* Return the size of the response so far */
return (sizeof(IP_Header_t) + RetSize);
}
return RetSize;
}

View file

@ -0,0 +1,93 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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 IP.c.
*/
#ifndef _IP_H_
#define _IP_H_
/* Includes: */
#include <avr/io.h>
#include <string.h>
#include "EthernetProtocols.h"
#include "Ethernet.h"
#include "ProtocolDecoders.h"
#include "Config/AppConfig.h"
/* Macros: */
/** Protocol IP address of the broadcast address. */
#define BROADCAST_IP_ADDRESS {0xFF, 0xFF, 0xFF, 0xFF}
/** Default Time To Live (TTL) value for sent packets, indicating the maximum allowable hops until their destination
* is reached.
*/
#define DEFAULT_TTL 128
/** Performs a comparison between two IP addresses, indicating if they are identical.
*
* \param[in] IP1 First IP address
* \param[in] IP2 Second IP address
*
* \return True if the addresses match, \c false otherwise
*/
#define IP_COMPARE(IP1, IP2) (memcmp(IP1, IP2, sizeof(IP_Address_t)) == 0)
/* Type Defines: */
/** Type define of an IP packet header. */
typedef struct
{
unsigned HeaderLength : 4; /**< Total length of the packet header, in 4-byte blocks */
unsigned Version : 4; /**< IP protocol version */
uint8_t TypeOfService; /**< Special service type identifier, indicating delay/throughput/reliability levels */
uint16_t TotalLength; /**< Total length of the IP packet, in bytes */
uint16_t Identification; /**< Identification value for identifying fragmented packets */
unsigned FragmentOffset : 13; /**< Offset of this IP fragment */
unsigned Flags : 3; /**< Fragment flags, to indicate if a packet is fragmented */
uint8_t TTL; /**< Maximum allowable number of hops to reach the packet destination */
uint8_t Protocol; /**< Encapsulated protocol type */
uint16_t HeaderChecksum; /**< Ethernet checksum of the IP header */
IP_Address_t SourceAddress; /**< Source protocol IP address of the packet */
IP_Address_t DestinationAddress; /**< Destination protocol IP address of the packet */
} IP_Header_t;
/* Function Prototypes: */
int16_t IP_ProcessIPPacket(Ethernet_Frame_Info_t* const FrameIN,
void* InDataStart,
void* OutDataStart);
#endif

View file

@ -0,0 +1,277 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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.
*/
/* Protocol decoders for Ethernet, TCP, IP, ICMP and ARP. Each of these routines
accepts a header to the appropriate protocol and prints out pertinent information
on the packet through the serial port.
To disable printing of a specific protocol, define the token NO_DECODE_{Protocol}
in the project makefile, and pass it to the compiler using the -D switch.
*/
/** \file
*
* Protocol decoding routines, for the plain-text decoding of Ethernet frames for debugging purposes.
* Enabled protocol decoders will print incoming Ethernet frame contents through the USART in a human
* readable format.
*
* Note that the USART is a slow transmission medium, and will slow down packet processing considerably.
* Packet decoding routines can be disabled by defining NO_DECODE_{Protocol Name} in the project makefile
* and passing it to the compiler via the -D switch.
*/
#include "ProtocolDecoders.h"
/** Decodes an Ethernet frame header and prints its contents to through the USART in a human readable format.
*
* \param[in] InDataStart Pointer to the start of an Ethernet frame of data
*/
void DecodeEthernetFrameHeader(void* InDataStart)
{
#if !defined(NO_DECODE_ETHERNET)
Ethernet_Frame_Header_t* FrameHeader = (Ethernet_Frame_Header_t*)InDataStart;
printf_P(PSTR("\r\n"));
printf_P(PSTR(" ETHERNET\r\n"));
if (!(MAC_COMPARE(&FrameHeader->Destination, &ServerMACAddress)) &&
!(MAC_COMPARE(&FrameHeader->Destination, &BroadcastMACAddress)))
{
printf_P(PSTR(" + NOT ADDRESSED TO DEVICE\r\n"));
return;
}
printf_P(PSTR(" + MAC Source : %02X:%02X:%02X:%02X:%02X:%02X\r\n"), FrameHeader->Source.Octets[0],
FrameHeader->Source.Octets[1],
FrameHeader->Source.Octets[2],
FrameHeader->Source.Octets[3],
FrameHeader->Source.Octets[4],
FrameHeader->Source.Octets[5]);
printf_P(PSTR(" + MAC Dest: %02X:%02X:%02X:%02X:%02X:%02X\r\n"), FrameHeader->Destination.Octets[0],
FrameHeader->Destination.Octets[1],
FrameHeader->Destination.Octets[2],
FrameHeader->Destination.Octets[3],
FrameHeader->Destination.Octets[4],
FrameHeader->Destination.Octets[5]);
printf_P(PSTR(" + Protocol: 0x%04x\r\n"), SwapEndian_16(FrameHeader->EtherType));
#endif
}
/** Decodes an ARP header and prints its contents to through the USART in a human readable format.
*
* \param[in] InDataStart Pointer to the start of an ARP packet header
*/
void DecodeARPHeader(void* InDataStart)
{
#if !defined(NO_DECODE_ARP)
ARP_Header_t* ARPHeader = (ARP_Header_t*)InDataStart;
printf_P(PSTR(" \\\r\n ARP\r\n"));
if (!(IP_COMPARE(&ARPHeader->TPA, &ServerIPAddress)) &&
!(MAC_COMPARE(&ARPHeader->THA, &ServerMACAddress)))
{
printf_P(PSTR(" + NOT ADDRESSED TO DEVICE\r\n"));
return;
}
printf_P(PSTR(" + Protocol: %x\r\n"), SwapEndian_16(ARPHeader->ProtocolType));
printf_P(PSTR(" + Operation: %u\r\n"), SwapEndian_16(ARPHeader->Operation));
if (SwapEndian_16(ARPHeader->ProtocolType) == ETHERTYPE_IPV4)
{
printf_P(PSTR(" + SHA MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n"), ARPHeader->SHA.Octets[0],
ARPHeader->SHA.Octets[1],
ARPHeader->SHA.Octets[2],
ARPHeader->SHA.Octets[3],
ARPHeader->SHA.Octets[4],
ARPHeader->SHA.Octets[5]);
printf_P(PSTR(" + SPA IP: %u.%u.%u.%u\r\n"), ARPHeader->SPA.Octets[0],
ARPHeader->SPA.Octets[1],
ARPHeader->SPA.Octets[2],
ARPHeader->SPA.Octets[3]);
printf_P(PSTR(" + THA MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n"), ARPHeader->THA.Octets[0],
ARPHeader->THA.Octets[1],
ARPHeader->THA.Octets[2],
ARPHeader->THA.Octets[3],
ARPHeader->THA.Octets[4],
ARPHeader->THA.Octets[5]);
printf_P(PSTR(" + TPA IP: %u.%u.%u.%u\r\n"), ARPHeader->TPA.Octets[0],
ARPHeader->TPA.Octets[1],
ARPHeader->TPA.Octets[2],
ARPHeader->TPA.Octets[3]);
}
#endif
}
/** Decodes an IP header and prints its contents to through the USART in a human readable format.
*
* \param[in] InDataStart Pointer to the start of an IP packet header
*/
void DecodeIPHeader(void* InDataStart)
{
#if !defined(NO_DECODE_IP)
IP_Header_t* IPHeader = (IP_Header_t*)InDataStart;
uint16_t HeaderLengthBytes = (IPHeader->HeaderLength * sizeof(uint32_t));
printf_P(PSTR(" \\\r\n IP\r\n"));
if (!(IP_COMPARE(&IPHeader->DestinationAddress, &ServerIPAddress)))
{
printf_P(PSTR(" + NOT ADDRESSED TO DEVICE\r\n"));
return;
}
printf_P(PSTR(" + Header Length: %u Bytes\r\n"), HeaderLengthBytes);
printf_P(PSTR(" + Packet Version: %u\r\n"), IPHeader->Version);
printf_P(PSTR(" + Total Length: %u\r\n"), SwapEndian_16(IPHeader->TotalLength));
printf_P(PSTR(" + Protocol: %u\r\n"), IPHeader->Protocol);
printf_P(PSTR(" + TTL: %u\r\n"), IPHeader->TTL);
printf_P(PSTR(" + IP Src: %u.%u.%u.%u\r\n"), IPHeader->SourceAddress.Octets[0],
IPHeader->SourceAddress.Octets[1],
IPHeader->SourceAddress.Octets[2],
IPHeader->SourceAddress.Octets[3]);
printf_P(PSTR(" + IP Dst: %u.%u.%u.%u\r\n"), IPHeader->DestinationAddress.Octets[0],
IPHeader->DestinationAddress.Octets[1],
IPHeader->DestinationAddress.Octets[2],
IPHeader->DestinationAddress.Octets[3]);
#endif
}
/** Decodes an ICMP header and prints its contents to through the USART in a human readable format.
*
* \param[in] InDataStart Pointer to the start of an ICMP packet header
*/
void DecodeICMPHeader(void* InDataStart)
{
#if !defined(NO_DECODE_ICMP)
ICMP_Header_t* ICMPHeader = (ICMP_Header_t*)InDataStart;
printf_P(PSTR(" \\\r\n ICMP\r\n"));
printf_P(PSTR(" + Type: %u\r\n"), ICMPHeader->Type);
printf_P(PSTR(" + Code: %u\r\n"), ICMPHeader->Code);
#endif
}
/** Decodes a TCP header and prints its contents to through the USART in a human readable format.
*
* \param[in] InDataStart Pointer to the start of a TCP packet header
*/
void DecodeTCPHeader(void* InDataStart)
{
#if !defined(NO_DECODE_TCP)
TCP_Header_t* TCPHeader = (TCP_Header_t*)InDataStart;
uint16_t HeaderLengthBytes = (TCPHeader->DataOffset * sizeof(uint32_t));
printf_P(PSTR(" \\\r\n TCP\r\n"));
printf_P(PSTR(" + Header Length: %u Bytes\r\n"), HeaderLengthBytes);
printf_P(PSTR(" + Source Port: %u\r\n"), SwapEndian_16(TCPHeader->SourcePort));
printf_P(PSTR(" + Destination Port: %u\r\n"), SwapEndian_16(TCPHeader->DestinationPort));
printf_P(PSTR(" + Sequence Number: %lu\r\n"), SwapEndian_32(TCPHeader->SequenceNumber));
printf_P(PSTR(" + Acknowledgment Number: %lu\r\n"), SwapEndian_32(TCPHeader->AcknowledgmentNumber));
printf_P(PSTR(" + Flags: 0x%02X\r\n"), TCPHeader->Flags);
if (TCP_GetPortState(TCPHeader->DestinationPort) == TCP_Port_Closed)
printf_P(PSTR(" + NOT LISTENING ON DESTINATION PORT\r\n"));
#endif
}
/** Decodes an UDP header and prints its contents to through the USART in a human readable format.
*
* \param[in] InDataStart Pointer to the start of a UDP packet header
*/
void DecodeUDPHeader(void* InDataStart)
{
#if !defined(NO_DECODE_UDP)
UDP_Header_t* UDPHeader = (UDP_Header_t*)InDataStart;
printf_P(PSTR(" \\\r\n UDP\r\n"));
printf_P(PSTR(" + Source Port: %u\r\n"), SwapEndian_16(UDPHeader->SourcePort));
printf_P(PSTR(" + Destination Port: %u\r\n"), SwapEndian_16(UDPHeader->DestinationPort));
printf_P(PSTR(" + Data Length: %d\r\n"), SwapEndian_16(UDPHeader->Length));
#endif
}
/** Decodes an DHCP header and prints its contents to through the USART in a human readable format.
*
* \param[in] InDataStart Pointer to the start of a DHCP packet header
*/
void DecodeDHCPHeader(void* InDataStart)
{
#if !defined(NO_DECODE_DHCP)
uint8_t* DHCPOptions = ((uint8_t*)InDataStart + sizeof(DHCP_Header_t));
printf_P(PSTR(" \\\r\n DHCP\r\n"));
while (DHCPOptions[0] != DHCP_OPTION_END)
{
if (DHCPOptions[0] == DHCP_OPTION_MESSAGETYPE)
{
switch (DHCPOptions[2])
{
case DHCP_MESSAGETYPE_DISCOVER:
printf_P(PSTR(" + DISCOVER\r\n"));
break;
case DHCP_MESSAGETYPE_REQUEST:
printf_P(PSTR(" + REQUEST\r\n"));
break;
case DHCP_MESSAGETYPE_RELEASE:
printf_P(PSTR(" + RELEASE\r\n"));
break;
case DHCP_MESSAGETYPE_DECLINE:
printf_P(PSTR(" + DECLINE\r\n"));
break;
}
}
DHCPOptions += ((DHCPOptions[0] == DHCP_OPTION_PAD) ? 1 : (DHCPOptions[1] + 2));
}
#endif
}

View file

@ -0,0 +1,60 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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 ProtocolDecoders.c.
*/
#ifndef _PROTOCOL_DECODERS_H_
#define _PROTOCOL_DECODERS_H_
/* Includes: */
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <LUFA/Drivers/Peripheral/Serial.h>
#include "EthernetProtocols.h"
#include "Ethernet.h"
#include "Config/AppConfig.h"
/* Function Prototypes: */
void DecodeEthernetFrameHeader(void* InDataStart);
void DecodeARPHeader(void* InDataStart);
void DecodeIPHeader(void* InDataStart);
void DecodeICMPHeader(void* InDataStart);
void DecodeTCPHeader(void* InDataStart);
void DecodeUDPHeader(void* InDataStart);
void DecodeDHCPHeader(void* InDataStart);
#endif

View file

@ -0,0 +1,632 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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
*
* Transmission Control Protocol (TCP) packet handling routines. This protocol handles the reliable in-order transmission
* and reception of packets to and from devices on a network, to "ports" on the device. It is used in situations where data
* delivery must be reliable and correct, e.g. HTTP, TELNET and most other non-streaming protocols.
*/
#define INCLUDE_FROM_TCP_C
#include "TCP.h"
/** Port state table array. This contains the current status of TCP ports in the device. To save on space, only open ports are
* stored - closed ports may be overwritten at any time, and the system will assume any ports not present in the array are closed. This
* allows for MAX_OPEN_TCP_PORTS to be less than the number of ports used by the application if desired.
*/
TCP_PortState_t PortStateTable[MAX_OPEN_TCP_PORTS];
/** Connection state table array. This contains the current status of TCP connections in the device. To save on space, only active
* (non-closed) connections are stored - closed connections may be overwritten at any time, and the system will assume any connections
* not present in the array are closed.
*/
TCP_ConnectionState_t ConnectionStateTable[MAX_TCP_CONNECTIONS];
/** Task to handle the calling of each registered application's callback function, to process and generate TCP packets at the application
* level. If an application produces a response, this task constructs the appropriate Ethernet frame and places it into the Ethernet OUT
* buffer for later transmission.
*/
void TCP_TCPTask(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo,
Ethernet_Frame_Info_t* const FrameOUT)
{
/* Run each application in sequence, to process incoming and generate outgoing packets */
for (uint8_t CSTableEntry = 0; CSTableEntry < MAX_TCP_CONNECTIONS; CSTableEntry++)
{
/* Find the corresponding port entry in the port table */
for (uint8_t PTableEntry = 0; PTableEntry < MAX_OPEN_TCP_PORTS; PTableEntry++)
{
/* Run the application handler for the port */
if ((PortStateTable[PTableEntry].Port == ConnectionStateTable[CSTableEntry].Port) &&
(PortStateTable[PTableEntry].State == TCP_Port_Open))
{
PortStateTable[PTableEntry].ApplicationHandler(&ConnectionStateTable[CSTableEntry],
&ConnectionStateTable[CSTableEntry].Info.Buffer);
}
}
}
/* Bail out early if there is already a frame waiting to be sent in the Ethernet OUT buffer */
if (FrameOUT->FrameLength)
return;
/* Send response packets from each application as the TCP packet buffers are filled by the applications */
for (uint8_t CSTableEntry = 0; CSTableEntry < MAX_TCP_CONNECTIONS; CSTableEntry++)
{
/* For each completely received packet, pass it along to the listening application */
if ((ConnectionStateTable[CSTableEntry].Info.Buffer.Direction == TCP_PACKETDIR_OUT) &&
(ConnectionStateTable[CSTableEntry].Info.Buffer.Ready))
{
Ethernet_Frame_Header_t* FrameOUTHeader = (Ethernet_Frame_Header_t*)&FrameOUT->FrameData;
IP_Header_t* IPHeaderOUT = (IP_Header_t*)&FrameOUT->FrameData[sizeof(Ethernet_Frame_Header_t)];
TCP_Header_t* TCPHeaderOUT = (TCP_Header_t*)&FrameOUT->FrameData[sizeof(Ethernet_Frame_Header_t) +
sizeof(IP_Header_t)];
void* TCPDataOUT = &FrameOUT->FrameData[sizeof(Ethernet_Frame_Header_t) +
sizeof(IP_Header_t) +
sizeof(TCP_Header_t)];
uint16_t PacketSize = ConnectionStateTable[CSTableEntry].Info.Buffer.Length;
/* Fill out the TCP data */
TCPHeaderOUT->SourcePort = ConnectionStateTable[CSTableEntry].Port;
TCPHeaderOUT->DestinationPort = ConnectionStateTable[CSTableEntry].RemotePort;
TCPHeaderOUT->SequenceNumber = SwapEndian_32(ConnectionStateTable[CSTableEntry].Info.SequenceNumberOut);
TCPHeaderOUT->AcknowledgmentNumber = SwapEndian_32(ConnectionStateTable[CSTableEntry].Info.SequenceNumberIn);
TCPHeaderOUT->DataOffset = (sizeof(TCP_Header_t) / sizeof(uint32_t));
TCPHeaderOUT->WindowSize = SwapEndian_16(TCP_WINDOW_SIZE);
TCPHeaderOUT->Flags = TCP_FLAG_ACK;
TCPHeaderOUT->UrgentPointer = 0;
TCPHeaderOUT->Checksum = 0;
TCPHeaderOUT->Reserved = 0;
memcpy(TCPDataOUT, ConnectionStateTable[CSTableEntry].Info.Buffer.Data, PacketSize);
ConnectionStateTable[CSTableEntry].Info.SequenceNumberOut += PacketSize;
TCPHeaderOUT->Checksum = TCP_Checksum16(TCPHeaderOUT, &ServerIPAddress,
&ConnectionStateTable[CSTableEntry].RemoteAddress,
(sizeof(TCP_Header_t) + PacketSize));
PacketSize += sizeof(TCP_Header_t);
/* Fill out the response IP header */
IPHeaderOUT->TotalLength = SwapEndian_16(sizeof(IP_Header_t) + PacketSize);
IPHeaderOUT->TypeOfService = 0;
IPHeaderOUT->HeaderLength = (sizeof(IP_Header_t) / sizeof(uint32_t));
IPHeaderOUT->Version = 4;
IPHeaderOUT->Flags = 0;
IPHeaderOUT->FragmentOffset = 0;
IPHeaderOUT->Identification = 0;
IPHeaderOUT->HeaderChecksum = 0;
IPHeaderOUT->Protocol = PROTOCOL_TCP;
IPHeaderOUT->TTL = DEFAULT_TTL;
IPHeaderOUT->SourceAddress = ServerIPAddress;
IPHeaderOUT->DestinationAddress = ConnectionStateTable[CSTableEntry].RemoteAddress;
IPHeaderOUT->HeaderChecksum = Ethernet_Checksum16(IPHeaderOUT, sizeof(IP_Header_t));
PacketSize += sizeof(IP_Header_t);
/* Fill out the response Ethernet frame header */
FrameOUTHeader->Source = ServerMACAddress;
FrameOUTHeader->Destination = (MAC_Address_t){{0x02, 0x00, 0x02, 0x00, 0x02, 0x00}};
FrameOUTHeader->EtherType = SwapEndian_16(ETHERTYPE_IPV4);
PacketSize += sizeof(Ethernet_Frame_Header_t);
/* Set the response length in the buffer and indicate that a response is ready to be sent */
FrameOUT->FrameLength = PacketSize;
ConnectionStateTable[CSTableEntry].Info.Buffer.Ready = false;
break;
}
}
}
/** Initializes the TCP protocol handler, clearing the port and connection state tables. This must be called before TCP packets are
* processed.
*/
void TCP_Init(void)
{
/* Initialize the port state table with all CLOSED entries */
for (uint8_t PTableEntry = 0; PTableEntry < MAX_OPEN_TCP_PORTS; PTableEntry++)
PortStateTable[PTableEntry].State = TCP_Port_Closed;
/* Initialize the connection table with all CLOSED entries */
for (uint8_t CSTableEntry = 0; CSTableEntry < MAX_TCP_CONNECTIONS; CSTableEntry++)
ConnectionStateTable[CSTableEntry].State = TCP_Connection_Closed;
}
/** Sets the state and callback handler of the given port, specified in big endian to the given state.
*
* \param[in] Port Port whose state and callback function to set, specified in big endian
* \param[in] State New state of the port, a value from the \ref TCP_PortStates_t enum
* \param[in] Handler Application callback handler for the port
*
* \return Boolean \c true if the port state was set, \c false otherwise (no more space in the port state table)
*/
bool TCP_SetPortState(const uint16_t Port,
const uint8_t State,
void (*Handler)(TCP_ConnectionState_t*, TCP_ConnectionBuffer_t*))
{
/* Note, Port number should be specified in BIG endian to simplify network code */
/* Check to see if the port entry is already in the port state table */
for (uint8_t PTableEntry = 0; PTableEntry < MAX_OPEN_TCP_PORTS; PTableEntry++)
{
/* Find existing entry for the port in the table, update it if found */
if (PortStateTable[PTableEntry].Port == Port)
{
PortStateTable[PTableEntry].State = State;
PortStateTable[PTableEntry].ApplicationHandler = Handler;
return true;
}
}
/* Check if trying to open the port -- if so we need to find an unused (closed) entry and replace it */
if (State == TCP_Port_Open)
{
for (uint8_t PTableEntry = 0; PTableEntry < MAX_OPEN_TCP_PORTS; PTableEntry++)
{
/* Find a closed port entry in the table, change it to the given port and state */
if (PortStateTable[PTableEntry].State == TCP_Port_Closed)
{
PortStateTable[PTableEntry].Port = Port;
PortStateTable[PTableEntry].State = State;
PortStateTable[PTableEntry].ApplicationHandler = Handler;
return true;
}
}
/* Port not in table and no room to add it, return failure */
return false;
}
else
{
/* Port not in table but trying to close it, so operation successful */
return true;
}
}
/** Retrieves the current state of a given TCP port, specified in big endian.
*
* \param[in] Port TCP port whose state is to be retrieved, given in big-endian
*
* \return A value from the \ref TCP_PortStates_t enum
*/
uint8_t TCP_GetPortState(const uint16_t Port)
{
/* Note, Port number should be specified in BIG endian to simplify network code */
for (uint8_t PTableEntry = 0; PTableEntry < MAX_OPEN_TCP_PORTS; PTableEntry++)
{
/* Find existing entry for the port in the table, return the port status if found */
if (PortStateTable[PTableEntry].Port == Port)
return PortStateTable[PTableEntry].State;
}
/* Port not in table, assume closed */
return TCP_Port_Closed;
}
/** Sets the connection state of the given port, remote address and remote port to the given TCP connection state. If the
* connection exists in the connection state table it is updated, otherwise it is created if possible.
*
* \param[in] Port TCP port of the connection on the device, specified in big endian
* \param[in] RemoteAddress Remote protocol IP address of the connected device
* \param[in] RemotePort TCP port of the remote device in the connection, specified in big endian
* \param[in] State TCP connection state, a value from the \ref TCP_ConnectionStates_t enum
*
* \return Boolean \c true if the connection was updated or created, \c false otherwise (no more space in the connection state table)
*/
bool TCP_SetConnectionState(const uint16_t Port,
const IP_Address_t* RemoteAddress,
const uint16_t RemotePort,
const uint8_t State)
{
/* Note, Port number should be specified in BIG endian to simplify network code */
for (uint8_t CSTableEntry = 0; CSTableEntry < MAX_TCP_CONNECTIONS; CSTableEntry++)
{
/* Find port entry in the table */
if ((ConnectionStateTable[CSTableEntry].Port == Port) &&
IP_COMPARE(&ConnectionStateTable[CSTableEntry].RemoteAddress, RemoteAddress) &&
ConnectionStateTable[CSTableEntry].RemotePort == RemotePort)
{
ConnectionStateTable[CSTableEntry].State = State;
return true;
}
}
for (uint8_t CSTableEntry = 0; CSTableEntry < MAX_TCP_CONNECTIONS; CSTableEntry++)
{
/* Find empty entry in the table */
if (ConnectionStateTable[CSTableEntry].State == TCP_Connection_Closed)
{
ConnectionStateTable[CSTableEntry].Port = Port;
ConnectionStateTable[CSTableEntry].RemoteAddress = *RemoteAddress;
ConnectionStateTable[CSTableEntry].RemotePort = RemotePort;
ConnectionStateTable[CSTableEntry].State = State;
return true;
}
}
return false;
}
/** Retrieves the current state of a given TCP connection to a host.
*
* \param[in] Port TCP port on the device in the connection, specified in big endian
* \param[in] RemoteAddress Remote protocol IP address of the connected host
* \param[in] RemotePort Remote TCP port of the connected host, specified in big endian
*
* \return A value from the \ref TCP_ConnectionStates_t enum
*/
uint8_t TCP_GetConnectionState(const uint16_t Port,
const IP_Address_t* RemoteAddress,
const uint16_t RemotePort)
{
/* Note, Port number should be specified in BIG endian to simplify network code */
for (uint8_t CSTableEntry = 0; CSTableEntry < MAX_TCP_CONNECTIONS; CSTableEntry++)
{
/* Find port entry in the table */
if ((ConnectionStateTable[CSTableEntry].Port == Port) &&
IP_COMPARE(&ConnectionStateTable[CSTableEntry].RemoteAddress, RemoteAddress) &&
ConnectionStateTable[CSTableEntry].RemotePort == RemotePort)
{
return ConnectionStateTable[CSTableEntry].State;
}
}
return TCP_Connection_Closed;
}
/** Retrieves the connection info structure of a given connection to a host.
*
* \param[in] Port TCP port on the device in the connection, specified in big endian
* \param[in] RemoteAddress Remote protocol IP address of the connected host
* \param[in] RemotePort Remote TCP port of the connected host, specified in big endian
*
* \return ConnectionInfo structure of the connection if found, NULL otherwise
*/
TCP_ConnectionInfo_t* TCP_GetConnectionInfo(const uint16_t Port,
const IP_Address_t* RemoteAddress,
const uint16_t RemotePort)
{
/* Note, Port number should be specified in BIG endian to simplify network code */
for (uint8_t CSTableEntry = 0; CSTableEntry < MAX_TCP_CONNECTIONS; CSTableEntry++)
{
/* Find port entry in the table */
if ((ConnectionStateTable[CSTableEntry].Port == Port) &&
IP_COMPARE(&ConnectionStateTable[CSTableEntry].RemoteAddress, RemoteAddress) &&
ConnectionStateTable[CSTableEntry].RemotePort == RemotePort)
{
return &ConnectionStateTable[CSTableEntry].Info;
}
}
return NULL;
}
/** Processes a TCP packet inside an Ethernet frame, and writes the appropriate response
* to the output Ethernet frame if one is created by a application handler.
*
* \param[in] IPHeaderInStart Pointer to the start of the incoming packet's IP header
* \param[in] TCPHeaderInStart Pointer to the start of the incoming packet's TCP header
* \param[out] TCPHeaderOutStart Pointer to the start of the outgoing packet's TCP header
*
* \return The number of bytes written to the out Ethernet frame if any, NO_RESPONSE if no
* response was generated, NO_PROCESS if the packet processing was deferred until the
* next Ethernet packet handler iteration
*/
int16_t TCP_ProcessTCPPacket(void* IPHeaderInStart,
void* TCPHeaderInStart,
void* TCPHeaderOutStart)
{
IP_Header_t* IPHeaderIN = (IP_Header_t*)IPHeaderInStart;
TCP_Header_t* TCPHeaderIN = (TCP_Header_t*)TCPHeaderInStart;
TCP_Header_t* TCPHeaderOUT = (TCP_Header_t*)TCPHeaderOutStart;
TCP_ConnectionInfo_t* ConnectionInfo;
DecodeTCPHeader(TCPHeaderInStart);
bool PacketResponse = false;
/* Check if the destination port is open and allows incoming connections */
if (TCP_GetPortState(TCPHeaderIN->DestinationPort) == TCP_Port_Open)
{
/* Detect SYN from host to start a connection */
if (TCPHeaderIN->Flags & TCP_FLAG_SYN)
TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, TCPHeaderIN->SourcePort, TCP_Connection_Listen);
/* Detect RST from host to abort existing connection */
if (TCPHeaderIN->Flags & TCP_FLAG_RST)
{
if (TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort, TCP_Connection_Closed))
{
TCPHeaderOUT->Flags = (TCP_FLAG_RST | TCP_FLAG_ACK);
PacketResponse = true;
}
}
else
{
/* Process the incoming TCP packet based on the current connection state for the sender and port */
switch (TCP_GetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, TCPHeaderIN->SourcePort))
{
case TCP_Connection_Listen:
if (TCPHeaderIN->Flags == TCP_FLAG_SYN)
{
/* SYN connection starts a connection with a peer */
if (TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort, TCP_Connection_SYNReceived))
{
TCPHeaderOUT->Flags = (TCP_FLAG_SYN | TCP_FLAG_ACK);
ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, TCPHeaderIN->SourcePort);
ConnectionInfo->SequenceNumberIn = (SwapEndian_32(TCPHeaderIN->SequenceNumber) + 1);
ConnectionInfo->SequenceNumberOut = 0;
ConnectionInfo->Buffer.InUse = false;
}
else
{
TCPHeaderOUT->Flags = TCP_FLAG_RST;
}
PacketResponse = true;
}
break;
case TCP_Connection_SYNReceived:
if (TCPHeaderIN->Flags == TCP_FLAG_ACK)
{
/* ACK during the connection process completes the connection to a peer */
TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort, TCP_Connection_Established);
ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort);
ConnectionInfo->SequenceNumberOut++;
}
break;
case TCP_Connection_Established:
if (TCPHeaderIN->Flags == (TCP_FLAG_FIN | TCP_FLAG_ACK))
{
/* FIN ACK when connected to a peer starts the finalization process */
TCPHeaderOUT->Flags = (TCP_FLAG_FIN | TCP_FLAG_ACK);
PacketResponse = true;
TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort, TCP_Connection_CloseWait);
ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort);
ConnectionInfo->SequenceNumberIn++;
ConnectionInfo->SequenceNumberOut++;
}
else if ((TCPHeaderIN->Flags == TCP_FLAG_ACK) || (TCPHeaderIN->Flags == (TCP_FLAG_ACK | TCP_FLAG_PSH)))
{
ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort);
/* Check if the buffer is currently in use either by a buffered data to send, or receive */
if ((ConnectionInfo->Buffer.InUse == false) && (ConnectionInfo->Buffer.Ready == false))
{
ConnectionInfo->Buffer.Direction = TCP_PACKETDIR_IN;
ConnectionInfo->Buffer.InUse = true;
ConnectionInfo->Buffer.Length = 0;
}
/* Check if the buffer has been claimed by us to read in data from the peer */
if ((ConnectionInfo->Buffer.Direction == TCP_PACKETDIR_IN) &&
(ConnectionInfo->Buffer.Length != TCP_WINDOW_SIZE))
{
uint16_t IPOffset = (IPHeaderIN->HeaderLength * sizeof(uint32_t));
uint16_t TCPOffset = (TCPHeaderIN->DataOffset * sizeof(uint32_t));
uint16_t DataLength = (SwapEndian_16(IPHeaderIN->TotalLength) - IPOffset - TCPOffset);
/* Copy the packet data into the buffer */
memcpy(&ConnectionInfo->Buffer.Data[ConnectionInfo->Buffer.Length],
&((uint8_t*)TCPHeaderInStart)[TCPOffset],
DataLength);
ConnectionInfo->SequenceNumberIn += DataLength;
ConnectionInfo->Buffer.Length += DataLength;
/* Check if the buffer is full or if the PSH flag is set, if so indicate buffer ready */
if ((!(TCP_WINDOW_SIZE - ConnectionInfo->Buffer.Length)) || (TCPHeaderIN->Flags & TCP_FLAG_PSH))
{
ConnectionInfo->Buffer.InUse = false;
ConnectionInfo->Buffer.Ready = true;
TCPHeaderOUT->Flags = TCP_FLAG_ACK;
PacketResponse = true;
}
}
else
{
/* Buffer is currently in use by the application, defer processing of the incoming packet */
return NO_PROCESS;
}
}
break;
case TCP_Connection_Closing:
ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort);
TCPHeaderOUT->Flags = (TCP_FLAG_ACK | TCP_FLAG_FIN);
PacketResponse = true;
ConnectionInfo->Buffer.InUse = false;
TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort, TCP_Connection_FINWait1);
break;
case TCP_Connection_FINWait1:
if (TCPHeaderIN->Flags == (TCP_FLAG_FIN | TCP_FLAG_ACK))
{
ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort);
TCPHeaderOUT->Flags = TCP_FLAG_ACK;
PacketResponse = true;
ConnectionInfo->SequenceNumberIn++;
ConnectionInfo->SequenceNumberOut++;
TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort, TCP_Connection_Closed);
}
else if (TCPHeaderIN->Flags == TCP_FLAG_ACK)
{
TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort, TCP_Connection_FINWait2);
}
break;
case TCP_Connection_FINWait2:
if (TCPHeaderIN->Flags == (TCP_FLAG_FIN | TCP_FLAG_ACK))
{
ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort);
TCPHeaderOUT->Flags = TCP_FLAG_ACK;
PacketResponse = true;
ConnectionInfo->SequenceNumberIn++;
ConnectionInfo->SequenceNumberOut++;
TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort, TCP_Connection_Closed);
}
break;
case TCP_Connection_CloseWait:
if (TCPHeaderIN->Flags == TCP_FLAG_ACK)
{
TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort, TCP_Connection_Closed);
}
break;
}
}
}
else
{
/* Port is not open, indicate via a RST/ACK response to the sender */
TCPHeaderOUT->Flags = (TCP_FLAG_RST | TCP_FLAG_ACK);
PacketResponse = true;
}
/* Check if we need to respond to the sent packet */
if (PacketResponse)
{
ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort);
TCPHeaderOUT->SourcePort = TCPHeaderIN->DestinationPort;
TCPHeaderOUT->DestinationPort = TCPHeaderIN->SourcePort;
TCPHeaderOUT->SequenceNumber = SwapEndian_32(ConnectionInfo->SequenceNumberOut);
TCPHeaderOUT->AcknowledgmentNumber = SwapEndian_32(ConnectionInfo->SequenceNumberIn);
TCPHeaderOUT->DataOffset = (sizeof(TCP_Header_t) / sizeof(uint32_t));
if (!(ConnectionInfo->Buffer.InUse))
TCPHeaderOUT->WindowSize = SwapEndian_16(TCP_WINDOW_SIZE);
else
TCPHeaderOUT->WindowSize = SwapEndian_16(TCP_WINDOW_SIZE - ConnectionInfo->Buffer.Length);
TCPHeaderOUT->UrgentPointer = 0;
TCPHeaderOUT->Checksum = 0;
TCPHeaderOUT->Reserved = 0;
TCPHeaderOUT->Checksum = TCP_Checksum16(TCPHeaderOUT, &IPHeaderIN->DestinationAddress,
&IPHeaderIN->SourceAddress, sizeof(TCP_Header_t));
return sizeof(TCP_Header_t);
}
return NO_RESPONSE;
}
/** Calculates the appropriate TCP checksum, consisting of the addition of the one's compliment of each word,
* complimented.
*
* \param[in] TCPHeaderOutStart Pointer to the start of the packet's outgoing TCP header
* \param[in] SourceAddress Source protocol IP address of the outgoing IP header
* \param[in] DestinationAddress Destination protocol IP address of the outgoing IP header
* \param[in] TCPOutSize Size in bytes of the TCP data header and payload
*
* \return A 16-bit TCP checksum value
*/
static uint16_t TCP_Checksum16(void* TCPHeaderOutStart,
const IP_Address_t* SourceAddress,
const IP_Address_t* DestinationAddress,
uint16_t TCPOutSize)
{
uint32_t Checksum = 0;
/* TCP/IP checksums are the addition of the one's compliment of each word including the IP pseudo-header,
complimented */
Checksum += ((uint16_t*)SourceAddress)[0];
Checksum += ((uint16_t*)SourceAddress)[1];
Checksum += ((uint16_t*)DestinationAddress)[0];
Checksum += ((uint16_t*)DestinationAddress)[1];
Checksum += SwapEndian_16(PROTOCOL_TCP);
Checksum += SwapEndian_16(TCPOutSize);
for (uint16_t CurrWord = 0; CurrWord < (TCPOutSize >> 1); CurrWord++)
Checksum += ((uint16_t*)TCPHeaderOutStart)[CurrWord];
if (TCPOutSize & 0x01)
Checksum += (((uint16_t*)TCPHeaderOutStart)[TCPOutSize >> 1] & 0x00FF);
while (Checksum & 0xFFFF0000)
Checksum = ((Checksum & 0xFFFF) + (Checksum >> 16));
return ~Checksum;
}

View file

@ -0,0 +1,260 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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 TCP.c.
*/
#ifndef _TCP_H_
#define _TCP_H_
/* Includes: */
#include <avr/io.h>
#include <stdbool.h>
#include "EthernetProtocols.h"
#include "Ethernet.h"
#include "ProtocolDecoders.h"
/* Macros: */
/** Maximum number of TCP ports which can be open at the one time. */
#define MAX_OPEN_TCP_PORTS 1
/** Maximum number of TCP connections which can be sustained at the one time. */
#define MAX_TCP_CONNECTIONS 3
/** TCP window size, giving the maximum number of bytes which can be buffered at the one time. */
#define TCP_WINDOW_SIZE 512
/** Port number for HTTP transmissions. */
#define TCP_PORT_HTTP SwapEndian_16(80)
/** Data direction indicator for a TCP application buffer, indicating data from host-to-device. */
#define TCP_PACKETDIR_IN false
/** Data direction indicator for a TCP application buffer, indicating data from device-to-host. */
#define TCP_PACKETDIR_OUT true
/** Congestion Window Reduced TCP flag mask. */
#define TCP_FLAG_CWR (1 << 7)
/** Explicit Congestion Notification TCP flag mask. */
#define TCP_FLAG_ECE (1 << 6)
/** Urgent TCP flag mask. */
#define TCP_FLAG_URG (1 << 5)
/** Data Acknowledge TCP flag mask. */
#define TCP_FLAG_ACK (1 << 4)
/** Data Push TCP flag mask. */
#define TCP_FLAG_PSH (1 << 3)
/** Reset TCP flag mask. */
#define TCP_FLAG_RST (1 << 2)
/** Synchronize TCP flag mask. */
#define TCP_FLAG_SYN (1 << 1)
/** Connection Finalize TCP flag mask. */
#define TCP_FLAG_FIN (1 << 0)
/** Application macro: Determines if the given application buffer contains a packet received from the host
*
* \param[in] Buffer Application buffer to check
*
* \return Boolean \c true if the buffer contains a packet from the host, \c false otherwise
*/
#define TCP_APP_HAS_RECEIVED_PACKET(Buffer) (Buffer->Ready && (Buffer->Direction == TCP_PACKETDIR_IN))
/** Application macro: Indicates if the application buffer is currently locked by the application for device-to-host transfers.
*
* \param[in] Buffer Application buffer to check
*
* \return Boolean \c true if the buffer has been captured by the application for device-to-host transmissions, \c false otherwise
*/
#define TCP_APP_HAVE_CAPTURED_BUFFER(Buffer) (!(Buffer->Ready) && Buffer->InUse && (Buffer->Direction == TCP_PACKETDIR_OUT))
/** Application macro: Indicates if the application can lock the buffer for multiple continued device-to-host transmissions.
*
* \param[in] Buffer Application buffer to check
*
* \return Boolean \c true if the buffer may be captured by the application for device-to-host transmissions, \c false otherwise
*/
#define TCP_APP_CAN_CAPTURE_BUFFER(Buffer) Buffer->InUse
/** Application macro: Captures the application buffer, locking it for device-to-host transmissions only. This should be
* performed when the application needs to transmit several packets worth of data in succession with no interruptions from the host.
*
* \pre The application must check that the buffer can be locked first using TCP_APP_CAN_CAPTURE_BUFFER().
*
* \param[in] Buffer Application buffer to lock
*/
#define TCP_APP_CAPTURE_BUFFER(Buffer) do { Buffer->Direction = TCP_PACKETDIR_OUT; Buffer->InUse = true; } while (0)
/** Application macro: Releases a captured application buffer, allowing for host-to-device packets to be received.
*
* \param[in] Buffer Application buffer to release
*/
#define TCP_APP_RELEASE_BUFFER(Buffer) do { Buffer->InUse = false; } while (0)
/** Application macro: Sends the contents of the given application buffer to the host.
*
* \param[in] Buffer Application buffer to send
* \param[in] Len Length of data contained in the buffer
*/
#define TCP_APP_SEND_BUFFER(Buffer, Len) do { Buffer->Direction = TCP_PACKETDIR_OUT; Buffer->Length = Len; Buffer->Ready = true; } while (0)
/** Application macro: Clears the application buffer, ready for a packet to be written to it.
*
* \param[in] Buffer Application buffer to clear
*/
#define TCP_APP_CLEAR_BUFFER(Buffer) do { Buffer->Ready = false; Buffer->Length = 0; } while (0)
/** Application macro: Closes an open connection to a host.
*
* \param[in] Connection Open TCP connection to close
*/
#define TCP_APP_CLOSECONNECTION(Connection) do { Connection->State = TCP_Connection_Closing; } while (0)
/* Enums: */
/** Enum for possible TCP port states. */
enum TCP_PortStates_t
{
TCP_Port_Closed = 0, /**< TCP port closed, no connections to a host may be made on this port. */
TCP_Port_Open = 1, /**< TCP port open, connections to a host may be made on this port. */
};
/** Enum for possible TCP connection states. */
enum TCP_ConnectionStates_t
{
TCP_Connection_Listen = 0, /**< Listening for a connection from a host */
TCP_Connection_SYNSent = 1, /**< Unused */
TCP_Connection_SYNReceived = 2, /**< SYN received, waiting for ACK */
TCP_Connection_Established = 3, /**< Connection established in both directions */
TCP_Connection_FINWait1 = 4, /**< Closing, waiting for ACK */
TCP_Connection_FINWait2 = 5, /**< Closing, waiting for FIN ACK */
TCP_Connection_CloseWait = 6, /**< Closing, waiting for ACK */
TCP_Connection_Closing = 7, /**< Unused */
TCP_Connection_LastACK = 8, /**< Unused */
TCP_Connection_TimeWait = 9, /**< Unused */
TCP_Connection_Closed = 10, /**< Connection closed in both directions */
};
/* Type Defines: */
/** Type define for a TCP connection buffer structure, including size, data and direction. */
typedef struct
{
uint16_t Length; /**< Length of data in the TCP application buffer */
uint8_t Data[TCP_WINDOW_SIZE]; /**< TCP application data buffer */
bool Direction; /**< Buffer transmission direction, either TCP_PACKETDIR_IN or TCP_PACKETDIR_OUT */
bool Ready; /**< If data from host, indicates buffer ready to be read, otherwise indicates
* buffer ready to be sent to the host
*/
bool InUse; /**< Indicates if the buffer is locked to to the current direction, and cannot be changed */
} TCP_ConnectionBuffer_t;
/** Type define for a TCP connection information structure. */
typedef struct
{
uint32_t SequenceNumberIn; /**< Current TCP sequence number for host-to-device */
uint32_t SequenceNumberOut; /**< Current TCP sequence number for device-to-host */
TCP_ConnectionBuffer_t Buffer; /**< Connection application data buffer */
} TCP_ConnectionInfo_t;
/** Type define for a complete TCP connection state. */
typedef struct
{
uint16_t Port; /**< Connection port number on the device */
uint16_t RemotePort; /**< Connection port number on the host */
IP_Address_t RemoteAddress; /**< Connection protocol IP address of the host */
TCP_ConnectionInfo_t Info; /**< Connection information, including application buffer */
uint8_t State; /**< Current connection state, a value from the \ref TCP_ConnectionStates_t enum */
} TCP_ConnectionState_t;
/** Type define for a TCP port state. */
typedef struct
{
uint16_t Port; /**< TCP port number on the device */
uint8_t State; /**< Current port state, a value from the \ref TCP_PortStates_t enum */
void (*ApplicationHandler) (TCP_ConnectionState_t* ConnectionState,
TCP_ConnectionBuffer_t* Buffer); /**< Port application handler */
} TCP_PortState_t;
/** Type define for a TCP packet header. */
typedef struct
{
uint16_t SourcePort; /**< Source port of the TCP packet */
uint16_t DestinationPort; /**< Destination port of the TCP packet */
uint32_t SequenceNumber; /**< Data sequence number of the packet */
uint32_t AcknowledgmentNumber; /**< Data acknowledgment number of the packet */
unsigned Reserved : 4; /**< Reserved, must be all 0 */
unsigned DataOffset : 4; /**< Offset of the data from the start of the header, in 4 byte chunks */
uint8_t Flags; /**< TCP packet flags */
uint16_t WindowSize; /**< Current data window size (bytes remaining in reception buffer) */
uint16_t Checksum; /**< TCP checksum */
uint16_t UrgentPointer; /**< Urgent data pointer */
} TCP_Header_t;
/* Function Prototypes: */
void TCP_TCPTask(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo,
Ethernet_Frame_Info_t* const FrameOUT);
void TCP_Init(void);
bool TCP_SetPortState(const uint16_t Port,
const uint8_t State,
void (*Handler)(TCP_ConnectionState_t*, TCP_ConnectionBuffer_t*));
uint8_t TCP_GetPortState(const uint16_t Port);
bool TCP_SetConnectionState(const uint16_t Port,
const IP_Address_t* RemoteAddress,
const uint16_t RemotePort,
const uint8_t State);
uint8_t TCP_GetConnectionState(const uint16_t Port,
const IP_Address_t* RemoteAddress,
const uint16_t RemotePort);
TCP_ConnectionInfo_t* TCP_GetConnectionInfo(const uint16_t Port,
const IP_Address_t* RemoteAddress,
const uint16_t RemotePort);
int16_t TCP_ProcessTCPPacket(void* IPHeaderInStart,
void* TCPHeaderInStart,
void* TCPHeaderOutStart);
#if defined(INCLUDE_FROM_TCP_C)
static uint16_t TCP_Checksum16(void* TCPHeaderOutStart,
const IP_Address_t* SourceAddress,
const IP_Address_t* DestinationAddress,
uint16_t TCPOutSize);
#endif
#endif

View file

@ -0,0 +1,84 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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
*
* User Datagram Protocol (UDP) packet handling routines. This protocol handles high throughput, low
* reliability packets which are typically used to encapsulate streaming data.
*/
#define INCLUDE_FROM_UDP_C
#include "UDP.h"
/** Processes a UDP packet inside an Ethernet frame, and writes the appropriate response
* to the output Ethernet frame if a sub-protocol handler has created a response packet.
*
* \param[in] IPHeaderInStart Pointer to the start of the incoming packet's IP header
* \param[in] UDPHeaderInStart Pointer to the start of the incoming packet's UDP header
* \param[out] UDPHeaderOutStart Pointer to the start of the outgoing packet's UDP header
*
* \return The number of bytes written to the out Ethernet frame if any, NO_RESPONSE otherwise
*/
int16_t UDP_ProcessUDPPacket(void* IPHeaderInStart,
void* UDPHeaderInStart,
void* UDPHeaderOutStart)
{
UDP_Header_t* UDPHeaderIN = (UDP_Header_t*)UDPHeaderInStart;
UDP_Header_t* UDPHeaderOUT = (UDP_Header_t*)UDPHeaderOutStart;
int16_t RetSize = NO_RESPONSE;
DecodeUDPHeader(UDPHeaderInStart);
switch (SwapEndian_16(UDPHeaderIN->DestinationPort))
{
case UDP_PORT_DHCP_REQUEST:
RetSize = DHCP_ProcessDHCPPacket(IPHeaderInStart,
&((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],
&((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);
break;
}
/* Check to see if the protocol processing routine has filled out a response */
if (RetSize > 0)
{
/* Fill out the response UDP packet header */
UDPHeaderOUT->SourcePort = UDPHeaderIN->DestinationPort;
UDPHeaderOUT->DestinationPort = UDPHeaderIN->SourcePort;
UDPHeaderOUT->Checksum = 0;
UDPHeaderOUT->Length = SwapEndian_16(sizeof(UDP_Header_t) + RetSize);
/* Return the size of the response so far */
return (sizeof(UDP_Header_t) + RetSize);
}
return NO_RESPONSE;
}

View file

@ -0,0 +1,70 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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 UDP.c.
*/
#ifndef _UDP_H_
#define _UDP_H_
/* Includes: */
#include <avr/io.h>
#include "EthernetProtocols.h"
#include "Ethernet.h"
#include "ProtocolDecoders.h"
#include "DHCP.h"
/* Macros: */
/** Source UDP port for a DHCP request. */
#define UDP_PORT_DHCP_REQUEST 67
/** Destination UDP port for a DHCP reply. */
#define UDP_PORT_DHCP_REPLY 68
/* Type Defines: */
/** Type define for a UDP packet header. */
typedef struct
{
uint16_t SourcePort; /**< Packet source port */
uint16_t DestinationPort; /**< Packet destination port */
uint16_t Length; /**< Total packet length, in bytes */
uint16_t Checksum; /**< Optional UDP packet checksum */
} UDP_Header_t;
/* Function Prototypes: */
int16_t UDP_ProcessUDPPacket(void* IPHeaderInStart,
void* UDPHeaderInStart,
void* UDPHeaderOutStart);
#endif

View file

@ -0,0 +1,203 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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
*
* Simple webserver application for demonstrating the RNDIS demo and TCP/IP stack. This
* application will serve up a static HTTP web page when requested by the host.
*/
#include "Webserver.h"
/** HTTP server response header, for transmission before the page contents. This indicates to the host that a page exists at the
* given location, and gives extra connection information.
*/
const char HTTP200Header[] PROGMEM = "HTTP/1.1 200 OK\r\n"
"Server: LUFA RNDIS\r\n"
"Content-type: text/html\r\n"
"Connection: close\r\n\r\n";
/** HTTP server response header, for transmission before a resource not found error. This indicates to the host that the given
* given URL is invalid, and gives extra error information.
*/
const char HTTP404Header[] PROGMEM = "HTTP/1.1 404 Not Found\r\n"
"Server: LUFA RNDIS\r\n"
"Connection: close\r\n\r\n";
/** HTTP page to serve to the host when a HTTP request is made. This page is too long for a single response, thus it is automatically
* broken up into smaller blocks and sent as a series of packets each time the webserver application callback is run.
*/
const char HTTPPage[] PROGMEM =
"<html>"
" <head>"
" <title>"
" LUFA Webserver Demo"
" </title>"
" </head>"
" <body>"
" <h1>Hello from your USB AVR!</h1>"
" <p>"
" Hello! Welcome to the LUFA RNDIS Demo Webserver test page, running on your USB AVR via the LUFA library. This demonstrates the HTTP webserver, TCP/IP stack and RNDIS demo all running atop the LUFA USB stack."
" <br /><br />"
" <small>Project Information: <a href=\"http://www.lufa-lib.org\">http://www.lufa-lib.org</a>.</small>"
" <hr />"
" <i>LUFA Version: </i>" LUFA_VERSION_STRING
" </p>"
" </body>"
"</html>";
/** Initializes the Webserver application, opening the appropriate HTTP port in the TCP handler and registering the application
* callback routine for packets sent to the HTTP protocol port.
*/
void Webserver_Init(void)
{
/* Open the HTTP port in the TCP protocol so that HTTP connections to the device can be established */
TCP_SetPortState(TCP_PORT_HTTP, TCP_Port_Open, Webserver_ApplicationCallback);
}
/** Indicates if a given request equals the given HTTP command.
*
* \param[in] RequestHeader HTTP request made by the host
* \param[in] Command HTTP command to compare the request to
*
* \return Boolean \c true if the command matches the request, \c false otherwise
*/
static bool IsHTTPCommand(uint8_t* RequestHeader,
char* Command)
{
/* Returns true if the non null terminated string in RequestHeader matches the null terminated string Command */
return (strncmp((char*)RequestHeader, Command, strlen(Command)) == 0);
}
/** Application callback routine, executed each time the TCP processing task runs. This callback determines what request
* has been made (if any), and serves up appropriate responses.
*
* \param[in] ConnectionState Pointer to a TCP Connection State structure giving connection information
* \param[in,out] Buffer Pointer to the application's send/receive packet buffer
*/
void Webserver_ApplicationCallback(TCP_ConnectionState_t* const ConnectionState,
TCP_ConnectionBuffer_t* const Buffer)
{
char* BufferDataStr = (char*)Buffer->Data;
static uint8_t PageBlock = 0;
/* Check to see if a packet has been received on the HTTP port from a remote host */
if (TCP_APP_HAS_RECEIVED_PACKET(Buffer))
{
if (IsHTTPCommand(Buffer->Data, "GET"))
{
if (IsHTTPCommand(Buffer->Data, "GET / "))
{
PageBlock = 0;
/* Copy the HTTP 200 response header into the packet buffer */
strcpy_P(BufferDataStr, HTTP200Header);
/* Send the buffer contents to the host */
TCP_APP_SEND_BUFFER(Buffer, strlen(BufferDataStr));
/* Lock the buffer to Device->Host transmissions only while we send the page contents */
TCP_APP_CAPTURE_BUFFER(Buffer);
}
else
{
/* Copy the HTTP 404 response header into the packet buffer */
strcpy_P(BufferDataStr, HTTP404Header);
/* Send the buffer contents to the host */
TCP_APP_SEND_BUFFER(Buffer, strlen(BufferDataStr));
/* All data sent, close the connection */
TCP_APP_CLOSECONNECTION(ConnectionState);
}
}
else if (IsHTTPCommand(Buffer->Data, "HEAD"))
{
if (IsHTTPCommand(Buffer->Data, "HEAD / "))
{
/* Copy the HTTP response header into the packet buffer */
strcpy_P(BufferDataStr, HTTP200Header);
/* Send the buffer contents to the host */
TCP_APP_SEND_BUFFER(Buffer, strlen(BufferDataStr));
}
else
{
/* Copy the HTTP response header into the packet buffer */
strcpy_P(BufferDataStr, HTTP404Header);
/* Send the buffer contents to the host */
TCP_APP_SEND_BUFFER(Buffer, strlen(BufferDataStr));
}
/* All data sent, close the connection */
TCP_APP_CLOSECONNECTION(ConnectionState);
}
else if (IsHTTPCommand(Buffer->Data, "TRACE"))
{
/* Echo the host's query back to the host */
TCP_APP_SEND_BUFFER(Buffer, Buffer->Length);
/* All data sent, close the connection */
TCP_APP_CLOSECONNECTION(ConnectionState);
}
else
{
/* Unknown request, just clear the buffer (drop the packet) */
TCP_APP_CLEAR_BUFFER(Buffer);
}
}
else if (TCP_APP_HAVE_CAPTURED_BUFFER(Buffer))
{
uint16_t RemLength = strlen_P(&HTTPPage[PageBlock * HTTP_REPLY_BLOCK_SIZE]);
uint16_t Length;
/* Determine the length of the loaded block */
Length = ((RemLength > HTTP_REPLY_BLOCK_SIZE) ? HTTP_REPLY_BLOCK_SIZE : RemLength);
/* Copy the next buffer sized block of the page to the packet buffer */
strncpy_P(BufferDataStr, &HTTPPage[PageBlock * HTTP_REPLY_BLOCK_SIZE], Length);
/* Send the buffer contents to the host */
TCP_APP_SEND_BUFFER(Buffer, Length);
/* Check to see if the entire page has been sent */
if (PageBlock++ == (sizeof(HTTPPage) / HTTP_REPLY_BLOCK_SIZE))
{
/* Unlock the buffer so that the host can fill it with future packets */
TCP_APP_RELEASE_BUFFER(Buffer);
/* Close the connection to the host */
TCP_APP_CLOSECONNECTION(ConnectionState);
}
}
}

View file

@ -0,0 +1,57 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 disclaims 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 Webserver.c.
*/
#ifndef _WEBSERVER_H_
#define _WEBSERVER_H_
/* Includes: */
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <LUFA/Version.h>
#include "TCP.h"
/* Macros: */
/** Maximum size of a HTTP response per transmission */
#define HTTP_REPLY_BLOCK_SIZE 128
/* Function Prototypes: */
void Webserver_Init(void);
void Webserver_ApplicationCallback(TCP_ConnectionState_t* const ConnectionState,
TCP_ConnectionBuffer_t* const Buffer);
#endif