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

📄 dhcpclnt.c

📁 在ARM7和UC/OSII的平台上实现了GPS自动报站的功能,涉及GPS模块LEA_4S的驱动,位置速寻算法,语音芯片ISD4004的录放音驱动,LED页面管理等等.从启动代码到操作系统的移植以及到业
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * FILENAME: dhcpclnt.c
 *
 * Copyright 1997- 2000 By InterNiche Technologies Inc. All rights reserved
 *
 * DHCP Client code for InterNiche IP stack.
 *
 * MODULE: INET
 *
 * ROUTINES: dhc_get_srv_ipaddr(), dhc_init(), 
 * ROUTINES: dhc_set_callback(), dhc_upcall(), dhc_buildheader(), 
 * ROUTINES: dhc_discover(), dhc_rx_offer(), dhc_request(), dhc_setip(), 
 * ROUTINES: dhc_resetip(), dhc_decline(), dh_getlong(), dhc_extract_opts(), 
 * ROUTINES: dhc_stats(), dhc_second(), dhc_halt(), dhc_reclaim(), 
 * ROUTINES: dhc_state_init(), dhc_alldone(), dhc_ifacedone(), 
 * ROUTINES: dhc_set_state(),
 *
 * PORTABLE: yes
 */

/* Additional Copyrights: */
/* Portions Copyright 1996 by NetPort Software. */

#include "ipport.h"

#ifdef DHCP_CLIENT   /* ifdef out whole file */

#include "q.h"
#include "netbuf.h"
#include "net.h"
#include "ip.h"
#include "udp.h"
#include "dhcpclnt.h"

#include "minip.h"      /* (yaxon add) */

/* A lot of the following variables are named similarly to variables 
 * of similar function in the dhcp server code. n general the 
 * difference is that the client names start with "dhc_" and the 
 * server versions 
 */
UDPCONN dhc_conn = NULL;

long     xids  =  0x22334455;    /* seed for unique request IDs */

/* DHCP client statistics: */
ulong      dsc_errors    = 0; /* protocol/implementation runtime errors */
ulong      dsc_discovers = 0; /* discovers sent */
ulong      dsc_offers    = 0; /* offers recieved */
ulong      dsc_requests  = 0; /* requests sent */
ulong      dsc_acks      = 0; /* acks received */
ulong      dsc_bpreplys  = 0; /* plain bootp replys received */
ulong      dsc_declines  = 0; /* declines sent */
ulong      dsc_releases  = 0; /* releases sent */
ulong      dsc_naks      = 0; /* naks received */
ulong      dsc_renew     = 0; /* unicast requests sent to renew lease */
ulong      dsc_rebind    = 0; /* broadcast requests sent to renew lease */
ulong      dsc_rlyerrs   = 0; /* runtime errors due to DHCP Relay agents */

/* reqlist contains the list of options to be requested in a DISCOVER 
 * pkt. reqlist is used only if DHCP_REQLIST is enabled. 
 */
#ifdef DHCP_REQLIST
u_char   reqlist[]   =  {  DHOP_SNMASK,DHOP_ROUTER,   DHOP_DNSRV, DHOP_DOMAIN }  ;

/* u_char reqlist[] = { DHOP_SNMASK,DHOP_ROUTER, DHOP_DNSRV, 
 * DHOP_DOMAIN,0x2c,0x2e,0x2f }; 
 */
int      reqlist_len = sizeof(reqlist)/sizeof(u_char);
#endif   /* DHCP_REQLIST */

struct dhc_state  dhc_states[MAXNETS]; /* DHCP client state of each net. */

#ifdef NET_STATS
static char *dhc_state_str[] = 
{
   "unused",
   "init",
   "init-reboot",
   "rebooting",
   "selecting",
   "requesting",
   "bound",
   "renewing",
   "rebinding",
   "restarting",
};
#endif

#define  DHC_BCASTFLAG  0x8000            /* for the flags field of pkt */
#define  DHC_INFINITY   0xffffffff        /* That is, "-1" */
#define  DHC_MAX_TRIES  4                 /* Max num of retires to tbe done */
#define  DHC_RETRY_TMO  4                 /* Timeout(secs) for retries */
#define  DHCPDATA       ((void*)0xFFFFFFFD)  /* tag for pass to udp_open() */

/* DHCP functions used within this file */
int      dhc_upcall      (PACKET pkt, void * data); 
int      dhc_discover    (int iface);    /* send a dhcp discover packet */
int      dhc_reclaim     (int iface);    /* try to reclaim previous address */
int      dhc_setip       (int iface);    /* set iface's IP addr */
int      dhc_resetip     (int iface);    /* reset iface's IP addr */
int      dhc_request     (int iface, int xid_flag); /* Send a request */
int      dhc_rx_offer    (int iface, struct bootp * bp, unsigned bplen);
int      dhc_decline     (int iface, struct bootp * bp, unsigned bplen);
int      dhc_buildheader (int iface, struct bootp * outbp);
int  dhc_extract_opts(int iface, u_char * opts);
void     dhc_set_state   (int iface, int state);

extern   void fixup_subnet_mask(int netnum);  /* from ipnet.c */
static long dh_getlong( u_char *ptr ); 

extern char *  dhc_hostname(void);  /* returns a name for this machine */


/* FUNCTION: dhc_get_srv_ipaddr()
 * 
 * PARAM1: u_char *options - the ones after "magic cookie"
 *
 * RETURNS: 
 */

ip_addr 
dhc_get_srv_ipaddr(u_char *options /* after magic cookie */) 
{
    u_char * opts;
    u_char   optlen;
   ip_addr srv_ipaddr = 0;

   if ((opts = find_opt(DHOP_SERVER, options)) != NULL) 
   {
      opts++;
      optlen = *opts;
      opts++;
      srv_ipaddr = dh_getlong(opts);
      opts += optlen;
   }

   return (srv_ipaddr);
} 


/* dhc_init() - this must set up the default fields above, read in 
 * bootptab file (if supported) and open UDP socket for listens. 
 * Returns 0 if OK, else negative error code from net.h file 
 */


/* FUNCTION: dhc_init()
 * 
 * This must set up the default fields above, read in 
 * bootptab file (if supported) and open UDP socket for listens. 
 *
 * PARAM1: void
 *
 * RETURNS: Returns 0 if OK, else negative error code from net.h file 
 */

int
dhc_init(void)
{
   int   i;

   /* open UDP connection to receive incoming DHCP replys */
   dhc_conn = udp_open(0L,    /* wildcard foriegn host */
      BOOTP_SERVER_PORT, BOOTP_CLIENT_PORT,
      dhc_upcall, DHCPDATA);

   if (!dhc_conn)
      return ENP_RESOURCE;

   for (i = 0; i < MAXNETS; i++)
   {
      dhc_states[i].state = DHCS_UNUSED;
      dhc_states[i].tries = 0;
   }

   return 0;
}



/* FUNCTION: dhc_set_callback()
 *
 * dhc_set_callback() : This interface allows the caller to set a 
 * calling back for a interface. When DHCP Client gets an ACK, it 
 * callings this routine. This mechanism is provider so that the 
 * caller can do some processing when the interface is up (like doing 
 * initializations or blinking LEDs , etc.). 
 *
 * 
 * PARAM1: int iface
 * PARAM2: int (*routine)(int
 * PARAM3: int
 *
 * RETURNS: 
 */

void
dhc_set_callback(int iface, int (*routine)(int,int) )
{
   dhc_states[iface].callback = routine;
}



/* FUNCTION: dhc_upcall()
 *
 * dhc_upcall() - DHCP client UDP callback. Called from stack 
 * whenever we get a bootp (or DHCP) reply. Returns 0 or error code. 
 * . 
 * 
 * PARAM1: PACKET pkt
 * PARAM2: void * data
 *
 * RETURNS: If the processing was sucessfull, the packet is freed and 0 is 
 * returned. Otherwise the packet is NOT free'ed and an error code is 
 * returned
 */

int
dhc_upcall(PACKET pkt, void * data)
{
   struct bootp * bp;
   int      len      =  pkt->nb_plen;  /* len of UDP data - the bootp/dhcp struct */
   int      dhcptype =  0;    /* DHCP type - not valid if bootp */
   int      e;
   int      iface;
   u_char * opts;          /* scratch options pointer */

   if (data != DHCPDATA)
   {
      dtrap("dhcpclnt 0\n");
      return ENP_LOGIC;    /* internal logic error */
   }

   /* punt if packet didn't come in a net we sent on */
   iface = net_num(pkt->net);
   if (dhc_states[iface].state == DHCS_UNUSED)
      return ENP_NOT_MINE;

   bp = (struct bootp *)pkt->nb_prot;

   /*   Validate various fields   */
   if ((len < (sizeof(struct bootp)-BOOTP_OPTSIZE) ) || 
       (bp->op != BOOTREPLY) ||
       (*(u_long*)(&bp->options) != RFC1084_MAGIC_COOKIE))
   {
      dtrap("dhcpclnt 1\n");
      dsc_errors++;
      return ENP_NOT_MINE;
   }

   /* punt offers or replys which are not for me */
   if(MEMCMP(bp->chaddr, pkt->net->n_haddr, pkt->net->n_hal))
      return ENP_NOT_MINE;    /* not an error, just ignore it */

   /* see if it's full DHCP or plain bootp by looking for dhcp type option */
   opts = find_opt(DHOP_TYPE ,&bp->options[4]);
   if (opts && *opts == DHOP_TYPE)
   {
      dhcptype = *(opts+2);
      bp->op |= ISDHCP;       /* tag packet for isdhcp() macro */
   }

   if (isdhcp(bp))
   {
      switch (dhcptype)
      {
      case DHCP_DISCOVER:
      case DHCP_REQUEST:
      case DHCP_DECLINE:
      case DHCP_RELEASE:
         dsc_errors++;     /* these should only be upcalled to a server */
         return ENP_NOT_MINE;
      }

      switch (dhc_states[iface].state)
      {
      case DHCS_INIT:
      case DHCS_INITREBOOT:
         /* How can we receive any response when we never sent one */
      case DHCS_BOUND:
         /* If there are multiple DHCP Servers, and one of them is slow
            in responding, we might get OFFER pkts when are in BOUND state */
         dsc_errors++;     /* these should only be upcalled to a server */
         return ENP_NOT_MINE;
      case DHCS_SELECTING:
         /* We will respond to the first offer packet that we receive ) */
         if ( dhcptype == DHCP_OFFER ) /* got offer back from server */
         {
            dsc_offers++;
            dhc_states[iface].srv_ipaddr = dhc_get_srv_ipaddr(&bp->options[4]);
            if (dhc_states[iface].srv_ipaddr == 0 )
            {
               dtrap("dhcpclnt 2\n"); /* didn't receive server-identifier option */
               dsc_errors++;
               dhc_states[iface].srv_ipaddr = pkt->fhost;   /* Try using fhost */
            }

            if (bp->hops)
            {
               /* OFFER is received via DHCP Relay Agent. Remember the
                * IP addr of DHCP Relay Agent, so that packets from other
                * DHCP Relay Agents can be discarded 
                */
               dhc_states[iface].rly_ipaddr = pkt->fhost;   /* Try using fhost */
            }
            else
               dhc_states[iface].rly_ipaddr = 0;

            e = dhc_rx_offer(iface,bp,pkt->nb_plen);     /* send request */
            if (e)
            {
               dsc_errors++;
               dhc_set_state(iface,DHCS_INIT);
               dtrap("dhcpclnt 3\n");
               return ENP_NOT_MINE;
            }
            else
               dhc_set_state(iface,DHCS_REQUESTING);
         }
         else
         {
            /* We can't receive any other packet in this state. 
             * Report an error and remain in SELECTING state, so that 
             * an OFFER packet from another DHCP server can be 
             * accepted. If we timeout waiting for a OFFER packet, 
             * then dhc_second() will transition to DHCS_INIT state. 
             */
            dsc_errors++;
            if ( dhcptype == DHCP_NAK ) 
               dsc_naks++;
            return ENP_NOT_MINE;
         }
      break;
      case DHCS_REQUESTING:
      case DHCS_REBINDING:
      case DHCS_RENEWING:
         /* If the ACK/NACK is not from the same server which sent 
          * the OFFER packet, then discard it. in DHCS_REBOOTING 
          * state, srv_ipaddr is 0. Hence don't check in that state 
          */
         if ( dhc_states[iface].srv_ipaddr != 
             dhc_get_srv_ipaddr(&bp->options[4]) )
         {
            dsc_errors++;
            return ENP_NOT_MINE;
         }
         if (dhc_states[iface].rly_ipaddr &&
            (dhc_states[iface].rly_ipaddr != pkt->fhost))
         {
            dsc_rlyerrs++;
            dsc_errors++;
            return ENP_NOT_MINE;
         }
      case DHCS_REBOOTING:
         if ( dhcptype == DHCP_ACK )   /* Server OKed our request */
         {
            dsc_acks++;
            dhc_extract_opts(iface,&bp->options[4]);
            if ( dhc_states[iface].lease == DHC_INFINITY )
            {
               dhc_states[iface].t1 = DHC_INFINITY ;
               dhc_states[iface].t2 = DHC_INFINITY ;
            }
            else
            {
               dhc_states[iface].t1 = dhc_states[iface].lease/2     ;
               dhc_states[iface].t2 = (dhc_states[iface].lease/8)*7 ;
            }
            dhc_states[iface].lease_start = cticks;   /* to calc lease expiry */
            dhc_states[iface].srv_ipaddr = dhc_get_srv_ipaddr(&bp->options[4]); 
            if (dhc_states[iface].srv_ipaddr == 0 )
            {
               dtrap("dhcpclnt 4\n"); /* didn't receive server-identifier option */
               dsc_errors++;
               dhc_states[iface].srv_ipaddr = pkt->fhost;   /* Try using fhost */
            }
            if (bp->hops)
            {
               /* OFFER is received via DHCP Relay Agent. Remember the
                * IP addr of DHCP Relay Agent, so that packets from other
                * DHCP Relay Agents can be discarded 
                */
               dhc_states[iface].rly_ipaddr = pkt->fhost;   /* Try using fhost */
            }
            else
               dhc_states[iface].rly_ipaddr = 0;

            dhc_setip(iface);
            dhc_set_state(iface,DHCS_BOUND);
         }
         else if ( dhcptype == DHCP_NAK ) /* Server denied our request */
         {
            dhc_set_state(iface,DHCS_INIT);
            dsc_naks++;
         }
         else
         {
            /* We can't receive any other packet in this state.
               Revert to INIT state. */
            dsc_errors++;
            dhc_set_state(iface,DHCS_INIT);
            dtrap("dhcpclnt 5\n");
            return ENP_NOT_MINE;
         }
      break;
         default:    /* bad state */
         dtrap("dhcpclnt 6\n");
         dhc_set_state(iface,DHCS_INIT);
         dsc_errors++;
         return -1;
      }
   }
   else     /* plain bootp reply */
   {
      dsc_bpreplys++;
      dhc_extract_opts(iface,&bp->options[4]);
      dhc_states[iface].ipaddr = bp->yiaddr;
      dhc_setip(iface);

      /* Set values so that DHCP State Machine remains happy */
      dhc_set_state(iface,DHCS_BOUND);
      dhc_states[iface].t1    = DHC_INFINITY ;
   }

   udp_free(pkt);
   return 0;
}


/* FUNCTION: dhc_buildheader()
 *
 * dhc_buildheader() - build BOOTP request header 
 *
 * 
 * PARAM1: int iface
 * PARAM2: struct bootp * outbp
 *
 * RETURNS: Returns 0 on success, else an ENP_ error code. 
 */

int
dhc_buildheader(int iface, struct bootp * outbp)
{
   int   addrlen;    /* length of hardware address */

   MEMSET(outbp, 0, sizeof(struct bootp));   /* most of this is 0 anyway */
   outbp->op = BOOTREQUEST;

   /* map SNMPish hardware types into bootp types */
   switch (nets[iface]->n_mib->ifType)
   {
   case ETHERNET:       /* ETHERNET defined in net.h */
      outbp->htype = ETHHWTYPE;  /* defined in dhcp.h */
   break;
   case PPP:
   case SLIP:
      outbp->htype = LINEHWTYPE;    /* line type for PPP or SLIP */
   break;
      default:
      dtrap("dhcpclnt 7\n");
      return ENP_LOGIC;             /* this shouldn't happen */
   }

   addrlen = min(16, nets[iface]->n_hal);
   outbp->hlen = (u_char)addrlen;
   outbp->hops = 0;
   if(dhc_states[iface].state == DHCS_RENEWING) 
      outbp->flags = 0; /* Renewing needs unicast */
   else
      outbp->flags = htons(DHC_BCASTFLAG); /* Othwise broadcast */
   outbp->xid = dhc_states[iface].xid;
   outbp->secs = dhc_states[iface].secs;
#ifdef NPDEBUG
   /* make sure net[] has a MAC address, even if length is zero */
   if(nets[iface]->n_haddr == NULL)
   {
      dtrap("dhcpclnt 8\n");
      return ENP_LOGIC;
   }
#endif
   MEMCPY(outbp->chaddr, nets[iface]->n_haddr, addrlen);

   /* return success */
   return 0;
}

unsigned long sysuptime(void);


/* FUNCTION: dhc_discover()
 *
 * dhc_discover() - Send initial DHCP discovery packet for the passed 
 * interface. 
 *

⌨️ 快捷键说明

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