Pages: [1] 2 3 4   Go Down
Author Topic: DNS and DHCP Support with Ethernet Library  (Read 10225 times)
0 Members and 1 Guest are viewing this topic.
California
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino minerals
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

SF Bay Area
Offline Offline
Edison Member
*
Karma: 10
Posts: 1235
Arduino Ninja
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Unique RGB LED Modules and Arduino shields: http://www.macetech.com/store

0
Offline Offline
Faraday Member
**
Karma: 7
Posts: 2526
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Logged

New Zealand
Offline Offline
God Member
*****
Karma: 0
Posts: 999
Arduino pebbles
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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. :-)

--Phil.
Logged

0
Offline Offline
Faraday Member
**
Karma: 7
Posts: 2526
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 10
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
« Last Edit: April 09, 2009, 02:01:28 pm by Nebster » Logged

California
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino minerals
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley-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 smiley-sad
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 10
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

California
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino minerals
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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!
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 10
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Forum Administrator
Cambridge, MA
Offline Offline
Faraday Member
*****
Karma: 9
Posts: 3538
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 16
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Greetings - I just released an Arduino DHCP library - looking for feedback.

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

- Jordan
Logged

California
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino minerals
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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;
}
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 16
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

smartperson - Would you be willing to send me a copy of the traffic you sniffed?  If so, upload it to http://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
Logged

California
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino minerals
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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!  :smiley

I also changed some random parameters (MAC, hostname, etc.) but those shouldn't affect anything.
Logged

Pages: [1] 2 3 4   Go Up
Jump to: