Seperated out OTG, Device and Host mode demos into seperate folders for clarity. Adjusted makefiles so that the path to the LUFA library can be set in one place.

This commit is contained in:
Dean Camera 2009-03-20 06:34:41 +00:00
parent ecf7538430
commit ed031c1df2
209 changed files with 522 additions and 372 deletions

View file

@ -0,0 +1,85 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* 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 InDataStart Pointer to the start of the incomming packet's ARP header
* \param 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, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for ARP.c.
*/
#ifndef _ARP_H_
#define _ARP_H_
/* Includes: */
#include <avr/io.h>
#include <string.h>
#include <LUFA/Scheduler/Scheduler.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,118 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* 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 IPHeaderInStart Pointer to the start of the incomming packet's IP header
* \param DHCPHeaderInStart Pointer to the start of the incomming packet's DHCP header
* \param 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 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;
memcpy(&DHCPHeaderOUT->ClientHardwareAddress, &DHCPHeaderIN->ClientHardwareAddress, sizeof(MAC_Address_t));
DHCPHeaderOUT->Cookie = SwapEndian_32(DHCP_MAGIC_COOKIE);
/* Alter the incomming 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 incomming 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++) = 4;
*(DHCPOptionsOUTStart++) = 0xFF;
*(DHCPOptionsOUTStart++) = 0xFF;
*(DHCPOptionsOUTStart++) = 0xFF;
*(DHCPOptionsOUTStart++) = 0x00;
*(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) + 12 + 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,125 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for 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 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 postive matching between sent and recieved 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,263 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* USB Device Descriptors, for library use when in USB device mode. Descriptors are special
* computer-readable structures which the host requests upon device enumeration, to determine
* the device's capabilities and functions.
*/
#include "Descriptors.h"
/** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall
* device characteristics, including the supported USB version, control endpoint size and the
* number of device configurations. The descriptor is read out by the USB host when the enumeration
* process begins.
*/
USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
{
Header: {Size: sizeof(USB_Descriptor_Device_t), Type: DTYPE_Device},
USBSpecification: VERSION_BCD(01.10),
Class: 0x02,
SubClass: 0x00,
Protocol: 0x00,
Endpoint0Size: 8,
VendorID: 0x03EB,
ProductID: 0x204C,
ReleaseNumber: 0x0000,
ManufacturerStrIndex: 0x01,
ProductStrIndex: 0x02,
SerialNumStrIndex: NO_DESCRIPTOR,
NumberOfConfigurations: 1
};
/** Configuration descriptor structure. This descriptor, located in FLASH memory, describes the usage
* of the device in one of its supported configurations, including information about any device interfaces
* and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting
* a configuration so that the host may correctly communicate with the USB device.
*/
USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
{
Config:
{
Header: {Size: sizeof(USB_Descriptor_Configuration_Header_t), Type: DTYPE_Configuration},
TotalConfigurationSize: sizeof(USB_Descriptor_Configuration_t),
TotalInterfaces: 2,
ConfigurationNumber: 1,
ConfigurationStrIndex: NO_DESCRIPTOR,
ConfigAttributes: (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELFPOWERED),
MaxPowerConsumption: USB_CONFIG_POWER_MA(100)
},
CCI_Interface:
{
Header: {Size: sizeof(USB_Descriptor_Interface_t), Type: DTYPE_Interface},
InterfaceNumber: 0,
AlternateSetting: 0,
TotalEndpoints: 1,
Class: 0x02,
SubClass: 0x02,
Protocol: 0xFF,
InterfaceStrIndex: NO_DESCRIPTOR
},
CDC_Functional_Header:
{
Header: {Size: sizeof(CDC_FUNCTIONAL_DESCRIPTOR(2)), Type: 0x24},
SubType: 0x00,
Data: {0x01, 0x10}
},
CDC_Functional_CallManagement:
{
Header: {Size: sizeof(CDC_FUNCTIONAL_DESCRIPTOR(2)), Type: 0x24},
SubType: 0x01,
Data: {0x00, 0x00}
},
CDC_Functional_AbstractControlManagement:
{
Header: {Size: sizeof(CDC_FUNCTIONAL_DESCRIPTOR(1)), Type: 0x24},
SubType: 0x02,
Data: {0x00}
},
CDC_Functional_Union:
{
Header: {Size: sizeof(CDC_FUNCTIONAL_DESCRIPTOR(2)), Type: 0x24},
SubType: 0x06,
Data: {0x00, 0x01}
},
ManagementEndpoint:
{
Header: {Size: sizeof(USB_Descriptor_Endpoint_t), Type: DTYPE_Endpoint},
EndpointAddress: (ENDPOINT_DESCRIPTOR_DIR_IN | CDC_NOTIFICATION_EPNUM),
Attributes: EP_TYPE_INTERRUPT,
EndpointSize: CDC_NOTIFICATION_EPSIZE,
PollingIntervalMS: 0x02
},
DCI_Interface:
{
Header: {Size: sizeof(USB_Descriptor_Interface_t), Type: DTYPE_Interface},
InterfaceNumber: 1,
AlternateSetting: 0,
TotalEndpoints: 2,
Class: 0x0A,
SubClass: 0x00,
Protocol: 0x00,
InterfaceStrIndex: NO_DESCRIPTOR
},
DataOutEndpoint:
{
Header: {Size: sizeof(USB_Descriptor_Endpoint_t), Type: DTYPE_Endpoint},
EndpointAddress: (ENDPOINT_DESCRIPTOR_DIR_OUT | CDC_RX_EPNUM),
Attributes: EP_TYPE_BULK,
EndpointSize: CDC_TXRX_EPSIZE,
PollingIntervalMS: 0x00
},
DataInEndpoint:
{
Header: {Size: sizeof(USB_Descriptor_Endpoint_t), Type: DTYPE_Endpoint},
EndpointAddress: (ENDPOINT_DESCRIPTOR_DIR_IN | CDC_TX_EPNUM),
Attributes: EP_TYPE_BULK,
EndpointSize: CDC_TXRX_EPSIZE,
PollingIntervalMS: 0x00
}
};
/** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests
* the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate
* via the language ID table available at USB.org what languages the device supports for its string descriptors.
*/
USB_Descriptor_String_t PROGMEM LanguageString =
{
Header: {Size: USB_STRING_LEN(1), Type: DTYPE_String},
UnicodeString: {LANGUAGE_ID_ENG}
};
/** Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable
* form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device
* Descriptor.
*/
USB_Descriptor_String_t PROGMEM ManufacturerString =
{
Header: {Size: USB_STRING_LEN(11), Type: DTYPE_String},
UnicodeString: L"Dean Camera"
};
/** Product descriptor string. This is a Unicode string containing the product's details in human readable form,
* and is read out upon request by the host when the appropriate string ID is requested, listed in the Device
* Descriptor.
*/
USB_Descriptor_String_t PROGMEM ProductString =
{
Header: {Size: USB_STRING_LEN(19), Type: DTYPE_String},
UnicodeString: L"LUFA RNDIS CDC Demo"
};
/** This function is called by the library when in device mode, and must be overridden (see StdDescriptors.h
* documentation) by the application code so that the address and size of a requested descriptor can be given
* to the USB library. When the device recieves a Get Descriptor request on the control endpoint, this function
* is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the
* USB host.
*/
uint16_t USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress)
{
const uint8_t DescriptorType = (wValue >> 8);
const uint8_t DescriptorNumber = (wValue & 0xFF);
void* Address = NULL;
uint16_t Size = NO_DESCRIPTOR;
switch (DescriptorType)
{
case DTYPE_Device:
Address = DESCRIPTOR_ADDRESS(DeviceDescriptor);
Size = sizeof(USB_Descriptor_Device_t);
break;
case DTYPE_Configuration:
Address = DESCRIPTOR_ADDRESS(ConfigurationDescriptor);
Size = sizeof(USB_Descriptor_Configuration_t);
break;
case DTYPE_String:
switch (DescriptorNumber)
{
case 0x00:
Address = DESCRIPTOR_ADDRESS(LanguageString);
Size = pgm_read_byte(&LanguageString.Header.Size);
break;
case 0x01:
Address = DESCRIPTOR_ADDRESS(ManufacturerString);
Size = pgm_read_byte(&ManufacturerString.Header.Size);
break;
case 0x02:
Address = DESCRIPTOR_ADDRESS(ProductString);
Size = pgm_read_byte(&ProductString.Header.Size);
break;
}
break;
}
*DescriptorAddress = Address;
return Size;
}

View file

@ -0,0 +1,98 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for Descriptors.c.
*/
#ifndef _DESCRIPTORS_H_
#define _DESCRIPTORS_H_
/* Includes: */
#include <LUFA/Drivers/USB/USB.h>
#include <avr/pgmspace.h>
/* Macros: */
/** Macro to define a CDC class-specific functional descriptor. CDC functional descriptors have a
* uniform structure but variable sized data payloads, thus cannot be represented accurately by
* a single typedef struct. A macro is used instead so that functional descriptors can be created
* easily by specifying the size of the payload. This allows sizeof() to work correctly.
*
* \param DataSize Size in bytes of the CDC functional descriptor's data payload
*/
#define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \
struct \
{ \
USB_Descriptor_Header_t Header; \
uint8_t SubType; \
uint8_t Data[DataSize]; \
}
/** Endpoint number of the CDC device-to-host notification IN endpoint. */
#define CDC_NOTIFICATION_EPNUM 3
/** Endpoint number of the CDC device-to-host data IN endpoint. */
#define CDC_TX_EPNUM 1
/** Endpoint number of the CDC host-to-device data OUT endpoint. */
#define CDC_RX_EPNUM 2
/** Size in bytes of the CDC device-to-host notification IN endpoint. */
#define CDC_NOTIFICATION_EPSIZE 8
/** Size in bytes of the CDC data IN and OUT endpoints. */
#define CDC_TXRX_EPSIZE 64
/* Type Defines: */
/** Type define for the device configuration descriptor structure. This must be defined in the
* application code, as the configuration descriptor contains several sub-descriptors which
* vary between devices, and which describe the device's usage to the host.
*/
typedef struct
{
USB_Descriptor_Configuration_Header_t Config;
USB_Descriptor_Interface_t CCI_Interface;
CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_Header;
CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_CallManagement;
CDC_FUNCTIONAL_DESCRIPTOR(1) CDC_Functional_AbstractControlManagement;
CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_Union;
USB_Descriptor_Endpoint_t ManagementEndpoint;
USB_Descriptor_Interface_t DCI_Interface;
USB_Descriptor_Endpoint_t DataOutEndpoint;
USB_Descriptor_Endpoint_t DataInEndpoint;
} USB_Descriptor_Configuration_t;
/* Function Prototypes: */
uint16_t USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress)
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,136 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Ethernet frame packet handling routines. This protocol handles the processing of raw Ethernet
* frames sent and receieved, deferring the processing of subpacket protocols to the appropriate
* protocol handlers, such as DHCP or ARP.
*/
#include "Ethernet.h"
/* Global Variables: */
/** Ethernet Frame buffer structure, to hold the incomming Ethernet frame from the host. */
Ethernet_Frame_Info_t FrameIN;
/** Ethernet Frame buffer structure, to hold the outgoing Ethernet frame to the host. */
Ethernet_Frame_Info_t FrameOUT;
/** 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 incomming 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(void)
{
DecodeEthernetFrameHeader(FrameIN.FrameData);
/* Cast the incomming 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.FrameData[sizeof(Ethernet_Frame_Header_t)],
&FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t)]);
break;
}
/* Protcol 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);
FrameOUT.FrameInBuffer = true;
}
}
/* Check if the packet was processed */
if (RetSize != NO_PROCESS)
{
/* Clear the frame buffer */
FrameIN.FrameInBuffer = false;
}
}
/** Calculates the appropriate ethernet checksum, consisting of the addition of the one's
* compliment of each word, complimented.
*
* \param Data Pointer to the packet buffer data whose checksum must be calculated
* \param 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 (uint8_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,116 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for Ethernet.c.
*/
#ifndef _ETHERNET_H_
#define _ETHERNET_H_
/* Includes: */
#include <avr/io.h>
#include <string.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 virtual server on the network */
#define SERVER_MAC_ADDRESS {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}
/** 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 MAC1 First MAC address
* \param MAC2 Second MAC address
*
* \return True if the addresses match, false otherwise
*/
#define MAC_COMPARE(MAC1, MAC2) (memcmp(MAC1, MAC2, sizeof(MAC_Address_t)) == 0)
/** Maximum size of an incomming or outgoing Ethernet frame in bytes */
#define ETHERNET_FRAME_SIZE_MAX 1500
/** 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 buffer. */
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 */
bool FrameInBuffer; /**< Indicates if a frame is currently stored in the buffer */
} Ethernet_Frame_Info_t;
/** 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 */
union
{
uint16_t EtherType; /**< Ethernet packet subprotocol type, for Ethernet V2 packets */
uint16_t Length; /**< Ethernet frame length, for Ethernet V1 packets */
};
} Ethernet_Frame_Header_t;
/* External Variables: */
extern Ethernet_Frame_Info_t FrameIN;
extern Ethernet_Frame_Info_t FrameOUT;
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(void);
uint16_t Ethernet_Checksum16(void* Data, uint16_t Bytes);
#endif

View file

@ -0,0 +1,87 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* 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_
/* 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 a physical MAC address of a device on a network */
typedef struct
{
uint8_t Octets[6]; /**< Individual bytes of a MAC address */
} MAC_Address_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,79 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* 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 InDataStart Pointer to the start of the incomming packet's ICMP header
* \param 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(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;
uint16_t DataSize = FrameIN.FrameLength - ((((uint16_t)InDataStart + sizeof(ICMP_Header_t)) - (uint16_t)FrameIN.FrameData));
/* Copy the remaining payload to the response - echo requests should echo back any sent data */
memcpy(&((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,80 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for 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, a 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(void* InDataStart, void* OutDataStart);
#endif

View file

@ -0,0 +1,111 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* 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 subprotocol handler.
*
* \param InDataStart Pointer to the start of the incomming packet's IP header
* \param 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(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(&((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, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for 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"
/* Macros: */
/** Protocol IP address of the host (client) machine, once assigned by DHCP */
#define CLIENT_IP_ADDRESS { 10, 0, 0, 1}
/** Protocol IP address of the virtual server machine */
#define SERVER_IP_ADDRESS { 10, 0, 0, 2}
/** Protocol IP address of the broadcase 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 IP1 First IP address
* \param IP2 Second IP address
*
* \return True if the addresses match, 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 int HeaderLength : 4; /**< Total length of the packet header, in 4-byte blocks */
unsigned int Version : 4; /**< IP protocol version */
unsigned int TypeOfService : 8; /**< Special service type identifier, indicating delay/throughput/reliability levels */
unsigned int TotalLength : 16; /**< Total length of the IP packet, in bytes */
unsigned int Identification : 16; /**< Idenfication value for identifying fragmented packets */
unsigned int FragmentOffset : 13; /**< Offset of this IP fragment */
unsigned int Flags : 3; /**< Fragment flags, to indicate if a packet is fragmented */
unsigned int TTL : 8; /**< Maximum allowable number of hops to reach the packet destination */
unsigned int Protocol : 8; /**< Encapsulated protocol type */
unsigned int HeaderChecksum : 16; /**< 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(void* InDataStart, void* OutDataStart);
#endif

View file

@ -0,0 +1,52 @@
; Windows LUFA RNDIS Setup File
; Copyright (c) 2000 Microsoft Corporation
[Version]
Signature = "$Windows NT$"
Class = Net
ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
Provider = %COMPANY%
DriverVer = 06/21/2006,6.0.6000.16384
;CatalogFile = device.cat
[Manufacturer]
%COMPANY% = RndisDevices,NTx86,NTamd64,NTia64
; Decoration for x86 architecture
[RndisDevices.NTx86]
%RNDISDEV% = RNDIS.NT.5.1, USB\VID_03EB&PID_204C
; Decoration for x64 architecture
[RndisDevices.NTamd64]
%RNDISDEV% = RNDIS.NT.5.1, USB\VID_03EB&PID_204C
; Decoration for ia64 architecture
[RndisDevices.NTia64]
%RNDISDEV% = RNDIS.NT.5.1, USB\VID_03EB&PID_204C
;@@@ This is the common setting for setup
[ControlFlags]
ExcludeFromSelect=*
; DDInstall section
; References the in-build Netrndis.inf
[RNDIS.NT.5.1]
Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
BusType = 15
; NEVER REMOVE THE FOLLOWING REFERENCE FOR NETRNDIS.INF
include = netrndis.inf
needs = Usb_Rndis.ndi
AddReg = Rndis_AddReg_Vista
; DDInstal.Services section
[RNDIS.NT.5.1.Services]
include = netrndis.inf
needs = Usb_Rndis.ndi.Services
; No sys copyfiles - the sys files are already in-build
; (part of the operating system).
; Modify these strings for your device as needed.
[Strings]
COMPANY="LUFA Library"
RNDISDEV="LUFA USB RNDIS Demo"

View file

@ -0,0 +1,280 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/* Protocol decoders for Ethernet, TCP, IP, ICMP and ARP. Each of these routines
accepts a header to the appropriate protocol and prints out pertient 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 incomming 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 InDataStart Pointer to the start of an Ethernet frame header
*/
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"));
printf_P(PSTR(" + Frame Size: %u\r\n"), FrameIN.FrameLength);
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]);
if (SwapEndian_16(FrameIN.FrameLength) > ETHERNET_VER2_MINSIZE)
printf_P(PSTR(" + Protocol: 0x%04x\r\n"), SwapEndian_16(FrameHeader->EtherType));
else
printf_P(PSTR(" + Protocol: UNKNOWN E1\r\n"));
#endif
}
/** Decodes an ARP header and prints its contents to through the USART in a human readable format.
*
* \param 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 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 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 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 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 InDataStart Pointer to the start of a DHCP packet header
*/
void DecodeDHCPHeader(void* InDataStart)
{
#if !defined(NO_DECODE_DHCP)
uint8_t* DHCPOptions = (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;
}
}
DHCPOptionsINStart += ((DHCPOptionsINStart[0] == DHCP_OPTION_PAD) ? 1 : (DHCPOptionsINStart[1] + 2));
}
#endif
}

View file

@ -0,0 +1,56 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for ProtocolDecoders.c.
*/
#ifndef _PROTOCOL_DECODERS_H_
#define _PROTOCOL_DECODERS_H_
/* Includes: */
#include <avr/io.h>
#include <LUFA/Drivers/AT90USBXXX/Serial_Stream.h>
#include "EthernetProtocols.h"
#include "Ethernet.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,386 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* RNDIS command handler functions. This handles RNDIS commands according to
* the Microsoft RNDIS specification, creating a USB Ethernet network adapter.
*/
#define INCLUDE_FROM_RNDIS_C
#include "RNDIS.h"
/* Global Variables: */
/** Physical MAC address of the network adapter, which becomes the MAC address of the host for packets sent to the adapter. */
static MAC_Address_t PROGMEM AdapterMACAddress = {ADAPTER_MAC_ADDRESS};
/** Vendor description of the adapter. This is overridden by the INF file required to install the appropriate RNDIS drivers for
* the device, but may still be used by the OS in some circumstances.
*/
static char PROGMEM AdapterVendorDescription[] = "LUFA RNDIS Adapter";
/** List of RNDIS OID commands supported by this adapter. */
static const uint32_t PROGMEM AdapterSupportedOIDList[] =
{
OID_GEN_SUPPORTED_LIST,
OID_GEN_HARDWARE_STATUS,
OID_GEN_MEDIA_SUPPORTED,
OID_GEN_MEDIA_IN_USE,
OID_GEN_MAXIMUM_FRAME_SIZE,
OID_GEN_MAXIMUM_TOTAL_SIZE,
OID_GEN_LINK_SPEED,
OID_GEN_TRANSMIT_BLOCK_SIZE,
OID_GEN_RECEIVE_BLOCK_SIZE,
OID_GEN_VENDOR_ID,
OID_GEN_VENDOR_DESCRIPTION,
OID_GEN_CURRENT_PACKET_FILTER,
OID_GEN_MAXIMUM_TOTAL_SIZE,
OID_GEN_MEDIA_CONNECT_STATUS,
OID_GEN_XMIT_OK,
OID_GEN_RCV_OK,
OID_GEN_XMIT_ERROR,
OID_GEN_RCV_ERROR,
OID_GEN_RCV_NO_BUFFER,
OID_802_3_PERMANENT_ADDRESS,
OID_802_3_CURRENT_ADDRESS,
OID_802_3_MULTICAST_LIST,
OID_802_3_MAXIMUM_LIST_SIZE,
OID_802_3_RCV_ERROR_ALIGNMENT,
OID_802_3_XMIT_ONE_COLLISION,
OID_802_3_XMIT_MORE_COLLISIONS,
};
/** Buffer for RNDIS messages (as distinct from Ethernet frames sent through the adapter. This must be big enough to hold the entire
* Supported OID list, plus the response header. The buffer is half-duplex, and is written to as it is read to save on SRAM - for this
* reason, care must be taken when constructing RNDIS responses that unread data is not overwritten when writing in responses.
*/
uint8_t RNDISMessageBuffer[sizeof(AdapterSupportedOIDList) + sizeof(RNDIS_QUERY_CMPLT_t)];
/** Pointer to the RNDIS message header at the top of the RNDIS message buffer, for convenience. */
RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISMessageBuffer;
/** Indicates if a RNDIS message response is ready to be sent back to the host. */
bool ResponseReady = false;
/** Current RNDIS adapter state, a value from the RNDIS_States_t enum. */
uint8_t CurrRNDISState = RNDIS_Uninitialized;
/** Current Ethernet packet filter mask. This is non-zero when the adapter is initialized, or zero when disabled. */
uint32_t CurrPacketFilter = 0;
/** Processes the RNDIS message received by the host and stored in the RNDISMessageBuffer global buffer. If a response is
* created, the ResponseReady global is updated so that the response is written back to the host upon request.
*/
void ProcessRNDISControlMessage(void)
{
/* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of
this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */
switch (MessageHeader->MessageType)
{
case REMOTE_NDIS_INITIALIZE_MSG:
/* Initialize the adapter - return information about the supported RNDIS version and buffer sizes */
ResponseReady = true;
RNDIS_INITIALIZE_MSG_t* INITIALIZE_Message = (RNDIS_INITIALIZE_MSG_t*)&RNDISMessageBuffer;
RNDIS_INITIALIZE_CMPLT_t* INITIALIZE_Response = (RNDIS_INITIALIZE_CMPLT_t*)&RNDISMessageBuffer;
INITIALIZE_Response->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
INITIALIZE_Response->MessageLength = sizeof(RNDIS_INITIALIZE_CMPLT_t);
INITIALIZE_Response->RequestId = INITIALIZE_Message->RequestId;
INITIALIZE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
INITIALIZE_Response->MajorVersion = REMOTE_NDIS_VERSION_MAJOR;
INITIALIZE_Response->MinorVersion = REMOTE_NDIS_VERSION_MINOR;
INITIALIZE_Response->DeviceFlags = REMOTE_NDIS_DF_CONNECTIONLESS;
INITIALIZE_Response->Medium = REMOTE_NDIS_MEDIUM_802_3;
INITIALIZE_Response->MaxPacketsPerTransfer = 1;
INITIALIZE_Response->MaxTransferSize = (sizeof(RNDIS_PACKET_MSG_t) + ETHERNET_FRAME_SIZE_MAX);
INITIALIZE_Response->PacketAlignmentFactor = 0;
INITIALIZE_Response->AFListOffset = 0;
INITIALIZE_Response->AFListSize = 0;
CurrRNDISState = RNDIS_Initialized;
break;
case REMOTE_NDIS_HALT_MSG:
/* Halt the adapter, reset the adapter state - note that no response should be returned when completed */
ResponseReady = false;
MessageHeader->MessageLength = 0;
CurrRNDISState = RNDIS_Uninitialized;
break;
case REMOTE_NDIS_QUERY_MSG:
/* Request for information about a parameter about the adapter, specified as an OID token */
ResponseReady = true;
RNDIS_QUERY_MSG_t* QUERY_Message = (RNDIS_QUERY_MSG_t*)&RNDISMessageBuffer;
RNDIS_QUERY_CMPLT_t* QUERY_Response = (RNDIS_QUERY_CMPLT_t*)&RNDISMessageBuffer;
uint32_t Query_Oid = QUERY_Message->Oid;
void* QueryData = &RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
QUERY_Message->InformationBufferOffset];
void* ResponseData = &RNDISMessageBuffer[sizeof(RNDIS_QUERY_CMPLT_t)];
uint16_t ResponseSize;
QUERY_Response->MessageType = REMOTE_NDIS_QUERY_CMPLT;
QUERY_Response->MessageLength = sizeof(RNDIS_QUERY_CMPLT_t);
if (ProcessNDISQuery(Query_Oid, QueryData, QUERY_Message->InformationBufferLength,
ResponseData, &ResponseSize))
{
QUERY_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
QUERY_Response->MessageLength += ResponseSize;
QUERY_Response->InformationBufferLength = ResponseSize;
QUERY_Response->InformationBufferOffset = (sizeof(RNDIS_QUERY_CMPLT_t) - sizeof(RNDIS_Message_Header_t));
}
else
{
QUERY_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;
QUERY_Response->InformationBufferLength = 0;
QUERY_Response->InformationBufferOffset = 0;
}
break;
case REMOTE_NDIS_SET_MSG:
/* Request to set a parameter of the adapter, specified as an OID token */
ResponseReady = true;
RNDIS_SET_MSG_t* SET_Message = (RNDIS_SET_MSG_t*)&RNDISMessageBuffer;
RNDIS_SET_CMPLT_t* SET_Response = (RNDIS_SET_CMPLT_t*)&RNDISMessageBuffer;
uint32_t SET_Oid = SET_Message->Oid;
SET_Response->MessageType = REMOTE_NDIS_SET_CMPLT;
SET_Response->MessageLength = sizeof(RNDIS_SET_CMPLT_t);
SET_Response->RequestId = SET_Message->RequestId;
void* SetData = &RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
SET_Message->InformationBufferOffset];
if (ProcessNDISSet(SET_Oid, SetData, SET_Message->InformationBufferLength))
SET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
else
SET_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;
break;
case REMOTE_NDIS_RESET_MSG:
/* Soft reset the adapter */
ResponseReady = true;
RNDIS_RESET_CMPLT_t* RESET_Response = (RNDIS_RESET_CMPLT_t*)&RNDISMessageBuffer;
RESET_Response->MessageType = REMOTE_NDIS_RESET_CMPLT;
RESET_Response->MessageLength = sizeof(RNDIS_RESET_CMPLT_t);
RESET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
RESET_Response->AddressingReset = 0;
break;
case REMOTE_NDIS_KEEPALIVE_MSG:
/* Keep alive message sent to the adapter every 5 seconds when idle to ensure it is still responding */
ResponseReady = true;
RNDIS_KEEPALIVE_MSG_t* KEEPALIVE_Message = (RNDIS_KEEPALIVE_MSG_t*)&RNDISMessageBuffer;
RNDIS_KEEPALIVE_CMPLT_t* KEEPALIVE_Response = (RNDIS_KEEPALIVE_CMPLT_t*)&RNDISMessageBuffer;
KEEPALIVE_Response->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
KEEPALIVE_Response->MessageLength = sizeof(RNDIS_KEEPALIVE_CMPLT_t);
KEEPALIVE_Response->RequestId = KEEPALIVE_Message->RequestId;
KEEPALIVE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
break;
}
}
/** Processes RNDIS query commands, retrieving information from the adapter and reporting it back to the host. The requested
* parameter is given as an OID value.
*
* \param OId OId value of the parameter being queried
* \param QueryData Pointer to any extra query data being sent by the host to the device inside the RNDIS message buffer
* \param QuerySize Size in bytes of the extra query data being sent by the host
* \param ResponseData Pointer to the start of the query response inside the RNDIS message buffer
* \param ResponseSize Pointer to the size in bytes of the response data being sent to the host
*
* \return Boolean true if the query was handled, false otherwise
*/
static bool ProcessNDISQuery(uint32_t OId, void* QueryData, uint16_t QuerySize,
void* ResponseData, uint16_t* ResponseSize)
{
/* Handler for REMOTE_NDIS_QUERY_MSG messages */
switch (OId)
{
case OID_GEN_SUPPORTED_LIST:
*ResponseSize = sizeof(AdapterSupportedOIDList);
/* Copy the list of supported NDIS OID tokens to the response buffer */
memcpy_P(ResponseData, AdapterSupportedOIDList, sizeof(AdapterSupportedOIDList));
return true;
case OID_GEN_HARDWARE_STATUS:
*ResponseSize = sizeof(uint32_t);
/* Always indicate hardware ready */
*((uint32_t*)ResponseData) = NdisHardwareStatusReady;
return true;
case OID_GEN_MEDIA_SUPPORTED:
case OID_GEN_MEDIA_IN_USE:
*ResponseSize = sizeof(uint32_t);
/* Indicate 802.3 (Ethernet) supported by the adapter */
*((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIUM_802_3;
return true;
case OID_GEN_VENDOR_ID:
*ResponseSize = sizeof(uint32_t);
/* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */
*((uint32_t*)ResponseData) = 0x00FFFFFF;
return true;
case OID_GEN_MAXIMUM_FRAME_SIZE:
case OID_GEN_TRANSMIT_BLOCK_SIZE:
case OID_GEN_RECEIVE_BLOCK_SIZE:
*ResponseSize = sizeof(uint32_t);
/* Indicate that the maximum frame size is the size of the ethernet frame buffer */
*((uint32_t*)ResponseData) = ETHERNET_FRAME_SIZE_MAX;
return true;
case OID_GEN_VENDOR_DESCRIPTION:
*ResponseSize = sizeof(AdapterVendorDescription);
/* Copy vendor description string to the response buffer */
memcpy_P(ResponseData, AdapterVendorDescription, sizeof(AdapterVendorDescription));
return true;
case OID_GEN_MEDIA_CONNECT_STATUS:
*ResponseSize = sizeof(uint32_t);
/* Always indicate that the adapter is connected to a network */
*((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIA_STATE_CONNECTED;
return true;
case OID_GEN_LINK_SPEED:
*ResponseSize = sizeof(uint32_t);
/* Indicate 10Mb/s link speed */
*((uint32_t*)ResponseData) = 100000;
return true;
case OID_802_3_PERMANENT_ADDRESS:
case OID_802_3_CURRENT_ADDRESS:
*ResponseSize = sizeof(MAC_Address_t);
/* Copy over the fixed adapter MAC to the response buffer */
memcpy_P(ResponseData, &AdapterMACAddress, sizeof(MAC_Address_t));
return true;
case OID_802_3_MAXIMUM_LIST_SIZE:
*ResponseSize = sizeof(uint32_t);
/* Indicate only one multicast address supported */
*((uint32_t*)ResponseData) = 1;
return true;
case OID_GEN_CURRENT_PACKET_FILTER:
*ResponseSize = sizeof(uint32_t);
/* Indicate the current packet filter mask */
*((uint32_t*)ResponseData) = CurrPacketFilter;
return true;
case OID_GEN_XMIT_OK:
case OID_GEN_RCV_OK:
case OID_GEN_XMIT_ERROR:
case OID_GEN_RCV_ERROR:
case OID_GEN_RCV_NO_BUFFER:
case OID_802_3_RCV_ERROR_ALIGNMENT:
case OID_802_3_XMIT_ONE_COLLISION:
case OID_802_3_XMIT_MORE_COLLISIONS:
*ResponseSize = sizeof(uint32_t);
/* Unused statistic OIDs - always return 0 for each */
*((uint32_t*)ResponseData) = 0;
return true;
case OID_GEN_MAXIMUM_TOTAL_SIZE:
*ResponseSize = sizeof(uint32_t);
/* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */
*((uint32_t*)ResponseData) = (sizeof(RNDISMessageBuffer) + ETHERNET_FRAME_SIZE_MAX);
return true;
default:
return false;
}
}
/** Processes RNDIS set commands, setting adapter parameters to values given by the host. The requested parameter is given
* as an OID value.
*
* \param OId OId value of the parameter being set
* \param SetData Pointer to the parameter value in the RNDIS message buffer
* \param SetSize Size in bytes of the parameter value being sent by the host
*
* \return Boolean true if the set was handled, false otherwise
*/
static bool ProcessNDISSet(uint32_t OId, void* SetData, uint16_t SetSize)
{
/* Handler for REMOTE_NDIS_SET_MSG messages */
switch (OId)
{
case OID_GEN_CURRENT_PACKET_FILTER:
/* Save the packet filter mask in case the host queries it again later */
CurrPacketFilter = *((uint32_t*)SetData);
/* Set the RNDIS state to initialized if the packet filter is non-zero */
CurrRNDISState = ((CurrPacketFilter) ? RNDIS_Data_Initialized : RNDIS_Data_Initialized);
return true;
case OID_802_3_MULTICAST_LIST:
/* Do nothing - throw away the value from the host as it is unused */
return true;
default:
return false;
}
}

View file

@ -0,0 +1,226 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for RNDIS.c.
*/
#ifndef _RNDIS_H_
#define _RNDIS_H_
/* Includes: */
#include <avr/io.h>
#include <stdbool.h>
#include "RNDISEthernet.h"
#include "RNDISConstants.h"
#include "Ethernet.h"
/* Macros: */
/** Physical MAC Address of the USB netowork adapter */
#define ADAPTER_MAC_ADDRESS {0x02, 0x00, 0x02, 0x00, 0x02, 0x00}
/** Implemented RNDIS Version Major */
#define REMOTE_NDIS_VERSION_MAJOR 0x01
/** Implemented RNDIS Version Minor */
#define REMOTE_NDIS_VERSION_MINOR 0x00
/** RNDIS request to issue a host-to-device NDIS command */
#define SEND_ENCAPSULATED_COMMAND 0x00
/** RNDIS request to issue a device-to-host NDIS response */
#define GET_ENCAPSULATED_RESPONSE 0x01
/* Enums: */
/** Enum for the possible NDIS adapter states. */
enum RNDIS_States_t
{
RNDIS_Uninitialized = 0, /**< Adapter currently uninitialized */
RNDIS_Initialized = 1, /**< Adapter currently initialized but not ready for data transfers */
RNDIS_Data_Initialized = 2, /**< Adapter currently initialized and ready for data transfers */
};
/** Enum for the NDIS hardware states */
enum NDIS_Hardware_Status_t
{
NdisHardwareStatusReady, /**< Hardware Ready to accept commands from the host */
NdisHardwareStatusInitializing, /**< Hardware busy initializing */
NdisHardwareStatusReset, /**< Hardware reset */
NdisHardwareStatusClosing, /**< Hardware currently closing */
NdisHardwareStatusNotReady /**< Hardware not ready to accept commands from the host */
};
/* Type Defines: */
/** Type define for a RNDIS message header, sent before RNDIS messages */
typedef struct
{
uint32_t MessageType; /**< RNDIS message type, a REMOTE_NDIS_*_MSG constant */
uint32_t MessageLength; /**< Total length of the RNDIS message, in bytes */
} RNDIS_Message_Header_t;
/** Type define for a RNDIS packet message, used to encapsulate Ethernet packets sent to and from the adapter */
typedef struct
{
uint32_t MessageType;
uint32_t MessageLength;
uint32_t DataOffset;
uint32_t DataLength;
uint32_t OOBDataOffset;
uint32_t OOBDataLength;
uint32_t NumOOBDataElements;
uint32_t PerPacketInfoOffset;
uint32_t PerPacketInfoLength;
uint32_t VcHandle;
uint32_t Reserved;
} RNDIS_PACKET_MSG_t;
/** Type define for a RNDIS Initialize command message */
typedef struct
{
uint32_t MessageType;
uint32_t MessageLength;
uint32_t RequestId;
uint32_t MajorVersion;
uint32_t MinorVersion;
uint32_t MaxTransferSize;
} RNDIS_INITIALIZE_MSG_t;
/** Type define for a RNDIS Initialize complete response message */
typedef struct
{
uint32_t MessageType;
uint32_t MessageLength;
uint32_t RequestId;
uint32_t Status;
uint32_t MajorVersion;
uint32_t MinorVersion;
uint32_t DeviceFlags;
uint32_t Medium;
uint32_t MaxPacketsPerTransfer;
uint32_t MaxTransferSize;
uint32_t PacketAlignmentFactor;
uint32_t AFListOffset;
uint32_t AFListSize;
} RNDIS_INITIALIZE_CMPLT_t;
/** Type define for a RNDIS Keepalive command message */
typedef struct
{
uint32_t MessageType;
uint32_t MessageLength;
uint32_t RequestId;
} RNDIS_KEEPALIVE_MSG_t;
/** Type define for a RNDIS Keepalive complete message */
typedef struct
{
uint32_t MessageType;
uint32_t MessageLength;
uint32_t RequestId;
uint32_t Status;
} RNDIS_KEEPALIVE_CMPLT_t;
/** Type define for a RNDIS Reset complete message */
typedef struct
{
uint32_t MessageType;
uint32_t MessageLength;
uint32_t Status;
uint32_t AddressingReset;
} RNDIS_RESET_CMPLT_t;
/** Type define for a RNDIS Set command message */
typedef struct
{
uint32_t MessageType;
uint32_t MessageLength;
uint32_t RequestId;
uint32_t Oid;
uint32_t InformationBufferLength;
uint32_t InformationBufferOffset;
uint32_t DeviceVcHandle;
} RNDIS_SET_MSG_t;
/** Type define for a RNDIS Set complete response message */
typedef struct
{
uint32_t MessageType;
uint32_t MessageLength;
uint32_t RequestId;
uint32_t Status;
} RNDIS_SET_CMPLT_t;
/** Type define for a RNDIS Query command message */
typedef struct
{
uint32_t MessageType;
uint32_t MessageLength;
uint32_t RequestId;
uint32_t Oid;
uint32_t InformationBufferLength;
uint32_t InformationBufferOffset;
uint32_t DeviceVcHandle;
} RNDIS_QUERY_MSG_t;
/** Type define for a RNDIS Query complete response message */
typedef struct
{
uint32_t MessageType;
uint32_t MessageLength;
uint32_t RequestId;
uint32_t Status;
uint32_t InformationBufferLength;
uint32_t InformationBufferOffset;
} RNDIS_QUERY_CMPLT_t;
/* External Variables: */
extern uint8_t RNDISMessageBuffer[];
extern RNDIS_Message_Header_t* MessageHeader;
extern bool ResponseReady;
extern uint8_t CurrRNDISState;
/* Function Prototypes: */
void ProcessRNDISControlMessage(void);
#if defined(INCLUDE_FROM_RNDIS_C)
static bool ProcessNDISQuery(uint32_t OId, void* QueryData, uint16_t QuerySize,
void* ResponseData, uint16_t* ResponseSize);
static bool ProcessNDISSet(uint32_t OId, void* SetData, uint16_t SetSize);
#endif
#endif

View file

@ -0,0 +1,98 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* RNDIS specification related constants. For more information on these
* constants, please refer to the Microsoft RNDIS specification.
*/
#ifndef _RNDIS_CONSTANTS_H_
#define _RNDIS_CONSTANTS_H_
/* Macros: */
#define REMOTE_NDIS_PACKET_MSG 0x00000001UL
#define REMOTE_NDIS_INITIALIZE_MSG 0x00000002UL
#define REMOTE_NDIS_HALT_MSG 0x00000003UL
#define REMOTE_NDIS_QUERY_MSG 0x00000004UL
#define REMOTE_NDIS_SET_MSG 0x00000005UL
#define REMOTE_NDIS_RESET_MSG 0x00000006UL
#define REMOTE_NDIS_INDICATE_STATUS_MSG 0x00000007UL
#define REMOTE_NDIS_KEEPALIVE_MSG 0x00000008UL
#define REMOTE_NDIS_INITIALIZE_CMPLT 0x80000002UL
#define REMOTE_NDIS_QUERY_CMPLT 0x80000004UL
#define REMOTE_NDIS_SET_CMPLT 0x80000005UL
#define REMOTE_NDIS_RESET_CMPLT 0x80000006UL
#define REMOTE_NDIS_KEEPALIVE_CMPLT 0x80000008UL
#define REMOTE_NDIS_STATUS_SUCCESS 0x00000000UL
#define REMOTE_NDIS_STATUS_FAILURE 0xC0000001UL
#define REMOTE_NDIS_STATUS_INVALID_DATA 0xC0010015UL
#define REMOTE_NDIS_STATUS_NOT_SUPPORTED 0xC00000BBUL
#define REMOTE_NDIS_STATUS_MEDIA_CONNECT 0x4001000BUL
#define REMOTE_NDIS_STATUS_MEDIA_DISCONNECT 0x4001000CUL
#define REMOTE_NDIS_MEDIA_STATE_CONNECTED 0x00000000UL
#define REMOTE_NDIS_MEDIA_STATE_DISCONNECTED 0x00000001UL
#define REMOTE_NDIS_MEDIUM_802_3 0x00000000UL
#define REMOTE_NDIS_DF_CONNECTIONLESS 0x00000001UL
#define REMOTE_NDIS_DF_CONNECTION_ORIENTED 0x00000002UL
#define OID_GEN_SUPPORTED_LIST 0x00010101UL
#define OID_GEN_HARDWARE_STATUS 0x00010102UL
#define OID_GEN_MEDIA_SUPPORTED 0x00010103UL
#define OID_GEN_MEDIA_IN_USE 0x00010104UL
#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106UL
#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111UL
#define OID_GEN_LINK_SPEED 0x00010107UL
#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010AUL
#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010BUL
#define OID_GEN_VENDOR_ID 0x0001010CUL
#define OID_GEN_VENDOR_DESCRIPTION 0x0001010DUL
#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010EUL
#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111UL
#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114UL
#define OID_GEN_XMIT_OK 0x00020101UL
#define OID_GEN_RCV_OK 0x00020102UL
#define OID_GEN_XMIT_ERROR 0x00020103UL
#define OID_GEN_RCV_ERROR 0x00020104UL
#define OID_GEN_RCV_NO_BUFFER 0x00020105UL
#define OID_802_3_PERMANENT_ADDRESS 0x01010101UL
#define OID_802_3_CURRENT_ADDRESS 0x01010102UL
#define OID_802_3_MULTICAST_LIST 0x01010103UL
#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104UL
#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101UL
#define OID_802_3_XMIT_ONE_COLLISION 0x01020102UL
#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103UL
#endif

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,357 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Main source file for the RNDISEthernet demo. This file contains the main tasks of the demo and
* is responsible for the initial application hardware configuration.
*/
#include "RNDISEthernet.h"
/* Project Tags, for reading out using the ButtLoad project */
BUTTLOADTAG(ProjName, "LUFA RNDIS App");
BUTTLOADTAG(BuildTime, __TIME__);
BUTTLOADTAG(BuildDate, __DATE__);
BUTTLOADTAG(LUFAVersion, "LUFA V" LUFA_VERSION_STRING);
/* Scheduler Task List */
TASK_LIST
{
{ Task: USB_USBTask , TaskStatus: TASK_STOP },
{ Task: Ethernet_Task , TaskStatus: TASK_STOP },
{ Task: TCP_Task , TaskStatus: TASK_STOP },
{ Task: RNDIS_Task , TaskStatus: TASK_STOP },
};
/** Main program entry point. This routine configures the hardware required by the application, then
* starts the scheduler to run the USB management task.
*/
int main(void)
{
/* Disable watchdog if enabled by bootloader/fuses */
MCUSR &= ~(1 << WDRF);
wdt_disable();
/* Disable clock division */
clock_prescale_set(clock_div_1);
/* Hardware Initialization */
LEDs_Init();
SerialStream_Init(9600, false);
/* Webserver Initialization */
TCP_Init();
Webserver_Init();
printf_P(PSTR("\r\n\r\n****** RNDIS Demo running. ******\r\n"));
/* Indicate USB not ready */
UpdateStatus(Status_USBNotReady);
/* Initialize Scheduler so that it can be used */
Scheduler_Init();
/* Initialize USB Subsystem */
USB_Init();
/* Scheduling - routine never returns, so put this last in the main function */
Scheduler_Start();
}
/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
* starts the library USB task to begin the enumeration and USB management process.
*/
EVENT_HANDLER(USB_Connect)
{
/* Start USB management task */
Scheduler_SetTaskMode(USB_USBTask, TASK_RUN);
/* Indicate USB enumerating */
UpdateStatus(Status_USBEnumerating);
}
/** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
* the status LEDs and stops all the relevent tasks.
*/
EVENT_HANDLER(USB_Disconnect)
{
/* Stop running TCP/IP and USB management tasks */
Scheduler_SetTaskMode(RNDIS_Task, TASK_STOP);
Scheduler_SetTaskMode(Ethernet_Task, TASK_STOP);
Scheduler_SetTaskMode(TCP_Task, TASK_STOP);
Scheduler_SetTaskMode(USB_USBTask, TASK_STOP);
/* Indicate USB not ready */
UpdateStatus(Status_USBNotReady);
}
/** Event handler for the USB_ConfigurationChanged event. This is fired when the host sets the current configuration
* of the USB device after enumeration, and configures the RNDIS device endpoints and starts the relevent tasks.
*/
EVENT_HANDLER(USB_ConfigurationChanged)
{
/* Setup CDC Notification, Rx and Tx Endpoints */
Endpoint_ConfigureEndpoint(CDC_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT,
ENDPOINT_DIR_IN, CDC_NOTIFICATION_EPSIZE,
ENDPOINT_BANK_SINGLE);
Endpoint_ConfigureEndpoint(CDC_TX_EPNUM, EP_TYPE_BULK,
ENDPOINT_DIR_IN, CDC_TXRX_EPSIZE,
ENDPOINT_BANK_SINGLE);
Endpoint_ConfigureEndpoint(CDC_RX_EPNUM, EP_TYPE_BULK,
ENDPOINT_DIR_OUT, CDC_TXRX_EPSIZE,
ENDPOINT_BANK_SINGLE);
/* Indicate USB connected and ready */
UpdateStatus(Status_USBReady);
/* Start TCP/IP tasks */
Scheduler_SetTaskMode(RNDIS_Task, TASK_RUN);
Scheduler_SetTaskMode(Ethernet_Task, TASK_RUN);
Scheduler_SetTaskMode(TCP_Task, TASK_RUN);
}
/** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific
* control requests that are not handled internally by the USB library (including the RNDIS control commands,
* which set up the USB RNDIS network adapter), so that they can be handled appropriately for the application.
*/
EVENT_HANDLER(USB_UnhandledControlPacket)
{
/* Discard the unused wValue parameter */
Endpoint_Discard_Word();
/* Discard the unused wIndex parameter */
Endpoint_Discard_Word();
/* Read in the wLength parameter */
uint16_t wLength = Endpoint_Read_Word_LE();
/* Process RNDIS class commands */
switch (bRequest)
{
case SEND_ENCAPSULATED_COMMAND:
if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
{
/* Clear the SETUP packet, ready for data transfer */
Endpoint_ClearSetupReceived();
/* Read in the RNDIS message into the message buffer */
Endpoint_Read_Control_Stream_LE(RNDISMessageBuffer, wLength);
/* Finalize the stream transfer to clear the last packet from the host */
Endpoint_ClearSetupIN();
/* Process the RNDIS message */
ProcessRNDISControlMessage();
}
break;
case GET_ENCAPSULATED_RESPONSE:
if (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
{
/* Check if a response to the last message is ready */
if (!(MessageHeader->MessageLength))
{
/* Set the response to a single 0x00 byte to indicate that no response is ready */
RNDISMessageBuffer[0] = 0;
MessageHeader->MessageLength = 1;
}
/* Check if less than the requested number of bytes to transfer */
if (MessageHeader->MessageLength < wLength)
wLength = MessageHeader->MessageLength;
/* Clear the SETUP packet, ready for data transfer */
Endpoint_ClearSetupReceived();
/* Write the message response data to the endpoint */
Endpoint_Write_Control_Stream_LE(RNDISMessageBuffer, wLength);
/* Finalize the stream transfer to send the last packet or clear the host abort */
Endpoint_ClearSetupOUT();
/* Reset the message header once again after transmission */
MessageHeader->MessageLength = 0;
}
break;
}
}
/** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
* log to a serial port, or anything else that is suitable for status updates.
*
* \param CurrentStatus Current status of the system, from the RNDISEthernet_StatusCodes_t enum
*/
void UpdateStatus(uint8_t CurrentStatus)
{
uint8_t LEDMask = LEDS_NO_LEDS;
/* Set the LED mask to the appropriate LED mask based on the given status code */
switch (CurrentStatus)
{
case Status_USBNotReady:
LEDMask = (LEDS_LED1);
break;
case Status_USBEnumerating:
LEDMask = (LEDS_LED1 | LEDS_LED2);
break;
case Status_USBReady:
LEDMask = (LEDS_LED2 | LEDS_LED4);
break;
case Status_ProcessingEthernetFrame:
LEDMask = (LEDS_LED2 | LEDS_LED3);
break;
}
/* Set the board LEDs to the new LED mask */
LEDs_SetAllLEDs(LEDMask);
}
/** Task to manage the sending and receiving of encapsulated RNDIS data and notifications. This removes the RNDIS
* wrapper from recieved Ethernet frames and places them in the FrameIN global buffer, or adds the RNDIS wrapper
* to a frame in the FrameOUT global before sending the buffer contents to the host.
*/
TASK(RNDIS_Task)
{
/* Select the notification endpoint */
Endpoint_SelectEndpoint(CDC_NOTIFICATION_EPNUM);
/* Check if a message response is ready for the host */
if (Endpoint_ReadWriteAllowed() && ResponseReady)
{
USB_Notification_t Notification = (USB_Notification_t)
{
bmRequestType: (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
bNotification: NOTIF_RESPONSE_AVAILABLE,
wValue: 0,
wIndex: 0,
wLength: 0,
};
/* Indicate that a message response is ready for the host */
Endpoint_Write_Stream_LE(&Notification, sizeof(Notification));
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearCurrentBank();
/* Indicate a response is no longer ready */
ResponseReady = false;
}
/* Don't process the data endpoints until the system is in the data initialized state, and the buffer is free */
if ((CurrRNDISState == RNDIS_Data_Initialized) && !(MessageHeader->MessageLength))
{
/* Create a new packet header for reading/writing */
RNDIS_PACKET_MSG_t RNDISPacketHeader;
/* Select the data OUT endpoint */
Endpoint_SelectEndpoint(CDC_RX_EPNUM);
/* Check if the data OUT endpoint contains data, and that the IN buffer is empty */
if (Endpoint_ReadWriteAllowed() && !(FrameIN.FrameInBuffer))
{
/* Read in the packet message header */
Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t));
/* Stall the request if the data is too large */
if (RNDISPacketHeader.MessageLength > ETHERNET_FRAME_SIZE_MAX)
{
Endpoint_StallTransaction();
return;
}
/* Read in the Ethernet frame into the buffer */
Endpoint_Read_Stream_LE(FrameIN.FrameData, RNDISPacketHeader.DataLength);
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearCurrentBank();
/* Store the size of the Ethernet frame */
FrameIN.FrameLength = RNDISPacketHeader.DataLength;
/* Indicate Ethernet IN buffer full */
FrameIN.FrameInBuffer = true;
}
/* Select the data IN endpoint */
Endpoint_SelectEndpoint(CDC_TX_EPNUM);
/* Check if the data IN endpoint is ready for more data, and that the IN buffer is full */
if (Endpoint_ReadWriteAllowed() && FrameOUT.FrameInBuffer)
{
/* Clear the packet header with all 0s so that the relevant fields can be filled */
memset(&RNDISPacketHeader, 0, sizeof(RNDIS_PACKET_MSG_t));
/* Construct the required packet header fields in the buffer */
RNDISPacketHeader.MessageType = REMOTE_NDIS_PACKET_MSG;
RNDISPacketHeader.MessageLength = (sizeof(RNDIS_PACKET_MSG_t) + FrameOUT.FrameLength);
RNDISPacketHeader.DataOffset = (sizeof(RNDIS_PACKET_MSG_t) - sizeof(RNDIS_Message_Header_t));
RNDISPacketHeader.DataLength = FrameOUT.FrameLength;
/* Send the packet header to the host */
Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t));
/* Send the Ethernet frame data to the host */
Endpoint_Write_Stream_LE(FrameOUT.FrameData, RNDISPacketHeader.DataLength);
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearCurrentBank();
/* Indicate Ethernet OUT buffer no longer full */
FrameOUT.FrameInBuffer = false;
}
}
}
/** Ethernet frame processing task. This task checks to see if a frame has been received, and if so hands off the processing
* of the frame to the Ethernet processing routines.
*/
TASK(Ethernet_Task)
{
/* Task for Ethernet processing. Incoming ethernet frames are loaded into the FrameIN structure, and
outgoing frames should be loaded into the FrameOUT structure. Both structures can only hold a single
Ethernet frame at a time, so the FrameInBuffer bool is used to indicate when the buffers contain data. */
/* Check if a frame has been written to the IN frame buffer */
if (FrameIN.FrameInBuffer)
{
/* Indicate packet processing started */
UpdateStatus(Status_ProcessingEthernetFrame);
/* Process the ethernet frame - replace this with your own Ethernet handler code as desired */
Ethernet_ProcessPacket();
/* Indicate packet processing complete */
UpdateStatus(Status_USBReady);
}
}

View file

@ -0,0 +1,109 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for RNDISEthernet.c.
*/
#ifndef _RNDISETHERNET_H_
#define _RNDISETHERNET_H_
/* Includes: */
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/pgmspace.h>
#include <avr/power.h>
#include <string.h>
#include <stdio.h>
#include "Descriptors.h"
#include "RNDIS.h"
#include "Ethernet.h"
#include "TCP.h"
#include "ARP.h"
#include "Webserver.h"
#include <LUFA/Version.h> // Library Version Information
#include <LUFA/Common/ButtLoadTag.h> // PROGMEM tags readable by the ButtLoad project
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
#include <LUFA/Drivers/AT90USBXXX/Serial_Stream.h>
/* Macros: */
/** Notification value to indicate that a frame is ready to be read by the host. */
#define NOTIF_RESPONSE_AVAILABLE 0x01
/* Event Handlers: */
/** Indicates that this module will catch the USB_Connect event when thrown by the library. */
HANDLES_EVENT(USB_Connect);
/** Indicates that this module will catch the USB_Disconnect event when thrown by the library. */
HANDLES_EVENT(USB_Disconnect);
/** Indicates that this module will catch the USB_ConfigurationChanged event when thrown by the library. */
HANDLES_EVENT(USB_ConfigurationChanged);
/** Indicates that this module will catch the USB_UnhandledControlPacket event when thrown by the library. */
HANDLES_EVENT(USB_UnhandledControlPacket);
/* Type Defines: */
/** Type define for a RNDIS notification message, for transmission to the RNDIS host via the notification
* Endpoint.
*/
typedef struct
{
uint8_t bmRequestType; /**< Notification type, a mask of values from SrdRequestType.h */
uint8_t bNotification; /**< Notification index, indicating what the RNDIS notification relates to */
uint16_t wValue; /**< Two byte notification value parameter */
uint16_t wIndex; /**< Two byte notification index parameter */
uint16_t wLength; /**< Size of data payload following the notification header */
} USB_Notification_t;
/* Enums: */
/** Enum for the possible status codes for passing to the UpdateStatus() function. */
enum RNDISEthernet_StatusCodes_t
{
Status_USBNotReady = 0, /**< USB is not ready (disconnected from a USB host) */
Status_USBEnumerating = 1, /**< USB interface is enumerating */
Status_USBReady = 2, /**< USB interface is connected and ready */
Status_ProcessingEthernetFrame = 3, /**< Currently processing an ethernet frame from the host */
};
/* Tasks: */
TASK(RNDIS_Task);
TASK(Ethernet_Task);
/* Function Prototypes: */
void UpdateStatus(uint8_t CurrentStatus);
#endif

View file

@ -0,0 +1,115 @@
/** \file
*
* This file contains special DoxyGen information for the generation of the main page and other special
* documentation pages. It is not a project source file.
*/
/** \mainpage RNDIS Class Ethernet Demo (with Webserver/Telnet)
*
* \section SSec_Info USB Information:
*
* The following table gives a rundown of the USB utilization of this demo.
*
* Remote Network Driver Interface demonstration application.
* This gives a simple reference application for implementing
* a CDC RNDIS device acting as a simple network interface for
* ethernet packet exchange. RNDIS is a proprietary Microsoft
* standard; this demo will only work on Windows 2000 (manually
* patched with the Microsoft RNDIS hotfix) and above (with no
* manual patches), or on the latest Linux kernels.
*
* Before running, you will need to install the INF file that
* is located in the RNDISEthernet project directory. This will
* enable Windows to use its inbuilt RNDIS drivers, negating the
* need for special Windows drivers for the device. To install,
* right-click the .INF file and choose the Install option. If
* Windows 2000 is used, the Microsoft INF file in the hotfix
* will need to be altered to use the VID/PID of the demo and
* then chosen instead of the LUFA RNDIS INF file when prompted.
*
* When enumerated, this demo will install as a new network
* adapter which ethernet packets can be sent to and received
* from. Running on top of the adapter is a very simple TCP/IP
* stack with a HTTP webserver and TELNET host which can be
* accessed through a web browser at IP address 10.0.0.2:80 or
* through a TELNET client at 10.0.0.2:25. This device also supports
* ping echos via the ICMP protocol.
*
* \note The TCP/IP stack in this demo has a number of limitations
* and should serve as an example only - it is not fully featured nor
* compliant to the TCP/IP specification. For complete projects, it is
* recommended that it be replaced with an external open source TCP/IP
* stack that is feature complete, such as the uIP stack.
*
* \section SSec_Description Project Description:
*
* <table>
* <tr>
* <td><b>USB Mode:</b></td>
* <td>Device</td>
* </tr>
* <tr>
* <td><b>USB Class:</b></td>
* <td>Communications Device Class (CDC)</td>
* </tr>
* <tr>
* <td><b>USB Subclass:</b></td>
* <td>Remote NDIS (Microsoft Proprietary CDC Class Networking Standard)</td>
* </tr>
* <tr>
* <td><b>Relevant Standards:</b></td>
* <td>Microsoft RNDIS Specification</td>
* </tr>
* <tr>
* <td><b>Usable Speeds:</b></td>
* <td>Full Speed Mode</td>
* </tr>
* </table>
*
* \section SSec_Options Project Options
*
* The following defines can be found in this demo, which can control the demo behaviour when defined, or changed in value.
*
* <table>
* <tr>
* <td><b>Define Name:</b></td>
* <td><b>Location:</b></td>
* <td><b>Description:</b></td>
* </tr>
* <tr>
* <td>NO_DECODE_ETHERNET</td>
* <td>Makefile CDEFS</td>
* <td>When defined, received Ethernet headers will not be decoded and printed to the device serial port.</td>
* </tr>
* <tr>
* <td>NO_DECODE_ARP</td>
* <td>Makefile CDEFS</td>
* <td>When defined, received ARP headers will not be decoded and printed to the device serial port.</td>
* </tr>
* <tr>
* <td>NO_DECODE_IP</td>
* <td>Makefile CDEFS</td>
* <td>When defined, received IP headers will not be decoded and printed to the device serial port.</td>
* </tr>
* <tr>
* <td>NO_DECODE_ICMP</td>
* <td>Makefile CDEFS</td>
* <td>When defined, received ICMP headers will not be decoded and printed to the device serial port.</td>
* </tr>
* <tr>
* <td>NO_DECODE_TCP</td>
* <td>Makefile CDEFS</td>
* <td>When defined, received TCP headers will not be decoded and printed to the device serial port.</td>
* </tr>
* <tr>
* <td>NO_DECODE_UDP</td>
* <td>Makefile CDEFS</td>
* <td>When defined, received UDP headers will not be decoded and printed to the device serial port.</td>
* </tr>
* <tr>
* <td>NO_DECODE_DHCP</td>
* <td>Makefile CDEFS</td>
* <td>When defined, received DHCP headers will not be decoded and printed to the device serial port.</td>
* </tr>
* </table>
*/

View file

@ -0,0 +1,614 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* 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"
/* Global Variables: */
/** 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.
*/
TASK(TCP_Task)
{
/* Task to hand off TCP packets to and from the listening applications. */
/* Run each application in sequence, to process incomming 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_TCP_CONNECTIONS; 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.FrameInBuffer)
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;
FrameOUT.FrameInBuffer = true;
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 Port Port whose state and callback function to set, specified in big endian
* \param State New state of the port, a value from the TCP_PortStates_t enum
* \param Handler Application callback handler for the port
*
* \return Boolean true if the port state was set, false otherwise (no more space in the port state table)
*/
bool TCP_SetPortState(uint16_t Port, uint8_t State, void (*Handler)(TCP_ConnectionState_t*, TCP_ConnectionBuffer_t*))
{
/* Note, Port number should be specified in BIG endian to simplfy network code */
/* Check to see if the port entry is already in the port state table */
for (uint8_t PTableEntry = 0; PTableEntry < MAX_TCP_CONNECTIONS; 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_TCP_CONNECTIONS; 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 Port TCP port whose state is to be retrieved, given in big-endian
*
* \return A value from the TCP_PortStates_t enum
*/
uint8_t TCP_GetPortState(uint16_t Port)
{
/* Note, Port number should be specified in BIG endian to simplfy network code */
for (uint8_t PTableEntry = 0; PTableEntry < MAX_TCP_CONNECTIONS; 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 Port TCP port of the connection on the device, specified in big endian
* \param RemoteAddress Remote protocol IP address of the connected device
* \param RemotePort TCP port of the remote device in the connection, specified in big endian
* \param State TCP connection state, a value from the TCP_ConnectionStates_t enum
*
* \return Boolean true if the connection was updated or created, false otherwise (no more space in the connection state table)
*/
bool TCP_SetConnectionState(uint16_t Port, IP_Address_t RemoteAddress, uint16_t RemotePort, uint8_t State)
{
/* Note, Port number should be specified in BIG endian to simplfy 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 Port TCP port on the device in the connection, specified in big endian
* \param RemoteAddress Remote protocol IP address of the connected host
* \param RemotePort Remote TCP port of the connected host, specified in big endian
*
* \return A value from the TCP_ConnectionStates_t enum
*/
uint8_t TCP_GetConnectionState(uint16_t Port, IP_Address_t RemoteAddress, uint16_t RemotePort)
{
/* Note, Port number should be specified in BIG endian to simplfy 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 Port TCP port on the device in the connection, specified in big endian
* \param RemoteAddress Remote protocol IP address of the connected host
* \param 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(uint16_t Port, IP_Address_t RemoteAddress, uint16_t RemotePort)
{
/* Note, Port number should be specified in BIG endian to simplfy 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 IPHeaderInStart Pointer to the start of the incomming packet's IP header
* \param TCPHeaderInStart Pointer to the start of the incomming packet's TCP header
* \param 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 incomming 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)
{
TCPHeaderOUT->Flags = (TCP_FLAG_RST | TCP_FLAG_ACK);
PacketResponse = true;
TCP_SetConnectionState(TCPHeaderIN->DestinationPort, IPHeaderIN->SourceAddress,
TCPHeaderIN->SourcePort, TCP_Connection_Closed);
}
else
{
/* Process the incomming 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 when closed starts a connection with a peer */
TCPHeaderOUT->Flags = (TCP_FLAG_SYN | TCP_FLAG_ACK);
PacketResponse = true;
TCP_SetConnectionState(TCPHeaderIN->DestinationPort, IPHeaderIN->SourceAddress, TCPHeaderIN->SourcePort,
TCP_Connection_SYNReceived);
ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, IPHeaderIN->SourceAddress, TCPHeaderIN->SourcePort);
ConnectionInfo->SequenceNumberIn = (SwapEndian_32(TCPHeaderIN->SequenceNumber) + 1);
ConnectionInfo->SequenceNumberOut = 0;
ConnectionInfo->Buffer.InUse = false;
}
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 incomming 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 TCPHeaderOutStart Pointer to the start of the packet's outgoing TCP header
* \param SourceAddress Source protocol IP address of the outgoing IP header
* \param SourceAddress DestinationAddress protocol IP address of the outgoing IP header
* \param 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, IP_Address_t SourceAddress,
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 psudo-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 (uint8_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,253 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for TCP.c.
*/
#ifndef _TCP_H_
#define _TCP_H_
/* Includes: */
#include <avr/io.h>
#include <stdbool.h>
#include <LUFA/Scheduler/Scheduler.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 1
/** TCP window size, giving the maximum number of bytes which can be buffered at the one time */
#define TCP_WINDOW_SIZE 1024
/** 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 Buffer Application buffer to check
*
* \return Boolean true if the buffer contains a packet from the host, 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 Buffer Application buffer to check
*
* \return Boolean true if the buffer has been captured by the application for device-to-host transmissions, 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 Buffer Application buffer to check
*
* \return Boolean true if the buffer may be captured by the application for device-to-host transmissions, 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.
*
* \note The application must check that the buffer can be locked first using TCP_APP_CAN_CAPTURE_BUFFER().
*
* \param Buffer Application buffer to lock
*/
#define TCP_APP_CAPTURE_BUFFER(Buffer) MACROS{ Buffer->Direction = TCP_PACKETDIR_OUT; Buffer->InUse = true; }MACROE
/** Application macro: Releases a captured application buffer, allowing for host-to-device packets to be received.
*
* \param Buffer Application buffer to release
*/
#define TCP_APP_RELEASE_BUFFER(Buffer) MACROS{ Buffer->InUse = false; }MACROE
/** Application macro: Sends the contents of the given application buffer to the host.
*
* \param Buffer Application buffer to send
* \param Len Length of data contained in the buffer
*/
#define TCP_APP_SEND_BUFFER(Buffer, Len) MACROS{ Buffer->Direction = TCP_PACKETDIR_OUT; Buffer->Length = Len; Buffer->Ready = true; }MACROE
/** Application macro: Clears the application buffer, ready for a packet to be written to it.
*
* \param Buffer Application buffer to clear
*/
#define TCP_APP_CLEAR_BUFFER(Buffer) MACROS{ Buffer->Ready = false; Buffer->Length = 0; }MACROE
/** Application macro: Closes an open connection to a host.
*
* \param Connection Open TCP connection to close
*/
#define TCP_APP_CLOSECONNECTION(Connection) MACROS{ Connection->State = TCP_Connection_Closing; }MACROE
/* 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 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 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 int Reserved : 4; /**< Reserved, must be all 0 */
unsigned int 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 remaning in reception buffer) */
uint16_t Checksum; /**< TCP checksum */
uint16_t UrgentPointer; /**< Urgent data pointer */
} TCP_Header_t;
/* Tasks: */
TASK(TCP_Task);
/* External Variables: */
TCP_PortState_t PortStateTable[MAX_OPEN_TCP_PORTS];
/* Function Prototypes: */
void TCP_Init(void);
bool TCP_SetPortState(uint16_t Port, uint8_t State, void (*Handler)(TCP_ConnectionState_t*, TCP_ConnectionBuffer_t*));
uint8_t TCP_GetPortState(uint16_t Port);
bool TCP_SetConnectionState(uint16_t Port, IP_Address_t RemoteAddress, uint16_t RemotePort, uint8_t State);
uint8_t TCP_GetConnectionState(uint16_t Port, IP_Address_t RemoteAddress, uint16_t RemotePort);
TCP_ConnectionInfo_t* TCP_GetConnectionInfo(uint16_t Port, IP_Address_t RemoteAddress, 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, IP_Address_t SourceAddress,
IP_Address_t DestinationAddress, uint16_t TCPOutSize);
#endif
#endif

View file

@ -0,0 +1,80 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* 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 subprotocol handler has created a response packet.
*
* \param IPHeaderInStart Pointer to the start of the incomming packet's IP header
* \param UDPHeaderInStart Pointer to the start of the incomming packet's UDP header
* \param 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);
/* Check to see if the UDP packet is a DHCP packet */
if (SwapEndian_16(UDPHeaderIN->DestinationPort) == UDP_PORT_DHCP_REQUEST)
{
RetSize = DHCP_ProcessDHCPPacket(IPHeaderInStart,
&((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],
&((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);
}
/* 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,66 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for IP.c.
*/
#ifndef _UDP_H_
#define _UDP_H_
/* Includes: */
#include <avr/io.h>
#include "EthernetProtocols.h"
#include "Ethernet.h"
#include "ProtocolDecoders.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,162 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Simple webserver application for demonstrating the RNDIS demo and TCP/IP stack. This
* application will serve up a static HTTP webpage 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.
*/
char PROGMEM HTTPHeader[] = "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 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.
*/
char PROGMEM HTTPPage[] =
"<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.fourwalledcubicle.com/LUFA.php\">http://www.fourwalledcubicle.com/LUFA.php</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 RequestHeader HTTP request made by the host
* \param Command HTTP command to compare the request to
*
* \return Boolean true if the command matches the request, 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 ConnectionState Pointer to a TCP Connection State structure giving connection information
* \param Buffer Pointer to the application's send/receive packet buffer
*/
void Webserver_ApplicationCallback(TCP_ConnectionState_t* ConnectionState, TCP_ConnectionBuffer_t* 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"))
{
PageBlock = 0;
/* Copy the HTTP response header into the packet buffer */
strcpy_P(BufferDataStr, HTTPHeader);
/* 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 if (IsHTTPCommand(Buffer->Data, "HEAD"))
{
/* Copy the HTTP response header into the packet buffer */
strcpy_P(BufferDataStr, HTTPHeader);
/* Send the buffer contents to the host */
TCP_APP_SEND_BUFFER(Buffer, strlen(BufferDataStr));
}
else if (IsHTTPCommand(Buffer->Data, "TRACE"))
{
/* Echo the host's query back to the host */
TCP_APP_SEND_BUFFER(Buffer, Buffer->Length);
}
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,55 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for 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* ConnectionState, TCP_ConnectionBuffer_t* Buffer);
#endif

View file

@ -0,0 +1,743 @@
# Hey Emacs, this is a -*- makefile -*-
#----------------------------------------------------------------------------
# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
# >> Modified for use with the LUFA project. <<
#
# Released to the Public Domain
#
# Additional material for this makefile was written by:
# Peter Fleury
# Tim Henigan
# Colin O'Flynn
# Reiner Patommel
# Markus Pfaff
# Sander Pool
# Frederik Rouleau
# Carlos Lamas
# Dean Camera
# Opendous Inc.
# Denver Gingerich
#
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device, using avrdude.
# Please customize the avrdude settings below first!
#
# make dfu = Download the hex file to the device, using dfu-programmer (must
# have dfu-programmer installed).
#
# make flip = Download the hex file to the device, using Atmel FLIP (must
# have Atmel FLIP installed).
#
# make dfu-ee = Download the eeprom file to the device, using dfu-programmer
# (must have dfu-programmer installed).
#
# make flip-ee = Download the eeprom file to the device, using Atmel FLIP
# (must have Atmel FLIP installed).
#
# make doxygen = Generate DoxyGen documentation for the project (must have
# DoxyGen installed)
#
# make debug = Start either simulavr or avarice as specified for debugging,
# with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
# bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------
# MCU name
MCU = at90usb1287
# Target board (see library BoardTypes.h documentation, USER or blank for projects not requiring
# LUFA board drivers). If USER is selected, put custom board drivers in a directory called
# "Board" inside the application directory.
BOARD = USBKEY
# Processor frequency.
# This will define a symbol, F_CPU, in all source code files equal to the
# processor frequency. You can then use this symbol in your source code to
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
# automatically to create a 32-bit value in your source code.
# Typical values are:
# F_CPU = 1000000
# F_CPU = 1843200
# F_CPU = 2000000
# F_CPU = 3686400
# F_CPU = 4000000
# F_CPU = 7372800
# F_CPU = 8000000
# F_CPU = 11059200
# F_CPU = 14745600
# F_CPU = 16000000
# F_CPU = 18432000
# F_CPU = 20000000
F_CPU = 8000000
# Input clock frequency.
# This will define a symbol, F_CLOCK, in all source code files equal to the
# input clock frequency (before any prescaling is performed). This value may
# differ from F_CPU if prescaling is used on the latter, and is required as the
# raw input clock is fed directly to the PLL sections of the AVR for high speed
# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
# at the end, this will be done automatically to create a 32-bit value in your
# source code.
#
# If no clock division is performed on the input clock inside the AVR (via the
# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
F_CLOCK = 8000000
# Output format. (can be srec, ihex, binary)
FORMAT = ihex
# Target file name (without extension).
TARGET = RNDISEthernet
# Object files directory
# To put object files in current directory, use a dot (.), do NOT make
# this an empty or blank macro!
OBJDIR = .
# Path to the LUFA library
LUFA_PATH = ../../..
# List C source files here. (C dependencies are automatically generated.)
SRC = $(TARGET).c \
Descriptors.c \
RNDIS.c \
Ethernet.c \
ProtocolDecoders.c \
ICMP.c \
TCP.c \
UDP.c \
DHCP.c \
ARP.c \
IP.c \
Webserver.c \
$(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/LowLevel.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/Events.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/StdDescriptors.c \
$(LUFA_PATH)/LUFA/Drivers/AT90USBXXX/Serial_Stream.c \
$(LUFA_PATH)/LUFA/Drivers/AT90USBXXX/Serial.c \
# List C++ source files here. (C dependencies are automatically generated.)
CPPSRC =
# List Assembler source files here.
# Make them always end in a capital .S. Files ending in a lowercase .s
# will not be considered source files but generated files (assembler
# output from the compiler), and will be deleted upon "make clean"!
# Even though the DOS/Win* filesystem matches both .s and .S the same,
# it will preserve the spelling of the filenames, and gcc itself does
# care about how the name is spelled on its command-line.
ASRC =
# Optimization level, can be [0, 1, 2, 3, s].
# 0 = turn off optimization. s = optimize for size.
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
OPT = s
# Debugging format.
# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
# AVR Studio 4.10 requires dwarf-2.
# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
DEBUG = dwarf-2
# List any extra directories to look for include files here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRAINCDIRS = $(LUFA_PATH)/
# Compiler flag to set the C Standard level.
# c89 = "ANSI" C
# gnu89 = c89 plus GCC extensions
# c99 = ISO C99 standard (not yet fully implemented)
# gnu99 = c99 plus GCC extensions
CSTANDARD = -std=gnu99
# Place -D or -U options here for C sources
CDEFS = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD)
CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS -DUSB_DEVICE_ONLY
CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
CDEFS += -DNO_DECODE_ETHERNET -DNO_DECODE_ARP -DNO_DECODE_ICMP -DNO_DECODE_IP -DNO_DECODE_TCP -DNO_DECODE_UDP -DNO_DECODE_DHCP
# Place -D or -U options here for ASM sources
ADEFS = -DF_CPU=$(F_CPU)
# Place -D or -U options here for C++ sources
CPPDEFS = -DF_CPU=$(F_CPU)UL
#CPPDEFS += -D__STDC_LIMIT_MACROS
#CPPDEFS += -D__STDC_CONSTANT_MACROS
#---------------- Compiler Options C ----------------
# -g*: generate debugging information
# -O*: optimization level
# -f...: tuning, see GCC manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns...: create assembler listing
CFLAGS = -g$(DEBUG)
CFLAGS += $(CDEFS)
CFLAGS += -O$(OPT)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -ffunction-sections
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -finline-limit=20
CFLAGS += -Wall
CFLAGS += -Wstrict-prototypes
CFLAGS += -Wundef
#CFLAGS += -fno-unit-at-a-time
#CFLAGS += -Wunreachable-code
#CFLAGS += -Wsign-compare
CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst)
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
CFLAGS += $(CSTANDARD)
#---------------- Compiler Options C++ ----------------
# -g*: generate debugging information
# -O*: optimization level
# -f...: tuning, see GCC manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns...: create assembler listing
CPPFLAGS = -g$(DEBUG)
CPPFLAGS += $(CPPDEFS)
CPPFLAGS += -O$(OPT)
CPPFLAGS += -funsigned-char
CPPFLAGS += -funsigned-bitfields
CPPFLAGS += -fpack-struct
CPPFLAGS += -fshort-enums
CPPFLAGS += -fno-exceptions
CPPFLAGS += -Wall
CFLAGS += -Wundef
#CPPFLAGS += -mshort-calls
#CPPFLAGS += -fno-unit-at-a-time
#CPPFLAGS += -Wstrict-prototypes
#CPPFLAGS += -Wunreachable-code
#CPPFLAGS += -Wsign-compare
CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)
CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
#CPPFLAGS += $(CSTANDARD)
#---------------- Assembler Options ----------------
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns: create listing
# -gstabs: have the assembler create line number information; note that
# for use in COFF files, additional information about filenames
# and function names needs to be present in the assembler source
# files -- see avr-libc docs [FIXME: not yet described there]
# -listing-cont-lines: Sets the maximum number of continuation lines of hex
# dump that will be displayed for a given single line of source input.
ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100
#---------------- Library Options ----------------
# Minimalistic printf version
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
# Floating point printf version (requires MATH_LIB = -lm below)
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
# If this is left blank, then it will use the Standard printf version.
PRINTF_LIB =
#PRINTF_LIB = $(PRINTF_LIB_MIN)
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
# Minimalistic scanf version
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
# If this is left blank, then it will use the Standard scanf version.
SCANF_LIB =
#SCANF_LIB = $(SCANF_LIB_MIN)
#SCANF_LIB = $(SCANF_LIB_FLOAT)
MATH_LIB = -lm
# List any extra directories to look for libraries here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRALIBDIRS =
#---------------- External Memory Options ----------------
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# used for variables (.data/.bss) and heap (malloc()).
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# only used for heap (malloc()).
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
EXTMEMOPTS =
#---------------- Linker Options ----------------
# -Wl,...: tell GCC to pass this to linker.
# -Map: create map file
# --cref: add cross reference to map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
LDFLAGS += -Wl,--relax
LDFLAGS += -Wl,--gc-sections
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
#LDFLAGS += -T linker_script.x
#---------------- Programming Options (avrdude) ----------------
# Programming hardware: alf avr910 avrisp bascom bsd
# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500
#
# Type: avrdude -c ?
# to get a full listing.
#
AVRDUDE_PROGRAMMER = jtagmkII
# com1 = serial port. Use lpt1 to connect to parallel port.
AVRDUDE_PORT = usb
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
# Uncomment the following if you want avrdude's erase cycle counter.
# Note that this counter needs to be initialized first using -Yn,
# see avrdude manual.
#AVRDUDE_ERASE_COUNTER = -y
# Uncomment the following if you do /not/ wish a verification to be
# performed after programming the device.
#AVRDUDE_NO_VERIFY = -V
# Increase verbosity level. Please use this when submitting bug
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
# to submit bug reports.
#AVRDUDE_VERBOSE = -v -v
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
#---------------- Debugging Options ----------------
# For simulavr only - target MCU frequency.
DEBUG_MFREQ = $(F_CPU)
# Set the DEBUG_UI to either gdb or insight.
# DEBUG_UI = gdb
DEBUG_UI = insight
# Set the debugging back-end to either avarice, simulavr.
DEBUG_BACKEND = avarice
#DEBUG_BACKEND = simulavr
# GDB Init Filename.
GDBINIT_FILE = __avr_gdbinit
# When using avarice settings for the JTAG
JTAG_DEV = /dev/com1
# Debugging port used to communicate between GDB / avarice / simulavr.
DEBUG_PORT = 4242
# Debugging host used to communicate between GDB / avarice / simulavr, normally
# just set to localhost unless doing some sort of crazy debugging when
# avarice is running on a different computer.
DEBUG_HOST = localhost
#============================================================================
# Define programs and commands.
SHELL = sh
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
AR = avr-ar rcs
NM = avr-nm
AVRDUDE = avrdude
REMOVE = rm -f
REMOVEDIR = rm -rf
COPY = cp
WINSHELL = cmd
# Define Messages
# English
MSG_ERRORS_NONE = Errors: none
MSG_BEGIN = -------- begin --------
MSG_END = -------- end --------
MSG_SIZE_BEFORE = Size before:
MSG_SIZE_AFTER = Size after:
MSG_COFF = Converting to AVR COFF:
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
MSG_FLASH = Creating load file for Flash:
MSG_EEPROM = Creating load file for EEPROM:
MSG_EXTENDED_LISTING = Creating Extended Listing:
MSG_SYMBOL_TABLE = Creating Symbol Table:
MSG_LINKING = Linking:
MSG_COMPILING = Compiling C:
MSG_COMPILING_CPP = Compiling C++:
MSG_ASSEMBLING = Assembling:
MSG_CLEANING = Cleaning project:
MSG_CREATING_LIBRARY = Creating library:
# Define all object files.
OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)
# Define all listing files.
LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)
# Compiler flags to generate dependency files.
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
# Default target.
all: begin gccversion sizebefore build checkhooks checklibmode checkboard sizeafter end
# Change the build target to build a HEX file or a library.
build: elf hex eep lss sym
#build: lib
elf: $(TARGET).elf
hex: $(TARGET).hex
eep: $(TARGET).eep
lss: $(TARGET).lss
sym: $(TARGET).sym
LIBNAME=lib$(TARGET).a
lib: $(LIBNAME)
# Eye candy.
# AVR Studio 3.x does not check make's exit code but relies on
# the following magic strings to be generated by the compile job.
begin:
@echo
@echo $(MSG_BEGIN)
end:
@echo $(MSG_END)
@echo
# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
ELFSIZE = $(SIZE) $(MCU_FLAG) $(FORMAT_FLAG) $(TARGET).elf
MCU_FLAG = $(shell $(SIZE) --help | grep -- --mcu > /dev/null && echo --mcu=$(MCU) )
FORMAT_FLAG = $(shell $(SIZE) --help | grep -- --format=.*avr > /dev/null && echo --format=avr )
sizebefore:
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
2>/dev/null; echo; fi
sizeafter:
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
2>/dev/null; echo; fi
checkhooks: build
@echo
@echo ------- Unhooked LUFA Events -------
@$(shell) (grep -s '^Event.*LUFA/.*\\.o' $(TARGET).map | \
cut -d' ' -f1 | cut -d'_' -f2- | grep ".*") || \
echo "(None)"
@echo ------------------------------------
checklibmode:
@echo
@echo ----------- Library Mode -----------
@$(shell) ($(CC) $(ALL_CFLAGS) -E -dM - < /dev/null \
| grep 'USB_\(DEVICE\|HOST\)_ONLY' | cut -d' ' -f2 | grep ".*") \
|| echo "No specific mode (both device and host mode allowable)."
@echo ------------------------------------
checkboard:
@echo
@echo ---------- Selected Board ----------
@echo Selected board model is $(BOARD).
@echo ------------------------------------
# Display compiler version information.
gccversion :
@$(CC) --version
# Program the device.
program: $(TARGET).hex $(TARGET).eep
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
flip: $(TARGET).hex
batchisp -hardware usb -device $(MCU) -operation erase f
batchisp -hardware usb -device $(MCU) -operation loadbuffer $(TARGET).hex program
batchisp -hardware usb -device $(MCU) -operation start reset 0
dfu: $(TARGET).hex
dfu-programmer $(MCU) erase
dfu-programmer $(MCU) flash --debug 1 $(TARGET).hex
dfu-programmer $(MCU) reset
flip-ee: $(TARGET).hex $(TARGET).eep
copy $(TARGET).eep $(TARGET)eep.hex
batchisp -hardware usb -device $(MCU) -operation memory EEPROM erase
batchisp -hardware usb -device $(MCU) -operation memory EEPROM loadbuffer $(TARGET)eep.hex program
batchisp -hardware usb -device $(MCU) -operation start reset 0
dfu-ee: $(TARGET).hex $(TARGET).eep
dfu-programmer $(MCU) flash-eeprom --debug 1 --suppress-bootloader-mem $(TARGET).eep
dfu-programmer $(MCU) reset
# Generate avr-gdb config/init file which does the following:
# define the reset signal, load the target file, connect to target, and set
# a breakpoint at main().
gdb-config:
@$(REMOVE) $(GDBINIT_FILE)
@echo define reset >> $(GDBINIT_FILE)
@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
@echo end >> $(GDBINIT_FILE)
@echo file $(TARGET).elf >> $(GDBINIT_FILE)
@echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
ifeq ($(DEBUG_BACKEND),simulavr)
@echo load >> $(GDBINIT_FILE)
endif
@echo break main >> $(GDBINIT_FILE)
debug: gdb-config $(TARGET).elf
ifeq ($(DEBUG_BACKEND), avarice)
@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
@$(WINSHELL) /c pause
else
@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
$(DEBUG_MFREQ) --port $(DEBUG_PORT)
endif
@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT = $(OBJCOPY) --debugging
COFFCONVERT += --change-section-address .data-0x800000
COFFCONVERT += --change-section-address .bss-0x800000
COFFCONVERT += --change-section-address .noinit-0x800000
COFFCONVERT += --change-section-address .eeprom-0x810000
coff: $(TARGET).elf
@echo
@echo $(MSG_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
extcoff: $(TARGET).elf
@echo
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
# Create final output files (.hex, .eep) from ELF output file.
%.hex: %.elf
@echo
@echo $(MSG_FLASH) $@
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
%.eep: %.elf
@echo
@echo $(MSG_EEPROM) $@
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
# Create extended listing file from ELF output file.
%.lss: %.elf
@echo
@echo $(MSG_EXTENDED_LISTING) $@
$(OBJDUMP) -h -z -S $< > $@
# Create a symbol table from ELF output file.
%.sym: %.elf
@echo
@echo $(MSG_SYMBOL_TABLE) $@
$(NM) -n $< > $@
# Create library from object files.
.SECONDARY : $(TARGET).a
.PRECIOUS : $(OBJ)
%.a: $(OBJ)
@echo
@echo $(MSG_CREATING_LIBRARY) $@
$(AR) $@ $(OBJ)
# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
%.elf: $(OBJ)
@echo
@echo $(MSG_LINKING) $@
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
# Compile: create object files from C source files.
$(OBJDIR)/%.o : %.c
@echo
@echo $(MSG_COMPILING) $<
$(CC) -c $(ALL_CFLAGS) $< -o $@
# Compile: create object files from C++ source files.
$(OBJDIR)/%.o : %.cpp
@echo
@echo $(MSG_COMPILING_CPP) $<
$(CC) -c $(ALL_CPPFLAGS) $< -o $@
# Compile: create assembler files from C source files.
%.s : %.c
$(CC) -S $(ALL_CFLAGS) $< -o $@
# Compile: create assembler files from C++ source files.
%.s : %.cpp
$(CC) -S $(ALL_CPPFLAGS) $< -o $@
# Assemble: create object files from assembler source files.
$(OBJDIR)/%.o : %.S
@echo
@echo $(MSG_ASSEMBLING) $<
$(CC) -c $(ALL_ASFLAGS) $< -o $@
# Create preprocessed source for use in sending a bug report.
%.i : %.c
$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
# Target: clean project.
clean: begin clean_list clean_binary end
clean_binary:
$(REMOVE) $(TARGET).hex
clean_list:
@echo $(MSG_CLEANING)
$(REMOVE) $(TARGET).eep
$(REMOVE) $(TARGET)eep.hex
$(REMOVE) $(TARGET).cof
$(REMOVE) $(TARGET).elf
$(REMOVE) $(TARGET).map
$(REMOVE) $(TARGET).sym
$(REMOVE) $(TARGET).lss
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o)
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst)
$(REMOVE) $(SRC:.c=.s)
$(REMOVE) $(SRC:.c=.d)
$(REMOVE) $(SRC:.c=.i)
$(REMOVEDIR) .dep
doxygen:
@echo Generating Project Documentation...
@doxygen Doxygen.conf
@echo Documentation Generation Complete.
clean_doxygen:
rm -rf Documentation
# Create object files directory
$(shell mkdir $(OBJDIR) 2>/dev/null)
# Include the dependency files.
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
# Listing of phony targets.
.PHONY : all checkhooks checklibmode checkboard \
begin finish end sizebefore sizeafter gccversion \
build elf hex eep lss sym coff extcoff clean \
clean_list clean_binary program debug gdb-config \
doxygen dfu flip flip-ee dfu-ee