⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dhcp.c

📁 Intrisyc 公司的PXA255-bootloader,源码易懂
💻 C
字号:
//////////////////////////////////////////////////////////////////////////////////// Copyright(c) 2001 Intrinsyc Software Inc. All rights reserved.//// Module name:////      dhcp.c//// Description:////      Sends dhcp requests and handles the response.//// Author:////      Mike Kirkland//// Created:////      October 2001//// Modified:// 	Brad Remedios - March 25, 2002// 		- Made the dhcp code make use of the Ethernet Flush and// 		  related routines to help it out in the congested network// 		  scenerios.  If the board gets too many broadcast packets// 		  it may drop some on the floor.////////////////////////////////////////////////////////////////////////////////#include <dhcp.h>#include <bootp.h>#include <net.h>#include <types.h>#include <timer.h>#include <c_main.h>#include <udp.h>#include <util.h>#include <string.h>#include <ethernet.h>//#define DEBUG_LEVEL 4#include <debug.h>#define MAX_RETRIES 5   // number of times to try DHCP before giving up////////////////////////////////////////////////////////////////////////////////// fill_dhcp// PURPOSE: Creates a dhcp request packet.// PARAMS:  (OUT) u8 buf       - buffer to write packet into.//          (IN)  u16 *macaddr - MAC address to create packet for.// RETURNS: Nothing.////////////////////////////////////////////////////////////////////////////////static voidfill_dhcp(dhcp_packet *packet,         u16 *macaddr,         u32 sid,         u32 riaddr,         u32 xid,         u16 timestamp,         u8 type){   //we will need to fill in options at the end   u8 *end = (u8 *)(packet + 1);   //opcode   packet->op = BOOTP_REQ;   //hardware type   packet->htype = BOOTP_HATYPE_ETH;   //hardware address length   packet->hlen = BOOTP_HALENGTH_ETH;   //# of hops   packet->hops = 0;   //transaction id   packet->xid = htonl(xid);   //seconds since we started trying   packet->secs = timestamp;   //flags field (unused)   packet->flags = 0;   //client ip address (we don't know it yet)   packet->ciaddr = 0;   //"your" client ip address (set by server)   packet->yiaddr = 0;   //dhcp server address   packet->siaddr = 0;   //gateware ip address (set by server)   packet->giaddr = 0;   //client hardware address. 16 bytes long   packet->chaddr[0] = macaddr[0];   packet->chaddr[1] = macaddr[1];   packet->chaddr[2] = macaddr[2];   //server host name string. 64 bytes long   packet->sname[0] = '\0';   //boot file name (set by server). 128 bytes long   packet->bootfile[0] = '\0';   //set options "magic cookie"   packet->magic_cookie[0] = DHCP_MAGIC1;   packet->magic_cookie[1] = DHCP_MAGIC2;   packet->magic_cookie[2] = DHCP_MAGIC3;   packet->magic_cookie[3] = DHCP_MAGIC4;   //Set DHCP message type   *end++ = DHCP_OPTION_MSGTYPE;   *end++ = sizeof(u8);   *end++ = type;   //pad to u32 alignment to make following u32 writes simpler   *end++ = DHCP_OPTION_PAD;   *end++ = DHCP_OPTION_PAD;   *end++ = DHCP_OPTION_PAD;   if(riaddr != 0)   {      *end++ = DHCP_OPTION_REQADDR;      *end++ = sizeof(u32);      *(u32 *)end = htonl(riaddr);      end += sizeof(u32);      //pad to u32 alignment to make following u32 write simpler      *end++ = DHCP_OPTION_PAD;      *end++ = DHCP_OPTION_PAD;   }   if(sid != 0)   {      *end++ = DHCP_OPTION_SERVER_ID;      *end++ = sizeof(u32);      *(u32 *)end = htonl(sid);      end += sizeof(u32);   }   //specifically ask the DHCP server to tell us what the gateway address and   //subnet mask are.   *end++ = DHCP_OPTION_REQPARAM;   *end++ = 3;  //the number of parameters we are requesting   *end++ = DHCP_OPTION_ROUTER;   *end++ = DHCP_OPTION_SMASK;   *end++ = DHCP_OPTION_SERVER_ID;   // End of options   *end++ = DHCP_OPTION_END;}////////////////////////////////////////////////////////////////////////////////// request_dhcp// PURPOSE: Sends a DHCP request message.// PARAMS:  (IN) u32 ciaddr - IP address to request//          (IN) u32 sid    - DHCP server ID//          (IN) u32 xid    - DHCP transaction id// RETURNS: Nothing.////////////////////////////////////////////////////////////////////////////////static voidrequest_dhcp(u32 ciaddr,             u32 sid,             u32 xid){   u8 buf[MAX_PACKET_SIZE + 2];   //we want the packet to be u32 aligned *after* the headers (42 bytes)   u8 *packet = buf + 2;   memset32((u32 *)buf, 0 , MAX_PACKET_SIZE / sizeof(u32));   fill_dhcp((dhcp_packet *)(packet + UDPIP_HEADER_SIZE),             status.macaddr,             sid,             ciaddr,             xid,             0,             DHCP_REQUEST);   udppacket((u16 *)packet,             DHCP_PACKET_SIZE + UDPIP_HEADER_SIZE,             IP_BROADCAST,             0,             BOOTP_TX_PORT,             BOOTP_RX_PORT,             status.macaddr);}////////////////////////////////////////////////////////////////////////////////// parse_options_dhcp// PURPOSE: Parses the Options and vendor extentions field of DHCP and bootp//          packets. Currently supports message type, subnet mask, and router//          options.// PARAMS:  (IN) u8 *end        - the end of the static part of the DHCP/bootp//                                packet, and thus the beginning of the //                                extensions.//          (OUT) u32 *giaddr   - Gateway (router) address//          (OUT) u32 *smask    - Subnet mask//          (OUT) u32 *sid      - Server ID//          (OUT) u32 *msg_type - DHCP message type// RETURNS: Nothing.// NOTES:   The values of *giaddr, *smask, and *msg_type are undefined if they//          are not found in the options field pointed to by end.////////////////////////////////////////////////////////////////////////////////voidparse_options_dhcp(u8 *end,		   u32 *giaddr,		   u32 *smask,		   u32 *sid,		   u8 *msg_type){   int len;   u8 *option;   while(*end != DHCP_OPTION_END)   {      option = end++;      len = *end++;      DEBUG_3("Found DHCP option %d\r\n", *option);      if(*option == DHCP_OPTION_MSGTYPE)      {	 *msg_type = *end;      }      else if(*option == DHCP_OPTION_SMASK)      {	 *smask = *end++ << 24;	 *smask |= *end++ << 16;	 *smask |= *end++ << 8;	 *smask |= *end++;	 DEBUG_2("DHCP reports subnet mask as %s\r\n", iptoa(*smask));      }      else if(*option == DHCP_OPTION_ROUTER)      {         *giaddr = *end++ << 24;	 *giaddr |= *end++ << 16;	 *giaddr |= *end++ << 8;	 *giaddr |= *end++;	 DEBUG_2("DHCP reports gateway at %s\r\n", iptoa(*giaddr));      }      else if(*option == DHCP_OPTION_SERVER_ID)      {	 *sid = *end++ << 24;	 *sid |= *end++ << 16;	 *sid |= *end++ << 8;	 *sid |= *end++;	 DEBUG_2("DHCP reports server ID as %s\r\n", iptoa(*sid));      }      else if(*option == DHCP_OPTION_PAD)      {         len = -1;      // special case      }      else      {	 DEBUG_3("Ignoring DHCP Option #%i.\r\n", *option);      }      end = option + len + 2;   }}////////////////////////////////////////////////////////////////////////////////// listen_dhcp// PURPOSE: Listens for an incoming DHCP message for the board.// PARAMS:  (OUT) u32 *ciaddr - IP address being assigned to the board.//          (OUT) u32 *siaddr - DHCP server's IP address.//          (OUT) u32 *giaddr - gateway address.//          (OUT) u32 *smask  - IP netmask//          (OUT) u32 *sid    - server ID//          (OUT) char *bootfile - boot file name//          (IN) u32 xid      - transaction ID// RETURNS: Type of DHCP message received on success, 0 on failure.////////////////////////////////////////////////////////////////////////////////static u8listen_dhcp(u32 *ciaddr,            u32 *siaddr,	    u32 *giaddr,	    u32 *smask,	    u32 *sid,	    char *bootfile,            u32 xid){   u8 buf[MAX_PACKET_SIZE];   //we need this to be u32 aligned *after* the 42 bytes of headers   dhcp_packet *packet = (dhcp_packet *)(buf + UDPIP_HEADER_SIZE + 2);   u32 iaddr;   u16 size;   u8 *end = (u8 *)((u32)packet + sizeof(dhcp_packet));   u8 msg_type = 0;   // Randomize the timeout a bit; his might overflow, but that would just   // shorten the retry delay   u32 time = get_time_timer() + NET_TIMEOUT + rand() % 4;   do   {      if (time < get_time_timer())      {         // We timed out receiving reply         // We can't rely on the udplisten timeout because we could         // theoretically receive a steady supply of miscellaneous packets         // so it will never time out.         return 0;      }      size = MAX_PACKET_SIZE;      //if udp times out, abandon our own timeout.      if(!udplisten((buf + 2), &size, &iaddr,1))      {         return 0;      }   } while(packet->op != BOOTP_REPLY || ntohl(packet->xid) != xid ||           size < (UDPIP_HEADER_SIZE + sizeof(dhcp_packet)));   *ciaddr = ntohl(packet->yiaddr);   *siaddr = ntohl(packet->siaddr);   *giaddr = ntohl(packet->giaddr);   itc_strcpy(bootfile, packet->bootfile);   DEBUG_3("Bootfile: %s\r\n", bootfile);   if (packet->magic_cookie[0] == DHCP_MAGIC1 &&       packet->magic_cookie[1] == DHCP_MAGIC2 &&       packet->magic_cookie[2] == DHCP_MAGIC3 &&       packet->magic_cookie[3] == DHCP_MAGIC4)   {      parse_options_dhcp(end, giaddr, smask, sid, &msg_type);   }   DEBUG_3("Received a DHCP message of type: %i.\r\n", msg_type);   return msg_type;}////////////////////////////////////////////////////////////////////////////////// init_dhcp// PURPOSE: Handles a DHCP transaction to obtain the board's IP address, a//          default server IP address, and possibly other configuration details//          in the future (such as a script to run).// PARAMS:  (IN) u32 *ciaddr - Client IP address returned.//          (IN) u32 *siaddr - TFTP or other server address.//          (IN) u32 *giaddr - gateway address.//          (IN) u32 *smask  - IP netmask// RETURNS: 1 for success, 0 for failure. Parameters are not changed on failure.//// NOTES:// 	The two labels (offer_wait_start and ack_wait_start) are there to help// 	dhcp work well on very busy networks.  Also, Ethernet Flushes were// 	added for the same reason////////////////////////////////////////////////////////////////////////////////intinit_dhcp(u32 *ciaddr,          u32 *siaddr,	  u32 *giaddr,	  u32 *smask){   u8 buf[MAX_PACKET_SIZE + 2];   u32 xid = rand();   u32 time = get_time_timer();   //we want the packet to be u32 aligned *after* the headers (42 bytes)   u8 *packet = buf + 2;   int timeout = MAX_RETRIES;   int got_addr = 0;   // Delay a short random amount to space out DHCP requests from many clients   // booting up at once.   udelay(rand() % 100000);   udelay(rand() % 100000);   memset32((u32 *)buf, 0, MAX_PACKET_SIZE / sizeof(u32));   fill_dhcp((dhcp_packet *)(packet + UDPIP_HEADER_SIZE),            status.macaddr,            0,  //we don't care which dhcp server responds to us            0,  //we don't care what address it gives us            xid,            get_time_timer() - time,            DHCP_DISCOVER);   while(!got_addr && timeout--)   {      u32 temp_ciaddr = 0;      u32 temp_siaddr = 0;      u32 temp_giaddr = 0;      u32 temp_smask = 0;      u32 temp_sid = 0;      int offer_retry;      int ack_retry;      char temp_bootfile[MAX_BOOTFILE_SIZE];#if DEBUG_LEVEL >= 4      DEBUG("Sending--------\r\n");      parse_options_dhcp(packet + UDPIP_HEADER_SIZE + sizeof(dhcp_packet),                         &temp_giaddr,                         &temp_smask,                         &temp_sid,                         &temp_bootfile[0]);      DEBUG("---------------\r\n");#endif      flush_ethernet ();      udppacket((u16 *)packet,                DHCP_PACKET_SIZE + UDPIP_HEADER_SIZE,                IP_BROADCAST,                0,             //we don't know what our ip is yet                BOOTP_TX_PORT,                BOOTP_RX_PORT,                status.macaddr);      offer_retry=0;      if(listen_dhcp(&temp_ciaddr,		     &temp_siaddr,		     &temp_giaddr,		     &temp_smask,		     &temp_sid,		     (char *)temp_bootfile,		     xid) == DHCP_OFFER)      {         u32 ack_ciaddr = temp_ciaddr;         u32 ack_siaddr = temp_siaddr;	 u32 ack_giaddr = temp_giaddr;	 u32 ack_smask = temp_smask;         u32 ack_sid = temp_sid;	 char ack_bootfile[MAX_BOOTFILE_SIZE];         flush_ethernet ();         request_dhcp(temp_ciaddr, temp_sid, xid);	 ack_retry=0;         do         {             if(listen_dhcp(&ack_ciaddr,                            &ack_siaddr,                             &ack_giaddr,                            &ack_smask,                            &ack_sid,                             (char *)ack_bootfile,                            xid) == DHCP_ACK)             {               *ciaddr = ack_ciaddr;               *siaddr = ack_siaddr;               *giaddr = ack_giaddr;               *smask = ack_smask;               itc_strcpy(status.bootfile, ack_bootfile);               if(*siaddr == 0)               {                  // No more servers were given, so use this one as default                  *siaddr = ack_sid;               }               if(*giaddr == 0)               {                  // No gateway was given, despite our request; use server                  // address as a poor substitute.                  *giaddr = *siaddr;               }               got_addr = 1;               break;            }            itc_printf("+");        } while (ack_retry++ < 3);      }      if (!got_addr)      {         itc_printf(".");      }   }   rx_ethernet_off ();   flush_ethernet ();   if(!got_addr)   {      itc_printf("\r\n");      error_print(DHCP_TIMEOUT_ERROR);   }   return got_addr;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -