RTEMS BOOTP and Linksys routers

Joel Sherrill <joel@OARcorp.com> joel.sherrill at OARcorp.com
Thu Apr 28 13:56:29 UTC 2005


Chris Johns wrote:
> Joel Sherrill <joel at OARcorp.com> wrote:
> 
>>
>> I am not familiar with the protocol but it may be as simple as spawning
>> a background task to wakeup periodically and do some subset of the 
>> actions done during bootpc_init.
>>
> 
> We found some dhcp code on the RTEMS list provided by Andrew Bythell, 
> and changed it to add a task to renew the lease.

Chris.. why don't you merge this?


> Warning, the code will not rebind if the lease if not returned.
> 
> Enjoy.
> 
> 
> ------------------------------------------------------------------------
> 
> /*
>   ------------------------------------------------------------------------
>   $Id: dhcp.h,v 1.1 2005/04/21 02:44:01 cjohns Exp $
>   ------------------------------------------------------------------------
> 
>   Copyright Cybertec Pty Ltd, 2005
>   All rights reserved Cybertec Pty Ltd, 2005
>     
>   This software with is provided ``as is'' and with NO WARRANTY.
> 
>   ------------------------------------------------------------------------
>  */
> 
> /**
>   @file
> 
>   DHCP Server interface.
> */
> 
> #if !defined (__RTEMS_DHCP_H__)
> #define __RTEMS_DHCP_H__
> 
> #if __cplusplus
> extern "C"
> {
> #endif
> 
> /*
>  * Perform DHCP.
>  */
> void rtems_bsdnet_do_dhcp (void);
> 
> /*
>  * Maintain a DHCP offer that has already been accepted.
>  */
> void rtems_bsdnet_do_dhcp_refresh_only (unsigned long xid,
>                                         unsigned long lease_time,
>                                         unsigned long elapsed_time,
>                                         unsigned long ip_address,
>                                         unsigned long srv_address);
> 
> #if __cplusplus
> }
> #endif
> 
> #endif
> 
> 
> ------------------------------------------------------------------------
> 
> /*	
>  *  DCHP client for RTEMS 
>  *  Andrew Bythell, <abythell at nortelnetworks.com>
>  *  based on and uses subroutines from c/src/libnetworking/nfs/bootp_subr.c
>  */
> 
> /*
>  * DHCP task added.
>  * Brendan Gannon, <bgannon at cybertec.com.au>
>  */
> 
> /*
>  * Copyright (c) 1995 Gordon Ross, Adam Glass
>  * Copyright (c) 1992 Regents of the University of California.
>  * All rights reserved.
>  *
>  * This software was developed by the Computer Systems Engineering group
>  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
>  * contributed to Berkeley.
>  *
>  * Redistribution and use in source and binary forms, with or without
>  * modification, are permitted provided that the following conditions
>  * are met:
>  * 1. Redistributions of source code must retain the above copyright
>  *    notice, this list of conditions and the following disclaimer.
>  * 2. Redistributions in binary form must reproduce the above copyright
>  *    notice, this list of conditions and the following disclaimer in the
>  *    documentation and/or other materials provided with the distribution.
>  * 3. All advertising materials mentioning features or use of this software
>  *    must display the following acknowledgement:
>  *	This product includes software developed by the University of
>  *	California, Lawrence Berkeley Laboratory and its contributors.
>  * 4. Neither the name of the University nor the names of its contributors
>  *    may be used to endorse or promote products derived from this software
>  *    without specific prior written permission.
>  *
>  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
>  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
>  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
>  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
>  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
>  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
>  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
>  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
>  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
>  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
>  * SUCH DAMAGE.
>  *
>  */
> 
> /*
>  * WARNING:
>  *   This file should be moved into c/src/libnetworking/nfs
>  *   and the following two #ifndef...#endif blocks and the #undefs at
>  *   the end of the file should be removed
>  */
> 
> #ifndef _COMPILING_BSD_KERNEL_
> #define _COMPILING_BSD_KERNEL_
> #endif
> 
> #ifndef KERNEL
> #define KERNEL
> #endif
> 
> #include <string.h>
> 
> #include <sys/param.h>		/* for MAXHOSTNAMELEN */
> #include <sys/systm.h>
> #include <sys/socketvar.h>	/* for socreat() soclose() */
> #include <sys/socket.h>
> 
> #include <net/if.h>
> #include <netinet/in.h>		/* for NBO-HBO conversions */
> #include <net/if_types.h>	/* for IFT_ETHER */
> #include <net/if_dl.h>		/* for LLADDR */
> 
> #include <sys/stat.h>
> #include <sys/types.h>
> #include <fcntl.h>
> #include <rtems/mkrootfs.h>
> #include <rtems/rtems_bsdnet.h>
> 
> #include "rtems/dhcp.h"
> 
> #ifndef EALEN
> #define EALEN 6
> #endif
> 
> /* DHCP flags */
> #define DHCP_BROADCAST 0x8000
> #define DHCP_UNICAST   0x0000
> 
> /* DHCP Op Codes */
> #define DHCP_BOOTREQUEST 1
> #define DHCP_BOOTREPLY   2
> 
> /* DHCP Messages */
> #define DHCP_DISCOVER 1
> #define DHCP_OFFER    2
> #define DHCP_REQUEST  3
> #define DHCP_DECLINE  4
> #define DHCP_ACK      5
> #define DHCP_NACK     6
> #define DHCP_RELEASE  7
> 
> /* DHCP Options */
> #define DHCP_MAGIC_COOKIE "99.130.83.99"
> #define DHCP_OPTION_PAD    0
> #define DHCP_SUBNET        1
> #define DHCP_GATEWAY       3
> #define DHCP_DNS           6
> #define DHCP_HOST          12
> #define DHCP_DOMAIN_NAME   15
> #define DHCP_NETMASK       28
> #define DHCP_REQUESTED_IP  50
> #define DHCP_LEASE         51
> #define DHCP_MESSAGE       53
> #define DHCP_SERVER        54
> #define DHCP_PARAMETERS    55
> #define DHCP_OPTION_END    255
> 
> /* Definitions from RFC */
> struct dhcp_packet
> {
>   u_int8_t op;
>   u_int8_t htype;
>   u_int8_t hlen;
>   u_int8_t hops;
>   u_int32_t xid;
>   u_int16_t secs;
>   u_int16_t flags;
>   struct in_addr ciaddr;
>   struct in_addr yiaddr;
>   struct in_addr siaddr;
>   struct in_addr giaddr;
>   unsigned char chaddr[16];
>   char sname[64];
>   char file[128];
>   unsigned char vend[312];
> };
> 
> /* 
>  * External Declarations for Functions found in
>  * rtems/c/src/libnetworking/nfs/
>  */
> extern int bootpc_call (struct dhcp_packet *call,
> 			struct dhcp_packet *reply, struct proc *procp);
> extern int bootpc_fakeup_interface (struct ifreq *ireq, struct socket *so,
> 				    struct proc *procp);
> extern int
> bootpc_adjust_interface (struct ifreq *ireq, struct socket *so,
> 			 struct sockaddr_in *myaddr,
> 			 struct sockaddr_in *netmask,
> 			 struct sockaddr_in *gw, struct proc *procp);
> extern int nfs_diskless_valid;
> 
> /* Variables */
> static int dhcpOptionOverload = 0;
> static char dhcp_gotgw = 0;
> static char dhcp_gotnetmask = 0;
> static char dhcp_gotserver = 0;
> static char dhcp_gotlogserver = 0;
> static struct sockaddr_in dhcp_netmask;
> static struct sockaddr_in dhcp_gw;
> static char *dhcp_hostname;
> static int dhcpMessageType = 0;
> static unsigned long dhcp_lease_time;
> static unsigned long dhcp_elapsed_time = 0;
> static const char dhcp_magic_cookie[4] = { 99, 130, 83, 99 };
> static const char dhcpRequestParameters[5] = { DHCP_SUBNET, DHCP_GATEWAY,
>                                                DHCP_DNS, DHCP_HOST, DHCP_DOMAIN_NAME};
> 
> /*******************************************************************************
> *
> *   Print formatted IP Addresses 
> *    Same as bootpc but re-declared because of scope
> *
> *******************************************************************************/
> static void
> printsetup (const char* iface, struct in_addr ip_addr, struct in_addr mask_addr,
>             struct in_addr srv_addr, struct in_addr gw_addr)
> {
>   unsigned long ip;
> 
>   printf ("dhcpc: %s: ", iface);
>   
>   ip = ntohl (ip_addr.s_addr);
>   printf ("inet: %d.%d.%d.%d ", ip >> 24, (ip >> 16) & 0xff,
>           (ip >> 8) & 0xff, ip & 0xff);
> 
>   ip = ntohl (mask_addr.s_addr);
>   printf ("mask: %d.%d.%d.%d\n", ip >> 24, (ip >> 16) & 0xff,
>           (ip >> 8) & 0xff, ip & 0xff);
> 
>   ip = ntohl (srv_addr.s_addr);
>   printf ("             srv: %d.%d.%d.%d ", ip >> 24, (ip >> 16) & 0xff,
>           (ip >> 8) & 0xff, ip & 0xff);
> 
>   ip = ntohl (gw_addr.s_addr);
>   printf ("gw: %d.%d.%d.%d\n", ip >> 24, (ip >> 16) & 0xff,
>           (ip >> 8) & 0xff, ip & 0xff);
> 
>   return;
> }
> 
> 
> /*******************************************************************************
> *
> *  Process DCHP Options 
> *    Same as bootpc, with some extra handling for DHCP options
> *
> *******************************************************************************/
> static void
> processOptions (unsigned char *optbuf, int optbufSize)
> {
>   int j = 0;
>   int len;
>   int code, ncode;
>   char *p;
> 
>   ncode = optbuf[0];
>   while (j < optbufSize)
>   {
>     code = optbuf[j] = ncode;
>     if (code == 255)
>       return;
>     if (code == 0)
>     {
>       j++;
>       continue;
>     }
>     len = optbuf[j + 1];
>     j += 2;
>     
>     if ((len + j) >= optbufSize)
>     {
>       printf ("Truncated field for code %d", code);
>       return;
>     }
>     
>     ncode = optbuf[j + len];
>     optbuf[j + len] = '\0';
>     p = &optbuf[j];
>     j += len;
> 
>     /*
>      * Process the option
>      */
>     switch (code)
>     {
>       case 1:
>         /* Subnet mask */
>         if (len != 4)
>           panic ("dhcpc: subnet mask len is %d", len);
>         memcpy (&dhcp_netmask.sin_addr, p, 4);
>         dhcp_gotnetmask = 1;
>         break;
> 
>       case 2:
>         /* Time offset */
>         if (len != 4)
>           panic ("dhcpc: time offset len is %d", len);
>         memcpy (&rtems_bsdnet_timeoffset, p, 4);
>         rtems_bsdnet_timeoffset = ntohl (rtems_bsdnet_timeoffset);
>         break;
> 
>       case 3:
>         /* Routers */
>         if (len % 4)
>           panic ("dhcpc: Router Len is %d", len);
>         if (len > 0)
>         {
>           memcpy (&dhcp_gw.sin_addr, p, 4);
>           dhcp_gotgw = 1;
>         }
>         break;
> 
>       case 42:
>         /* NTP servers */
>         if (len % 4)
>           panic ("dhcpc: time server Len is %d", len);
>         {
>           int tlen = 0;
>           while ((tlen < len) &&
>                  (rtems_bsdnet_ntpserver_count <
>                   sizeof rtems_bsdnet_config.ntp_server /
>                   sizeof rtems_bsdnet_config.ntp_server[0]))
>           {
>             memcpy (&rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count],
>                     p + tlen, 4);
>             rtems_bsdnet_ntpserver_count++;
>             tlen += 4;
>           }
>         }
>         break;
> 
>       case 6:
>         /* Domain Name servers */
>         if (len % 4)
>           panic ("dhcpc: DNS Len is %d", len);
>         {
>           int dlen = 0;
>           while ((dlen < len) &&
>                  (rtems_bsdnet_nameserver_count <
>                   sizeof rtems_bsdnet_config.name_server /
>                   sizeof rtems_bsdnet_config.name_server[0]))
>           {
>             memcpy (&rtems_bsdnet_nameserver
>                     [rtems_bsdnet_nameserver_count], p + dlen, 4);
>             rtems_bsdnet_nameserver_count++;
>             dlen += 4;
>           }
>         }
>         break;
> 
>       case 12:
>         /* Host name */
>         if (len >= MAXHOSTNAMELEN)
>           panic ("dhcpc: hostname >=%d bytes", MAXHOSTNAMELEN);
>         if (sethostname (p, len) < 0)
>           panic ("Can't set host name");
>         dhcp_hostname = bootp_strdup_realloc(dhcp_hostname,p);
>         break;
> 
>       case 7:
>         /* Log servers */
>         if (len % 4)
>           panic ("dhcpc: Log server Len is %d", len);
>         if (len > 0)
>         {
>           memcpy (&rtems_bsdnet_log_host_address, p, 4);
>           dhcp_gotlogserver = 1;
>         }
>         break;
> 
>       case 15:
>         /* Domain name */
>         if (p[0])
>         {
>           rtems_bsdnet_domain_name = strdup (p);
>         }
>         break;
> 
>       case 16:		/* Swap server IP address. unused */
>         break;
> 
>       case 50:
>         /* DHCP Requested IP Address */
>         if (len != 4)
>           panic ("dhcpc: DHCP option requested IP len is %d", len);
>         /* 
>          * although nothing happens here, this case keeps the client
>          * from complaining about unknown options.  The Requested IP
>          * is necessary to return to the server for a DHCP REQUEST
>          */
>         break;
> 
>       case 51:
>         /* DHCP Lease Length */
>         if (len != 4)
>           panic ("DHCP option Lease-Length len is %d", len);
>         memcpy (&dhcp_lease_time, &p[0], 4);
>         dhcp_lease_time = ntohl (dhcp_lease_time);
>         break;
>         
>       case 52:
>         /* DHCP option override */
>         if (len != 1)
>           panic ("dhcpc: DHCP option overload len is %d", len);
>         dhcpOptionOverload = p[0];
>         break;
> 
>       case 53:
>         /* DHCP message */
>         if (len != 1)
>           panic ("dhcpc: DHCP message len is %d", len);
>         dhcpMessageType = p[0];
>         break;
> 
>       case 128:		/* Site-specific option for DHCP servers that 
>                    *   a) don't supply tag 54
>                    * and
>                    *   b) don't supply the server address in siaddr
>                    * For example, on Solaris 2.6 in.dhcpd, include in the dhcptab:
>                    *    Bootsrv s Site,128,IP,1,1
>                    * and use that symbol in the macro that defines the client:
>                    *    Bootsrv=<tftp-server-ip-address>
>                    */
>       case 54:
>         /* DHCP server */
>         if (len != 4)
>           panic ("dhcpc: DHCP server len is %d", len);
>         memcpy (&rtems_bsdnet_bootp_server_address, p, 4);
>         dhcp_gotserver = 1;
>         break;
> 
>       case 66:
>         /* DHCP server name option */
>         if (p[0])
>           rtems_bsdnet_bootp_server_name = strdup (p);
>         break;
> 
>       case 67:
>         /* DHCP bootfile option */
>         if (p[0])
>           rtems_bsdnet_bootp_boot_file_name = strdup (p);
>         break;
> 
>       default:
>         break;
>     }
>   }
> }
> 
> static int
> dhcp_discover_req (struct dhcp_packet* call, struct sockaddr_dl *sdl,
>                    unsigned long *xid)
> {
>   int len = 0;
>   
>   memset (call, 0, sizeof (struct dhcp_packet));
> 
>   /*
>    * Send a DHCP DISCOVER Message
>    */
>   call->op = DHCP_BOOTREQUEST;
>   call->htype = 1;		/* 10mb ethernet */
>   call->hlen = sdl->sdl_alen;	/* Hardware address length */
>   call->hops = 0;
>   (*xid)++;
>   call->xid = htonl (*xid);
>   call->flags = htons (DHCP_BROADCAST);
>   
>   memcpy (&call->chaddr, LLADDR (sdl), sdl->sdl_alen);
> 
>   /*
>    * Magic cookie.
>    */
>   memcpy (&call->vend[len], dhcp_magic_cookie, sizeof (dhcp_magic_cookie));
>   len += sizeof (dhcp_magic_cookie);
> 
>   /*
>    * DHCP Message type.
>    */
>   call->vend[len++] = DHCP_MESSAGE;
>   call->vend[len++] = 1;
>   call->vend[len++] = DHCP_DISCOVER;
> 
>   /*
>    * DHCP Parameter request list
>    */
>   call->vend[len++] = DHCP_PARAMETERS;
>   call->vend[len++] = sizeof (dhcpRequestParameters);
>   memcpy (&call->vend[len], &dhcpRequestParameters, sizeof (dhcpRequestParameters));
>   len += sizeof (dhcpRequestParameters);
> 
>   /*
>    * Lease time.
>    */
>   call->vend[len++] = DHCP_LEASE;
>   call->vend[len++] = 4;
>   memset (&call->vend[len], 0xFF, 4);	/* request infinite lease time */
>   len += 4;
> 
>   /*
>    * End.
>    */
>   call->vend[len++] = DHCP_OPTION_END;
>   call->secs = 0;
> 
>   return len;
> }
> 
> static int
> dhcp_request_req (struct dhcp_packet* call, struct dhcp_packet* reply,
>                   struct sockaddr_dl *sdl, int broadcast)
> {
>   int len = 0;
>   
>   memset (call, 0, sizeof (struct dhcp_packet));
> 
>   /*
>    * Send a DHCP REQUEST Message
>    */
>   call->op = DHCP_BOOTREQUEST;
>   call->htype = 1;		/* 10mb ethernet */
>   call->hlen = sdl->sdl_alen;	/* Hardware address length */
>   call->hops = 0;
>   call->xid = htonl (reply->xid);
>   if (broadcast)
>     call->flags = htons (DHCP_BROADCAST);
>   else
>   {
>     call->flags = htons (DHCP_UNICAST);
>     call->ciaddr = htonl (reply->yiaddr);
>   }
>   memcpy (&call->chaddr, LLADDR (sdl), sdl->sdl_alen);
> 
>   /*
>    * Magic cookie.
>    */
>   memcpy (&call->vend[len], dhcp_magic_cookie, sizeof (dhcp_magic_cookie));
>   len += sizeof (dhcp_magic_cookie);
> 
>   /*
>    * DHCP Message type.
>    */
>   call->vend[len++] = DHCP_MESSAGE;
>   call->vend[len++] = 1;
>   call->vend[len++] = DHCP_REQUEST;
> 
>   /*
>    * DHCP server
>    */
>   if (broadcast)
>   {
>     call->vend[len++] = DHCP_SERVER;
>     call->vend[len++] = sizeof (rtems_bsdnet_bootp_server_address);
>     memcpy (&call->vend[len], &rtems_bsdnet_bootp_server_address,
>             sizeof (rtems_bsdnet_bootp_server_address));
>     len += sizeof (rtems_bsdnet_bootp_server_address);
>   }
> 
>   /*
>    * Requested IP
>    */
>   call->vend[len++] = DHCP_REQUESTED_IP;
>   call->vend[len++] = sizeof (reply->yiaddr);
>   memcpy (&call->vend[len], &reply->yiaddr, sizeof (reply->yiaddr));
>   len += sizeof (reply->yiaddr);
>   
>   /*
>    * DHCP Parameter request list
>    */
>   call->vend[len++] = DHCP_PARAMETERS;
>   call->vend[len++] = sizeof (dhcpRequestParameters);
>   memcpy (&call->vend[len], &dhcpRequestParameters, sizeof (dhcpRequestParameters));
>   len += sizeof (dhcpRequestParameters);
> 
>   /*
>    * Lease time.
>    */
>   call->vend[len++] = DHCP_LEASE;
>   call->vend[len++] = 4;
>   memset (&call->vend[len], 0xFF, 4);	/* request infinite lease time */
>   len += 4;
> 
>   /*
>    * End.
>    */
>   call->vend[len++] = DHCP_OPTION_END;
>   call->secs = 0;
> 
>   return len;
> }
> 
> static struct dhcp_packet dhcp_req;
> static rtems_id dhcp_task_id;
> 
> static void
> dhcp_task (rtems_task_argument _sdl)
> {
>   unsigned long       count;
>   struct dhcp_packet  call;
>   struct sockaddr_dl  *sdl;
>   rtems_event_set     event_out;
>   unsigned int        timeout = 0;
>   int                 error;
>   struct proc *procp = NULL;
>   
>   sdl = (struct sockaddr_dl *) _sdl;
>   
>   count = dhcp_elapsed_time;
>   
>   while (TRUE)
>   {
>     if (count >= (dhcp_lease_time / 2))
>     {
>       rtems_bsdnet_semaphore_obtain ();
>       
>       dhcp_request_req (&call, &dhcp_req, sdl, TRUE);
> 
>       /*
>        * Send the Request.
>        */
>       error = bootpc_call (&call, &dhcp_req, procp);
>       
>       if (error)
>         panic ("BOOTP call failed -- error %d", error);
>       
>       /*
>        * Check for DHCP ACK/NACK
>        */
>       if (memcmp (&dhcp_req.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0)
>       {
>         rtems_bsdnet_semaphore_release ();
>         panic ("DHCP server did not send Magic Cookie.\n");
>       }
>   
>       processOptions (&dhcp_req.vend[4], sizeof (dhcp_req.vend) - 4);
>   
>       if (dhcpMessageType != DHCP_ACK)
>       {
>         rtems_bsdnet_semaphore_release (); 
>         panic ("DHCP server did not accept the DHCP request");
>       }
>       
>       rtems_bsdnet_semaphore_release ();
>       count = 0;
>     }
> 
>     /*
>      * Sleep until the next poll
>      */
>     timeout = TOD_MILLISECONDS_TO_TICKS (1000);
>     rtems_event_receive (RTEMS_EVENT_0,
>                          RTEMS_WAIT | RTEMS_EVENT_ANY,
>                          timeout, &event_out);
>     count++;
>   }
> }
> 
> static rtems_status_code
> dhcp_start_task (struct sockaddr_dl *sdl, struct dhcp_packet *reply, int priority)
> {
>   rtems_status_code sc;
>   
>   memcpy (&dhcp_req, reply, sizeof (struct dhcp_packet));
> 
>   sc = rtems_task_create (rtems_build_name ('d','h','c','p'),
>                           priority,
>                           2048,
>                           RTEMS_PREEMPT |
>                           RTEMS_NO_TIMESLICE |
>                           RTEMS_NO_ASR |
>                           RTEMS_INTERRUPT_LEVEL (0),
>                           RTEMS_LOCAL,
>                           &dhcp_task_id);
> 
>   if (sc != RTEMS_SUCCESSFUL)
>     return sc;
> 
>   sc = rtems_task_start (dhcp_task_id,
>                          dhcp_task,
>                          (rtems_task_argument) sdl);
> 
>   if (sc != RTEMS_SUCCESSFUL)
>     return sc;
> 
>   return RTEMS_SUCCESSFUL;
> }
>   
> /*******************************************************************************
> *
> *  DCHP Client Routine 
> *    - This routine does not yet handle renewing or releasing leases.
> *    - The first DHCP offer is always accepted
> *    - No DHCP DECLINE message is sent if ARPing fails
> *
> *******************************************************************************/
> void
> dhcp_init (int update_files)
> {
>   struct dhcp_packet call;
>   struct dhcp_packet reply;
>   static unsigned long xid = ~0xFF;
>   struct ifreq ireq;
>   struct ifnet *ifp;
>   struct socket *so;
>   int len;
>   int error;
>   struct sockaddr_in myaddr;
>   struct ifaddr *ifa;
>   struct sockaddr_dl *sdl = NULL;
>   struct proc *procp = NULL;
>   
>   /*
>    * If already filled in, don't touch it here 
>    */
>   if (nfs_diskless_valid)
>     return;
> 
>   /*
>    * If we are to update the files create the root
>    * file structure.
>    */
>   if (update_files)
>     if (rtems_create_root_fs () < 0) {
>       printf("Error creating the root filesystem.\nFile not created.\n");
>       update_files = 0;
>     }
>   
>   /*
>    * Find a network interface.
>    */
>   for (ifp = ifnet; ifp != 0; ifp = ifp->if_next)
>     if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0)
>       break;
>   if (ifp == NULL)
>     panic ("dhcpc_init: no suitable interface");
>   memset (&ireq, 0, sizeof (ireq));
>   sprintf (ireq.ifr_name, "%s%d", ifp->if_name, ifp->if_unit);
> 
>   if ((error = socreate (AF_INET, &so, SOCK_DGRAM, 0, procp)) != 0)
>     panic ("nfs_boot: socreate, error=%d", error);
> 
> //  bootpc_fakeup_interface (&ireq, so, procp);
> 
>   /* Get HW address */
> 
>   for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
>     if (ifa->ifa_addr->sa_family == AF_LINK &&
>         (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) &&
>         sdl->sdl_type == IFT_ETHER)
>       break;
> 
>   if (!sdl)
>     panic ("dhcpc: Unable to find HW address");
>   if (sdl->sdl_alen != EALEN)
>     panic ("dhcpc: HW address len is %d, expected value is %d",
>            sdl->sdl_alen, EALEN);
> 
>   /*
>    * Build the DHCP Discover
>    */
>   len = dhcp_discover_req (&call, sdl, &xid);
> 
>   /*
>    * Send the Discover.
>    */
>   error = bootpc_call (&call, &reply, procp);
>   if (error)
>     panic ("BOOTP call failed -- error %d", error);
> 
>   /*
>    * Check for DHCP OFFER
>    */
>   
>   if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0)
>     panic ("DHCP server did not send Magic Cookie.\n");
> 
>   processOptions (&reply.vend[4], sizeof (reply.vend) - 4);
>   
>   if (dhcpMessageType != DHCP_OFFER)
>     panic ("DHCP server did not send a DHCP Offer.\n");
> 
>   /*
>    * Send a DHCP REQUEST 
>    */
>   dhcp_request_req (&call, &reply, sdl, TRUE);
>   
>   error = bootpc_call (&call, &reply, procp);
>   if (error)
>     panic ("BOOTP call failed -- error %d", error);
> 
>   /*
>    * Check for DHCP ACK/NACK
>    */
>   if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0)
>     panic ("DHCP server did not send Magic Cookie.\n");
>   
>   processOptions (&reply.vend[4], sizeof (reply.vend) - 4);
>   
>   if (dhcpMessageType != DHCP_ACK)
>     panic ("DHCP server did not accept the DHCP request");
> 
>   /*
>    * Initialize network address structures
>    */
>   memset (&myaddr, 0, sizeof (myaddr));
>   memset (&dhcp_netmask, 0, sizeof (dhcp_netmask));
>   memset (&dhcp_gw, 0, sizeof (dhcp_gw));
>   myaddr.sin_len = sizeof (myaddr);
>   myaddr.sin_family = AF_INET;
>   dhcp_netmask.sin_len = sizeof (dhcp_netmask);
>   dhcp_netmask.sin_family = AF_INET;
>   dhcp_gw.sin_len = sizeof (dhcp_gw);
>   dhcp_gw.sin_family = AF_INET;
> 
>   /*
>    * Set our address
>    */
>   myaddr.sin_addr = reply.yiaddr;
> 
>   /*
>    * Process BOOTP/DHCP options
>    */
>   if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) == 0)
>     processOptions (&reply.vend[4], sizeof (reply.vend) - 4);
>   
>   if (dhcpOptionOverload & 1)
>     processOptions (reply.file, sizeof reply.file);
>   else
>     if (reply.file[0])
>       rtems_bsdnet_bootp_boot_file_name = strdup (reply.file);
>   
>   if (dhcpOptionOverload & 2)
>     processOptions (reply.sname, sizeof reply.sname);
>   else
>     if (reply.sname[0])
>       rtems_bsdnet_bootp_server_name = strdup (reply.sname);
> 
>   /*
>    * Use defaults if values were not supplied by BOOTP/DHCP options
>    */
>   if (!dhcp_gotnetmask)
>   {
>     if (IN_CLASSA (ntohl (myaddr.sin_addr.s_addr)))
>       dhcp_netmask.sin_addr.s_addr = htonl (IN_CLASSA_NET);
>     else if (IN_CLASSB (ntohl (myaddr.sin_addr.s_addr)))
>       dhcp_netmask.sin_addr.s_addr = htonl (IN_CLASSB_NET);
>     else
>       dhcp_netmask.sin_addr.s_addr = htonl (IN_CLASSC_NET);
>   }
>   
>   if (!dhcp_gotserver)
>     rtems_bsdnet_bootp_server_address = reply.siaddr;
>   
>   if (!dhcp_gotgw)
>     dhcp_gw.sin_addr = reply.giaddr;
>   
>   if (!dhcp_gotlogserver)
>     rtems_bsdnet_log_host_address = rtems_bsdnet_bootp_server_address;
> 
>   printsetup (ifp->if_name, myaddr.sin_addr, dhcp_netmask.sin_addr,
>               rtems_bsdnet_bootp_server_address, dhcp_gw.sin_addr);
> 
>   /*
>    * Update the files if we are asked too.
>    */
>   if (update_files) {
>     char *dn = rtems_bsdnet_domain_name;
>     char *hn = dhcp_hostname;
>     if (!dn)
>       dn = "mydomain";
>     if (!hn)
>     {
>       hn = "me";
>       sethostname (hn, strlen (hn));
>     }
>     rtems_rootfs_append_host_rec(*((unsigned long*) &myaddr.sin_addr), hn, dn);
> 
>     /*
>      * Should the given domainname be used here ?
>      */
>     if (dhcp_gotserver) {
>       if (rtems_bsdnet_bootp_server_name)
>         hn = rtems_bsdnet_bootp_server_name;
>       else
>         hn = "bootps";
>       rtems_rootfs_append_host_rec(*((unsigned long *) &rtems_bsdnet_bootp_server_address),
>                                    hn, dn);
>     }
> 
>     if (dhcp_gotlogserver) {
>       rtems_rootfs_append_host_rec(*((unsigned long *) &rtems_bsdnet_log_host_address),
>                                    "logs", dn);
>     }
> 
>     /*
>      * Setup the DNS configuration file /etc/resolv.conf.
>      */
>     if (rtems_bsdnet_nameserver_count) {
>       int        i;
>       char       buf[64];
>       const char *bufl[1];
> 
>       bufl[0] = buf;
>       
> #define MKFILE_MODE (S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH)
>       
>       if (rtems_bsdnet_domain_name &&
>           (strlen(rtems_bsdnet_domain_name) < (sizeof(buf) - 1))) {
>         strcpy(buf, "search ");
>         strcat(buf, rtems_bsdnet_domain_name);
>         strcat(buf, "\n");
>         rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl);
>       }
> 
>       for (i = 0; i < rtems_bsdnet_nameserver_count; i++) {
>         strcpy(buf, "nameserver ");
>         strcat(buf, inet_ntoa(rtems_bsdnet_ntpserver[i]));
>         strcat(buf, "\n");
>         if (rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl))
>           break;
>       }
>     }
>   }
>   
>   /*
>    * Configure the interface with the new settings
>    */
>   error = bootpc_adjust_interface (&ireq, so,
>                                    &myaddr, &dhcp_netmask, &dhcp_gw, procp);
> 
>   dhcp_start_task (sdl, &reply, 150);
>   
>   soclose (so);
> }
> 
> /*******************************************************************************
> *
> *  RTEMS Entry point to DHCP client
> *
> *******************************************************************************/
> void rtems_bsdnet_do_dhcp (void)
> {
>   rtems_bsdnet_semaphore_obtain ();
>   dhcp_init (TRUE);
>   rtems_bsdnet_semaphore_release ();
> }
> 
> void rtems_bsdnet_do_dhcp_refresh_only (unsigned long xid,
>                                         unsigned long lease_time,
>                                         unsigned long elapsed_time,
>                                         unsigned long ip_address,
>                                         unsigned long srv_address)
> {
>   struct dhcp_packet reply;
>   struct ifnet       *ifp = NULL;
>   struct ifaddr      *ifa = NULL;
>   struct sockaddr_dl *sdl = NULL;
>   struct sockaddr_in *sin = NULL;
>   int                match = 0;
> 
>   struct ifnet       *mtif = NULL;
>   
>   /*
>    * Find a network interface.
>    */
>   for (ifp = ifnet; (ifp != NULL) && !match; ifp = ifp->if_next)
>     if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0)
>       for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
>         if (ifa->ifa_addr->sa_family == AF_INET)
>         {
>           sin = (struct sockaddr_in *) ifa->ifa_addr;
>           if (sin->sin_addr.s_addr == htonl (ip_address))
>           {
>             mtif = ifp;
>             match = 1;
>             break;
>           }
>         }
> 
>   if (!match)
>     panic ("dhcpc: no matching interface");
> 
>   for (ifa = mtif->if_addrlist; ifa != NULL; ifa = ifa->ifa_next)
>     if (ifa->ifa_addr->sa_family == AF_LINK &&
>         (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) &&
>         sdl->sdl_type == IFT_ETHER)
>       break;
>   
>   if (!match)
>     panic ("dhcpc: no matching interface");
> 
>   memset (&reply, 0x00, sizeof (reply));
>   reply.xid = htonl (xid);
>   reply.yiaddr.s_addr = htonl (ip_address);
>   reply.siaddr.s_addr = htonl (srv_address);
>   if (reply.siaddr.s_addr != rtems_bsdnet_bootp_server_address.s_addr)
>   {
>     memcpy (&rtems_bsdnet_bootp_server_address, &reply.siaddr,
>             sizeof (reply.siaddr));
>   }
> 
>   dhcp_lease_time = lease_time;
>   dhcp_elapsed_time = elapsed_time;
>   dhcp_start_task (sdl, &reply, 150);
> }
> #undef D_COMPILING_BSD_KERNEL
> #undef KERNEL


-- 
Joel Sherrill, Ph.D.             Director of Research & Development
joel at OARcorp.com                 On-Line Applications Research
Ask me about RTEMS: a free RTOS  Huntsville AL 35805
    Support Available             (256) 722-9985




More information about the users mailing list