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