Welcome, Guest. Please Login or Register
YaBB - Yet another Bulletin Board
09.02.2010 at 18:53:28
News: Server upgrade went fine, you are now at the new system


Pages: 1 2 3 4
DNS and DHCP Support with Ethernet Library (Read 12032 times)
smartperson
YaBB Newbies
*
Offline

Arduino minerals

Posts: 9
California
Gender: male
DNS and DHCP Support with Ethernet Library
09.04.2009 at 07:32:09
 
Hey guys, I'm really sorry if there's already a topic on this matter, but I couldn't find one by searching and the subject is near and dear to my heart.

Against my better judgement, I'm looking at trying to add DNS and DHCP (maybe) support to Arduino.

Using bjoern's really nifty UDP add-on for the Ethernet library, I've started writing some code that could use that foundation to send out these kinds of UDP packets.

DNS is surprisingly easy. I've been able to send requests and receive name resolution responses.  The memory needs are not too severe: most replies should be under 100 bytes, and most requests around 50.

DHCP sucks.  There's this whole legacy matter of sending out 192 bytes of 0's that I think makes it harder to assemble the datagram before sending it out.  The total size of responses seems to be close to 600 bytes.

Would anyone else be interested in working further on this?  Or at least, have some advice based on past successes/failures?  I would love to have an unofficial add-on that would at least give us all DNS abilities.
Back to top
 
 
View Profile   IP Logged
macegr
God Member
*****
Offline

Arduino Ninja

Posts: 689

Re: DNS and DHCP Support with Ethernet Library
Reply #1 - 09.04.2009 at 08:48:50
 
Check Wiznet's own documentation site for an application note that does DHCP and is written for the Atmega. A similar set of code was used as the basis for the original Arduino Ethernet library. It should not be difficult to roll that in, though it will have a program size cost.
Back to top
 
 
View Profile | WWW   IP Logged
kg4wsv
God Member
*****
Offline



Posts: 1904

Re: DNS and DHCP Support with Ethernet Library
Reply #2 - 09.04.2009 at 12:29:37
 
Quote:
DHCP sucks.

Would BOOTP be any easier?

DNS would be handy, but judging by the traffic on the forum, DHCP is really needed to help the typical Arduino user, who probably isn't terribly familiar with configuring a network device, especially when the configuration values must be inferred or discovered from an existing network node.

-j

Back to top
 
 
View Profile   IP Logged
follower
God Member
*****
Offline

Arduino pebbles

Posts: 964
New Zealand
Re: DNS and DHCP Support with Ethernet Library
Reply #3 - 09.04.2009 at 16:09:37
 
Peter from tinker.it in London mentioned he had started working on DHCP/DNS support but hasn't so far responded to my request for access to the code.

I started re-looking at this recently, including the WIZnet supplied code. I suspect (like the original code) the WIZnet code will be functional but not efficient. The biggest issue will likely be the assumption by the original developer of greater RAM availability than the 168 or 328 provides.

Rather than pursue DHCP/DNS right now I was taking another look at modifying the Ethernet library to enable buffering of transmitted data. This would enable us to assemble the larger datagram in the "copious" quantities of RAM on the W5100 chip.

I'm still looking (slowly) into that though. Smiley

--Phil.
Back to top
 
 
View Profile | WWW   IP Logged
kg4wsv
God Member
*****
Offline



Posts: 1904

Re: DNS and DHCP Support with Ethernet Library
Reply #4 - 09.04.2009 at 16:58:53
 
Quote:
Rather than pursue DHCP/DNS right now I was taking another look at modifying the Ethernet library to enable buffering of transmitted data. This would enable us to assemble the larger datagram in the "copious" quantities of RAM on the W5100 chip.

That seems to almost be a prerequisite, anyway, as does UDP support.  I guess DHCP could be implemented directly, but since UDP is (IMO) desirable, it makes more sense to implement UDP in the arduino library (with the on-Wiz buffering you mention) and take advantage of all that to implement DHCP.

-j

Back to top
 
 
View Profile   IP Logged
Nebster
YaBB Newbies
*
Offline

Arduino rocks

Posts: 8

Re: DNS and DHCP Support with Ethernet Library
Reply #5 - 09.04.2009 at 19:34:46
 
Ok, thought I may as well mention this.

Over today, I have written a DHCP server (simple) which creates all the packets required and sends them after buffering them.

This is easy to implement as a client too.

If you want me to post the source, I can in 1-2 weeks (when i get back from Germany and clean up the code/maybe turn it into a library). It defo needs a clean up as it uses virtually all the memory on a ATMega328 because of the length of the packet (Up to 552 bytes) and I also allocate another 300-400 bytes for the response (but I could integrate that with the request to only use 552 bytes during authentication).

If you know how to use the RAM on the chip, please can you mention it here as I will use that if possible since it would make it easier

Also, I've got this code:
Code:
newoptions[j++]=15; //DOMAIN NAME
newoptions[j++]=6;
newoptions[j++]='M';
newoptions[j++]='S';
newoptions[j++]='H';
newoptions[j++]='O';
newoptions[j++]='M';
newoptions[j++]='E'; 


where j is an integer, newoptions is "char newoptions[312]".
How can I easily add "MSHOME" into the character array without doing it character by character? (Is there any other way than entering a for loop)

Cheers,
Nebster
Back to top
 
 
View Profile   IP Logged
smartperson
YaBB Newbies
*
Offline

Arduino minerals

Posts: 9
California
Gender: male
Re: DNS and DHCP Support with Ethernet Library
Reply #6 - 09.04.2009 at 20:21:36
 
Wow, I'm glad that there's so much interest in this.

I must confess that I'm looking at DNS because I'm too cheap to pay for a static IP address Wink

Nebster I'd love to see what you have for Arduino DHCP.  I bet we can use that as a base and get in-Wiz buffering working to make memory-efficient DHCP possible.

I would love to know what you've figured out so far, follower.  In the mean time I'll start reviewing the WizNet datasheet more closely for some insights of my own.

My plan if I can't get some basic DHCP working is to have a couple of pushbuttons that can be used to set IP information on device startup, and I really don't want to do that Sad
Back to top
 
 
View Profile   IP Logged
Nebster
YaBB Newbies
*
Offline

Arduino rocks

Posts: 8

Re: DNS and DHCP Support with Ethernet Library
Reply #7 - 12.04.2009 at 23:52:27
 
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)
Code:
#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
Back to top
 
 
View Profile   IP Logged
smartperson
YaBB Newbies
*
Offline

Arduino minerals

Posts: 9
California
Gender: male
Re: DNS and DHCP Support with Ethernet Library
Reply #8 - 13.04.2009 at 04:01:27
 
Hey guys,

I will try out your code Nebster when I can, and let you know.  I have a Diecimila, so I'm not sure I have enough RAM available to run it.

In the meantime, I have modified the UDP/socket code to support in-Wiz buffering.  It is only supported for sending UDP packets using UdpBufferedBytewise right now, and I will add support soon for receiving UDP packets and the other UDP methods.  I tested it out by sending packets up to about 1KB in size, and it really works.

This support is extremely extremely rough around the edges.  Namely, I'm having a hard time dealing with roll-back of the TX pointer register, so weird things happen once you've sent 65KB of data.

Use it the same way you would use the regular Bytewise class: call beginPacket(), then write() as many times as needed, then endPacket().  If you want to keep track of the TX pointer for debugging, call writePtr() instead of write().

Hopefully this is enough to get someone started, and maybe someone can help me work through these rough patches.

The svn repository is set up here.  If you want modify access let me know and I will be more than happy to provide it.  If there's a better home for this project than my personal server let me know and I can try to set everything up there.

Cheers!
Back to top
 
 
View Profile   IP Logged
Nebster
YaBB Newbies
*
Offline

Arduino rocks

Posts: 8

Re: DNS and DHCP Support with Ethernet Library
Reply #9 - 13.04.2009 at 23:27:49
 
That looks great so far!
You may have to reset the TX pointer somehow to 0 when you don't have enough room left in the buffer (so if you want to write 16 bytes and you only have 4 free, reset pointer and then write)
That's theoretical and I'm not actually sure how the chip works, lol

You should have enough memory to run that hopefully. I've integrated an available memory checker in there that I found on the net which will tell you when you try and run it!

The other way that I can think of trying to code it is read it byte by byte and altering data that I need to and send the bytes into the TX buffer. It would use less memory
Back to top
 
 
View Profile   IP Logged
mellis
YaBB Administrator
*****
Offline



Posts: 3006
Cambridge, MA
Re: DNS and DHCP Support with Ethernet Library
Reply #10 - 15.04.2009 at 18:00:09
 
If you guys get the code to state that you'd like to have it consider for inclusion in the library, please write it up on the developers mailing list: http://arduino.cc/mailman/listinfo/developers_arduino.cc
Back to top
 
 
View Profile | WWW   IP Logged
Jordan
YaBB Newbies
*
Offline

Arduino rocks

Posts: 16

Re: DNS and DHCP Support with Ethernet Library
Reply #11 - 20.04.2009 at 04:14:46
 
Greetings - I just released an Arduino DHCP library - looking for feedback.

http://blog.jordanterrell.com/post/RFID-Lock-Prototype-DHCP-Library-v01.aspx

- Jordan
Back to top
 
 
View Profile   IP Logged
smartperson
YaBB Newbies
*
Offline

Arduino minerals

Posts: 9
California
Gender: male
Re: DNS and DHCP Support with Ethernet Library
Reply #12 - 21.04.2009 at 09:17:33
 
That's cool, Jordan.

Has anyone else gotten Jordan's code working.  As written it wasn't working for me with the DHCP server built into Internet Sharing on my Mac.

I hooked my laptop up to my Mac and sniffed its traffic.  That's when I realized that the PC was sending a DHCP discover, then sending another one 5 seconds later.  It was also important to increment seconds elapsed between these two messages.

To that end, I changed the code as follows to hack it into working.  The summary of these changes is adding "wiring.h", sending two DHCPDISCOVER requests separated by 5 seconds, and putting a secondCount value in the buffer at indexes 8 and 9.  Yes, this is a hack, but I just wanted to demonstrate the kind of changes that I needed to make.  Once I do this it works beautifully!

Let me know what the rest of you find.  I'm going to study how Jordan is using buffering in the WizNet so effectively.

Cheers!

Code:
// DHCP Library v0.1 - April 19, 2009
// Author: Jordan Terrell - blog.jordanterrell.com

extern "C" {
#include "types.h"
#include "w5100.h"
#include "sockutil.h"
#include "socket.h"
#include "spi.h"
}

#include <string.h>
#include <stdlib.h>
#include "Dhcp.h"
#include "wiring.h"

int secondCount = 0;

int Dhcp::beginWithDHCP(uint8_t *mac)
{
	_dhcpTransactionId = 0x1234;
	uint8_t dhcp_state = STATE_DHCP_START;
	u_char messageType = 0;

	memset(_dhcpMacAddr, 0, 6);
	memset(_dhcpSubnetMask, 0, 4);
	memset(_dhcpGatewayIp, 0, 4);
	memset(_dhcpLocalIp, 0, 4);
	memset(_dhcpServerIp, 0, 4);
	memset(_dhcpDnsIp, 0, 4);

	memcpy((void*)_dhcpMacAddr, (void*)mac, 6);

	iinchip_init();
	setSHAR(_dhcpMacAddr);
	setSIPR(_dhcpLocalIp);

	sysinit(0x55, 0x55);
	if(socket(0, Sn_MR_UDP, DHCP_CLIENT_PORT, 0) <= 0)
	{
		return -1;
	}

	presend_DHCP();

	int result = 0;

	while(dhcp_state != STATE_DHCP_LEASED)
	{
		if(dhcp_state == STATE_DHCP_START)
		{
			send_DHCP_MESSAGE(DHCP_DISCOVER);
			delay(5000);
			send_DHCP_MESSAGE(DHCP_DISCOVER);
			dhcp_state = STATE_DHCP_DISCOVER;
		}
		else if(dhcp_state == STATE_DHCP_DISCOVER)
		{
			messageType = parseDHCPResponse();
			if(messageType == DHCP_OFFER)
			{
				send_DHCP_MESSAGE(DHCP_REQUEST);
				dhcp_state = STATE_DHCP_REQUEST;
			}

			//_dhcpTransactionId++;
			//send_DHCP_MESSAGE(DHCP_DISCOVER);
			//dhcp_state = STATE_DHCP_DISCOVER;
		}
		else if(dhcp_state == STATE_DHCP_REQUEST)
		{
			messageType = parseDHCPResponse();
			if(messageType == DHCP_ACK)
			{
				dhcp_state = STATE_DHCP_LEASED;
				result = 1;
			}
		}
	}

	close(0);
	_dhcpTransactionId++;

	if(result == 1)
	{
		setSIPR(_dhcpLocalIp);
		setGAR(_dhcpGatewayIp);
		setSUBR(_dhcpSubnetMask);
	}

	return result;
}

void Dhcp::presend_DHCP()
{
	uint16 port = DHCP_SERVER_PORT;

	IINCHIP_WRITE(Sn_DIPR0(0), 255);
	IINCHIP_WRITE((Sn_DIPR0(0) + 1), 255);
	IINCHIP_WRITE((Sn_DIPR0(0) + 2), 255);
	IINCHIP_WRITE((Sn_DIPR0(0) + 3), 255);

	IINCHIP_WRITE(Sn_DPORT0(0), (uint8)((port & 0xff00) >> 8));
	IINCHIP_WRITE((Sn_DPORT0(0) + 1), (uint8)(port & 0x00ff));  
}

void Dhcp::send_DHCP_MESSAGE(uint8 messageType)
{
	uint16 ptr = 0;

 	ptr = IINCHIP_READ(Sn_TX_WR0(0));
	ptr = ((ptr & 0x00ff) << 8) + IINCHIP_READ(Sn_TX_WR0(0) + 1);

	uint8 *buffer = (uint8*) malloc(32);
	memset(buffer, 0, 32);

	buffer[0] = DHCP_BOOTREQUEST;   // op
	buffer[1] = DHCP_HTYPE10MB;     // htype
	buffer[2] = DHCP_HLENETHERNET;  // hlen
	buffer[3] = DHCP_HOPS;          // hops

	// xid
	unsigned long xid = htonl(_dhcpTransactionId);
	memcpy(buffer + 4, &(xid), 4);

	// 8, 9 - sec: already zeroed
	buffer[8] = 0;
	buffer[9] = secondCount & 0xFF;
	secondCount += 5;

	// flags
	unsigned short flags = htons(DHCP_FLAGSBROADCAST);
	memcpy(buffer + 10, &(flags), 2);

	// ciaddr: already zeroed
	// yiaddr: already zeroed
	// siaddr: already zeroed
	// giaddr: already zeroed

	//put data in W5100 transmit buffer
	write_data(0, buffer, (uint8 *)ptr, 28);
	ptr += 28;

	memset(buffer, 0, 32); // clear local buffer

	memcpy(buffer, _dhcpMacAddr, 6); // chaddr

	//put data in W5100 transmit buffer
	write_data(0, buffer, (uint8 *)ptr, 16);
	ptr += 16;

	memset(buffer, 0, 32); // clear local buffer

	// leave zeroed out for sname
	// put in W5100 transmit buffer x 2 (64 bytes)

	write_data(0, buffer, (uint8 *)ptr, 32);
	ptr += 32;

	write_data(0, buffer, (uint8 *)ptr, 32);
	ptr += 32;

	// leave zeroed out for file
	// put in W5100 transmit buffer x 4 (128 bytes)

	write_data(0, buffer, (uint8 *)ptr, 32);
	ptr += 32;

	write_data(0, buffer, (uint8 *)ptr, 32);
	ptr += 32;

	write_data(0, buffer, (uint8 *)ptr, 32);
	ptr += 32;

	write_data(0, buffer, (uint8 *)ptr, 32);
	ptr += 32;

	// OPT - Magic Cookie
	buffer[0] = (uint8)((MAGIC_COOKIE >> 24)& 0xFF);
	buffer[1] = (uint8)((MAGIC_COOKIE >> 16)& 0xFF);
	buffer[2] = (uint8)((MAGIC_COOKIE >> 8)& 0xFF);
	buffer[3] = (uint8)(MAGIC_COOKIE& 0xFF);

	// OPT - message type
	buffer[4] = dhcpMessageType;
	buffer[5] = 0x01;
	buffer[6] = messageType; //DHCP_REQUEST;

	// OPT - client identifier
	buffer[7] = dhcpClientIdentifier;
	buffer[8] = 0x07;
	buffer[9] = 0x01;
	memcpy(buffer + 10, _dhcpMacAddr, 6);

	// OPT - host name
	buffer[16] = hostName;
	buffer[17] = strlen(HOST_NAME) + 3; // length of hostname + last 3 bytes of mac address
	strcpy((char*)&(buffer[18]), HOST_NAME);
	/*
	 buffer[24] = _dhcpMacAddr[3];
	 buffer[25] = _dhcpMacAddr[4];
	 buffer[26] = _dhcpMacAddr[5];*/

	buffer[24] = '1';
	buffer[25] = '2';
	buffer[26] = '3';

	//put data in W5100 transmit buffer
	write_data(0, buffer, (uint8 *)ptr, 27);
	ptr += 27;

	memset(buffer, 0, 32); // clear local buffer

	if(messageType == DHCP_REQUEST)
	{
		buffer[0] = dhcpRequestedIPaddr;
		buffer[1] = 0x04;
		buffer[2] = _dhcpLocalIp[0];
		buffer[3] = _dhcpLocalIp[1];
		buffer[4] = _dhcpLocalIp[2];
		buffer[5] = _dhcpLocalIp[3];

		buffer[6] = dhcpServerIdentifier;
		buffer[7] = 0x04;
		buffer[8] = _dhcpServerIp[0];
		buffer[9] = _dhcpServerIp[1];
		buffer[10] = _dhcpServerIp[2];
		buffer[11] = _dhcpServerIp[3];

		//put data in W5100 transmit buffer
		write_data(0, buffer, (uint8 *)ptr, 12);
		ptr += 12;

		memset(buffer, 0, 32); // clear local buffer
	}

	buffer[0] = dhcpParamRequest;
	buffer[1] = 0x06;
	buffer[2] = subnetMask;
	buffer[3] = routersOnSubnet;
	buffer[4] = dns;
	buffer[5] = domainName;
	buffer[6] = dhcpT1value;
	buffer[7] = dhcpT2value;
	buffer[8] = endOption;

	//put data in W5100 transmit buffer
	write_data(0, buffer, (uint8 *)ptr, 9);
	ptr += 9;

	if(buffer)
		free(buffer);

	IINCHIP_WRITE(Sn_TX_WR0(0),(uint8)((ptr & 0xff00) >> 8));
	IINCHIP_WRITE((Sn_TX_WR0(0) + 1),(uint8)(ptr & 0x00ff));

	IINCHIP_WRITE(Sn_CR(0), Sn_CR_SEND);

	while( IINCHIP_READ(Sn_CR(0)) ) ;
}

char Dhcp::parseDHCPResponse()
{
	uint16 ptr = 0;
 	uint16 data_len = 0;
 	uint16 port = 0;
 	u_char type = 0;
 	u_char svr_addr[4];
 	u_char opt_len = 0;

	uint8* buffer = 0;

	while((IINCHIP_READ(Sn_RX_RSR0(0)) == 0x0000) && (IINCHIP_READ(Sn_RX_RSR0(0) + 1) == 0x0000));

	ptr = IINCHIP_READ(Sn_RX_RD0(0));
	ptr = ((ptr & 0x00ff) << 8) + IINCHIP_READ(Sn_RX_RD0(0) + 1);

	// read UDP header
	buffer = (uint8*)malloc(8);
	read_data(0, (uint8 *)ptr, (uint8*)buffer, 0x08);
	ptr += 8;

	svr_addr[0] = buffer[0];
	svr_addr[1] = buffer[1];
	svr_addr[2] = buffer[2];
	svr_addr[3] = buffer[3];
	port = buffer[4];
	port = (port << 8) + buffer[5];
	data_len = buffer[6];
	data_len = (data_len << 8) + buffer[7];

	free(buffer);

	buffer = (uint8*) malloc(sizeof(RIP_MSG_FIXED));
	RIP_MSG_FIXED * pRMF = (RIP_MSG_FIXED*) buffer;

	read_data(0, (uint8 *)ptr, (uint8*)buffer, sizeof(RIP_MSG_FIXED));

	if(pRMF->op == DHCP_BOOTREPLY && port == DHCP_SERVER_PORT)
	{
		if(memcmp(pRMF->chaddr, _dhcpMacAddr, 6) != 0 || pRMF->xid != htonl(_dhcpTransactionId))
		{
			return 0;
		}

		memcpy(_dhcpLocalIp, pRMF->yiaddr, 4);
		free(buffer);

		uint16 optionLen = data_len - 240;
		buffer = (uint8*) malloc(optionLen);
		read_data(0, (uint8 *)ptr + 240, (uint8*)buffer, optionLen);


		uint8* p = buffer;
		uint8* e = p + optionLen;

		while ( p < e )
		{
			switch ( *p++ )
			{
				case endOption :
					break;
				case padOption :
					break;
				case dhcpMessageType :
					opt_len = *p++;
					type = *p;
					break;
				case subnetMask :
					opt_len =* p++;
					memcpy(_dhcpSubnetMask, p ,4);
					break;
				case routersOnSubnet :
					opt_len = *p++;
					memcpy(_dhcpGatewayIp, p, 4);
					break;
				case dns :
					opt_len = *p++;
					memcpy(_dhcpDnsIp, p, 4);
					break;
				case dhcpIPaddrLeaseTime :
					opt_len = *p++;
					break;

				case dhcpServerIdentifier :
					opt_len = *p++;
					if( *((u_long*)_dhcpServerIp) == 0 ||
					   *((u_long*)_dhcpServerIp) == *((u_long*)svr_addr) )
					{
						memcpy(_dhcpServerIp, p ,4);
					}

					break;
				default :
					opt_len = *p++;
					break;
			}

			p += opt_len;
		}

		free(buffer);
	}

	ptr += data_len;

	IINCHIP_WRITE(Sn_RX_RD0(0),(uint8)((ptr & 0xff00) >> 8));
	IINCHIP_WRITE((Sn_RX_RD0(0) + 1),(uint8)(ptr & 0x00ff));

	IINCHIP_WRITE(Sn_CR(0),Sn_CR_RECV);

	while( IINCHIP_READ(Sn_CR(0)) );

	return type;
}
 

Back to top
 
 
View Profile   IP Logged
Jordan
YaBB Newbies
*
Offline

Arduino rocks

Posts: 16

Re: DNS and DHCP Support with Ethernet Library
Reply #13 - 21.04.2009 at 14:32:22
 
smartperson - Would you be willing to send me a copy of the traffic you sniffed?  If so, upload it to ftp://ftp.i-synaptic.net/incoming, and then reply to my post with the file name.

This may be the issue that I saw needing to wait for a period of time before trying to send the first DISCOVER packet (see the commented code in the example included with the library). It appears some hubs/switches/routers need a few seconds before it will accept packets.  This even applies when I do a soft reset on the Arduino.  Strange, but I'll need to compensate with retry logic (and some kind of timeout probably).

Thanks - Jordan
Back to top
 
 
View Profile   IP Logged
smartperson
YaBB Newbies
*
Offline

Arduino minerals

Posts: 9
California
Gender: male
Re: DNS and DHCP Support with Ethernet Library
Reply #14 - 22.04.2009 at 03:56:11
 
I uploaded the file "ArduinoTCPDump.pcap"
Wireshark loads it quite nicely.

I saw your delay code.  If I include the delay you commented out, that it is not enough to get it to work.  For my DHCP server to respond it has to receive a DHCP Discover and then receive another Discover packet 5 seconds later.  Why?  I don't know!  Roll Eyes

I also changed some random parameters (MAC, hostname, etc.) but those shouldn't affect anything.
Back to top
 
 
View Profile   IP Logged
Pages: 1 2 3 4