Ok, this code was written without having an arduino around to test it on.
Do you mind testing it? Can you put the output here and whether it worked? (remember to set the baud rate)
#include <Ethernet.h>
#include <UdpRaw.h>
#define zap(x) if(x){free(x); x=0;}
//Constants
byte mac[] = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC };
byte ip[] = { 192, 168, 3, 1 };
byte highIP[] = { 255, 255, 255, 255 };
byte zeroIP[] = { 0, 0, 0, 0 };
byte broadcastIP[] = { 255, 255, 255, 255 };
byte subnet[] = { 255, 255, 255, 0 };
#define serverName "My DHCP Server"
byte myDomainName[] = "MSHOME";
/* UDP port numbers for DHCP */
#define DHCP_SERVER_PORT 67 /* from server to client */
#define DHCP_CLIENT_PORT 68 /* from client to server */
/* DHCP message OP code */
#define DHCP_BOOTREQUEST 1
#define DHCP_BOOTREPLY 2
/* DHCP message type */
#define DHCP_DISCOVER 1
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_DECLINE 4
#define DHCP_ACK 5
#define DHCP_NAK 6
#define DHCP_RELEASE 7
#define DHCP_INFORM 8
/**
* @brief DHCP option and value (cf. RFC1533)
*/
enum
{
padOption = 0,
subnetMask = 1,
timerOffset = 2,
routersOnSubnet = 3,
timeServer = 4,
nameServer = 5,
dns = 6,
logServer = 7,
cookieServer = 8,
lprServer = 9,
impressServer = 10,
resourceLocationServer = 11,
hostName = 12,
bootFileSize = 13,
meritDumpFile = 14,
domainName = 15,
swapServer = 16,
rootPath = 17,
extentionsPath = 18,
IPforwarding = 19,
nonLocalSourceRouting = 20,
policyFilter = 21,
maxDgramReasmSize = 22,
defaultIPTTL = 23,
pathMTUagingTimeout = 24,
pathMTUplateauTable = 25,
ifMTU = 26,
allSubnetsLocal = 27,
broadcastAddr = 28,
performMaskDiscovery = 29,
maskSupplier = 30,
performRouterDiscovery = 31,
routerSolicitationAddr = 32,
staticRoute = 33,
trailerEncapsulation = 34,
arpCacheTimeout = 35,
ethernetEncapsulation = 36,
tcpDefaultTTL = 37,
tcpKeepaliveInterval = 38,
tcpKeepaliveGarbage = 39,
nisDomainName = 40,
nisServers = 41,
ntpServers = 42,
vendorSpecificInfo = 43,
netBIOSnameServer = 44,
netBIOSdgramDistServer = 45,
netBIOSnodeType = 46,
netBIOSscope = 47,
xFontServer = 48,
xDisplayManager = 49,
dhcpRequestedIPaddr = 50,
dhcpIPaddrLeaseTime = 51,
dhcpOptionOverload = 52,
dhcpMessageType = 53,
dhcpServerIdentifier = 54,
dhcpParamRequest = 55,
dhcpMsg = 56,
dhcpMaxMsgSize = 57,
dhcpT1value = 58,
dhcpT2value = 59,
dhcpClassIdentifier = 60,
dhcpClientIdentifier = 61,
endOption = 255
};
/**
* @brief for the DHCP message
*/
typedef struct RIP_MSG
{
byte op;
byte htype;
byte hlen;
byte hops;
u_long xid;
u_int secs;
u_int flags;
byte ciaddr[4];
byte yiaddr[4];
byte siaddr[4];
byte giaddr[4];
byte chaddr[16];
byte sname[64];
byte file[128];
byte OPT[];
};
byte *GetOption(int dhcpOption, byte *options, int optionSize, int *optionLength)
{
for(int i=0;i<optionSize;i++)
{
if(options[i] == dhcpOption)
{
int test;
*optionLength = (int)options[i+1];
byte *option = (byte *)malloc(sizeof(byte)**optionLength);
memcpy(option,(byte *)options[i+2],*optionLength);
return option;
}
if(options[i] == endOption)
{
optionLength = 0;
return NULL;
}
i += 1 + options[i+1];
}
optionLength = 0;
return NULL;
}
// this function will return the number of bytes currently free in RAM
int memoryTest() {
int byteCounter = 0; // initialize a counter
byte *byteArray; // create a pointer to a byte array
// More on pointers here: http://en.wikipedia.org/wiki/Pointer#C_pointers
// use the malloc function to repeatedly attempt
// allocating a certain number of bytes to memory
// More on malloc here: http://en.wikipedia.org/wiki/Malloc
while ( (byteArray = (byte*) malloc (byteCounter * sizeof(byte))) != NULL ) {
byteCounter++; // if allocation was successful, then up the count for the next try
free(byteArray); // free memory after allocating it
}
free(byteArray); // also free memory after the function finishes
return byteCounter; // send back the highest number of bytes successfully allocated
}
void setup()
{
Serial.begin(38400);
Serial.print("Memory before starting server: ");
Serial.print(memoryTest(), DEC);
Ethernet.begin(mac,ip);
UdpRaw.begin(DHCP_SERVER_PORT);
Serial.print("Memory after starting server: ");
Serial.print(memoryTest(), DEC);
}
void loop()
{
if(UdpRaw.available())
{
int startMem = 0; // Make sure it's initialized
int endMem = 0;
startMem = memoryTest();
//Get packet size and allocate size of packet
int packetSize = UdpRaw.available()-8;
RIP_MSG *packet = (RIP_MSG *)malloc(sizeof(byte)*packetSize);
UdpRaw.readPacket((byte *)packet,packetSize);
packet->op = DHCP_BOOTREPLY;
strcpy((char *)packet->sname, serverName);
int currLoc = 4; //Start at four because of magic cookie
int reqLength; byte *reqList = GetOption(dhcpParamRequest, packet->OPT, packetSize-240,&reqLength);
byte *dhcpMessage = GetOption(dhcpMessageType, packet->OPT, packetSize-240,NULL);
packet->OPT[currLoc++] = dhcpMessageType;
if(dhcpMessage[0] == DHCP_DISCOVER) packet->OPT[currLoc++] = DHCP_OFFER;
else if(dhcpMessage[0] == DHCP_REQUEST) packet->OPT[currLoc++] = DHCP_ACK;
else packet->OPT[currLoc++] = DHCP_NAK;
for(int i=0;i<reqLength;i++)
{
switch(reqList[i])
{
case subnetMask:
packet->OPT[currLoc++] = reqList[i];
packet->OPT[currLoc++] = 4;
memcpy((byte *)packet->OPT[currLoc],subnet,4);
currLoc+=4;
break;
case routersOnSubnet:
case dns:
case logServer:
packet->OPT[currLoc++] = reqList[i];
packet->OPT[currLoc++] = 4;
memcpy((byte *)packet->OPT[currLoc],zeroIP,4);
currLoc += 4;
break;
case domainName:
packet->OPT[currLoc++] = reqList[i];
packet->OPT[currLoc++] = sizeof(myDomainName);
memcpy((byte *)packet->OPT[currLoc], myDomainName, sizeof(myDomainName));
currLoc += sizeof(myDomainName);
break;
case dhcpServerIdentifier:
packet->OPT[currLoc++] = reqList[i];
packet->OPT[currLoc++] = 4;
memcpy((byte *)packet->OPT[currLoc], ip, 4);
currLoc += 4;
break;
}
}
packet->OPT[currLoc++] = dhcpIPaddrLeaseTime;
packet->OPT[currLoc++] = 4;
memcpy((byte *)packet->OPT[currLoc],highIP,4);
currLoc += 4;
packet->OPT[currLoc++] = dhcpT1value;
packet->OPT[currLoc++] = 4;
memcpy((byte *)packet->OPT[currLoc],highIP,4);
currLoc += 4;
packet->OPT[currLoc++] = dhcpT2value;
packet->OPT[currLoc++] = 4;
memcpy((byte *)packet->OPT[currLoc],highIP,4);
currLoc += 4;
packet->OPT[currLoc++] = endOption;
//TODO: Dynamic IP configuration
byte targetIP[] = { 192, 168, 3, 11 };
memcpy(packet->yiaddr, targetIP, 4);
//Send Packet
UdpRaw.sendPacket((byte *)packet,240+currLoc,broadcastIP,DHCP_CLIENT_PORT);
//Disposal code
zap(packet);
zap(dhcpMessage);
zap(reqList);
endMem = memoryTest();
Serial.print("Memory leaked ");
Serial.print(endMem-startMem, DEC);
Serial.println(" bytes");
}
}
Cheers,
Nebster