diff options
Diffstat (limited to 'cpukit/libnetworking/rtems/rtems_dhcp.c')
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_dhcp.c | 1287 |
1 files changed, 0 insertions, 1287 deletions
diff --git a/cpukit/libnetworking/rtems/rtems_dhcp.c b/cpukit/libnetworking/rtems/rtems_dhcp.c deleted file mode 100644 index 6a153a4a40..0000000000 --- a/cpukit/libnetworking/rtems/rtems_dhcp.c +++ /dev/null @@ -1,1287 +0,0 @@ -#include <machine/rtems-bsd-kernel-space.h> - -/* - * DCHP client for RTEMS - * Andrew Bythell, <abythell@nortelnetworks.com> - * based on and uses subroutines from c/src/libnetworking/nfs/bootp_subr.c - */ - -/* - * DHCP task added. - * Brendan Gannon, <bgannon@cybertec.com.au> - */ - -/* - * Added interface to terminate DHCP task, and removed panics. - * Arnout Vandecappelle <arnout@mind.be>, Essensium/Mind - * Maarten Van Es <maarten@mind.be>, Essensium/Mind - */ - -/* - * 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. - * - */ - -#include <machine/rtems-bsd-kernel-space.h> - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <rtems.h> -#include <rtems/error.h> -#include <rtems/rtems_bsdnet.h> -#include <rtems/bsdnet/servers.h> - -#include <string.h> -#include <stdlib.h> -#include <unistd.h> - -#include <sys/sockio.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 <net/if_var.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/dhcp.h" -#include "rtems/bootp.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_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]; -}; - -/* - * Variables - */ -static int dhcp_option_overload = 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 dhcp_message_type = 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 dhcp_request_parameters[5] = { DHCP_SUBNET, - DHCP_GATEWAY, - DHCP_DNS, - DHCP_HOST, - DHCP_DOMAIN_NAME }; -#define NUM_NAMESERVERS \ - (sizeof rtems_bsdnet_config.name_server / sizeof rtems_bsdnet_config.name_server[0]) -static struct in_addr rtems_dhcpd_nameserver[NUM_NAMESERVERS]; -static int rtems_dhcpd_nameserver_count = 0; - -/* - * Clean any DNS entries add by a DHCP request. - */ -static void -clean_dns_entries (void) -{ - int e; - for (e = 0; e < rtems_dhcpd_nameserver_count; ++e) - { - int n; - for (n = 0; n < rtems_bsdnet_nameserver_count; ++ n) - { - if (memcmp (&rtems_dhcpd_nameserver[e], &rtems_bsdnet_nameserver[n], 4) == 0) - { - if (n < (NUM_NAMESERVERS - 1)) - memmove (&rtems_bsdnet_nameserver[n], - &rtems_bsdnet_nameserver[n + 1], - (NUM_NAMESERVERS - n - 1) * 4); - --rtems_bsdnet_nameserver_count; - } - } - } - rtems_dhcpd_nameserver_count = 0; -} - -/* - * Format an IP address in dotted decimal. - */ -static void -format_ip (unsigned long ip, char* buffer) -{ - sprintf (buffer, - "%lu.%lu.%lu.%lu", - (ip >> 24), - (ip >> 16) & 0xff, - (ip >> 8) & 0xff, - (ip & 0xff)); - - return; -} - -/* - * Print the IP setup - */ -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; - char ip_str[15]; - - printf ("dhcpc: %s: ", iface); - - ip = ntohl (ip_addr.s_addr); - format_ip (ip, ip_str); - printf ("inet: %-15s ", ip_str); - - ip = ntohl (mask_addr.s_addr); - format_ip (ip, ip_str); - printf ("mask: %-15s\n", ip_str); - - ip = ntohl (srv_addr.s_addr); - format_ip (ip, ip_str); - printf (" srv: %-15s ", ip_str); - - ip = ntohl (gw_addr.s_addr); - format_ip (ip, ip_str); - printf (" gw: %-15s\n", ip_str); - - return; -} - -/* - * Process options from the DHCP packet. - * Based on BOOTP routine. - */ -static void -process_options (unsigned char *optbuf, int optbufSize) -{ - int j = 0; - int len; - int code, ncode; - char *p; - - dhcp_message_type = 0; - - 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 = (char*) &optbuf[j]; - j += len; - - /* - * Process the option - */ - switch (code) - { - case 1: - /* Subnet mask */ - if (len != 4) { - printf ("dhcpc: subnet mask len is %d\n", len); - continue; - } - memcpy (&dhcp_netmask.sin_addr, p, 4); - dhcp_gotnetmask = 1; - break; - - case 2: - /* Time offset */ - if (len != 4) { - printf ("dhcpc: time offset len is %d\n", len); - continue; - } - memcpy (&rtems_bsdnet_timeoffset, p, 4); - rtems_bsdnet_timeoffset = ntohl (rtems_bsdnet_timeoffset); - break; - - case 3: - /* Routers */ - if (len % 4) { - printf ("dhcpc: Router Len is %d\n", len); - continue; - } - if (len > 0) - { - memcpy (&dhcp_gw.sin_addr, p, 4); - dhcp_gotgw = 1; - } - break; - - case 42: - /* NTP servers */ - if (len % 4) { - printf ("dhcpc: time server Len is %d\n", len); - continue; - } - { - 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) { - printf ("dhcpc: DNS Len is %d\n", len); - continue; - } - { - int dlen = 0; - while ((dlen < len) && - (rtems_dhcpd_nameserver_count < NUM_NAMESERVERS) && - (rtems_bsdnet_nameserver_count < NUM_NAMESERVERS)) - { - memcpy (&rtems_dhcpd_nameserver - [rtems_dhcpd_nameserver_count], p + dlen, 4); - rtems_dhcpd_nameserver_count++; - 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) { - printf ("dhcpc: hostname >= %d bytes\n", MAXHOSTNAMELEN); - len = MAXHOSTNAMELEN-1; - } - if (sethostname (p, len) < 0) { - printf ("dhcpc: can't set host name"); - } - if (dhcp_hostname != NULL) - { - char *tmp = realloc (dhcp_hostname, len); - if (tmp != NULL) { - dhcp_hostname = tmp; - strncpy (dhcp_hostname, p, len); - } else { /* realloc failed */ - printf ("dhcpc: realloc failed (%s:%d)", __FILE__, __LINE__); - free (dhcp_hostname, 0); - dhcp_hostname = NULL; - } - } else { /* dhcp_hostname == NULL */ - dhcp_hostname = strndup (p, len); - } - break; - - case 7: - /* Log servers */ - if (len % 4) { - printf ("dhcpc: Log server Len is %d\n", len); - continue; - } - 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) - printf ("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) { - printf ("dhcpc: DHCP option lease-length len is %d", len); - continue; - } - memcpy (&dhcp_lease_time, &p[0], 4); - dhcp_lease_time = ntohl (dhcp_lease_time); - break; - - case 52: - /* DHCP option override */ - if (len != 1) { - printf ("dhcpc: DHCP option overload len is %d", len); - continue; - } - dhcp_option_overload = p[0]; - break; - - case 53: - /* DHCP message */ - if (len != 1) { - printf ("dhcpc: DHCP message len is %d", len); - continue; - } - dhcp_message_type = 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) { - printf ("dhcpc: DHCP server len is %d", len); - continue; - } - 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; - } - } -} - -/* - * Generate the packet for a DHCP DISCOVER. - */ -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; - - /* - * If a host name is set add it to the request. - */ - if (rtems_bsdnet_config.hostname && \ - (strlen (rtems_bsdnet_config.hostname) > 1) && - (strlen (rtems_bsdnet_config.hostname) < 32)) { - call->vend[len++] = DHCP_HOST; - call->vend[len++] = strlen (rtems_bsdnet_config.hostname); - memcpy (&call->vend[len], - rtems_bsdnet_config.hostname, - strlen (rtems_bsdnet_config.hostname)); - len += strlen (rtems_bsdnet_config.hostname); - } - - /* - * DHCP Parameter request list - */ - call->vend[len++] = DHCP_PARAMETERS; - call->vend[len++] = sizeof (dhcp_request_parameters); - memcpy (&call->vend[len], &dhcp_request_parameters, sizeof (dhcp_request_parameters)); - len += sizeof (dhcp_request_parameters); - - /* - * 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; -} - -/* - * Generate the packet for a DHCP REQUEST. - */ -static int -dhcp_request_req (struct dhcp_packet* call, - struct dhcp_packet* reply, - struct sockaddr_dl *sdl, - int broadcast) -{ - int len = 0; - unsigned long temp; - char *hostname; - - 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 = reply->xid; - if (broadcast) - call->flags = htons (DHCP_BROADCAST); - else - { - call->flags = htons (DHCP_UNICAST); - call->ciaddr = 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 (dhcp_request_parameters); - memcpy (&call->vend[len], &dhcp_request_parameters, sizeof (dhcp_request_parameters)); - len += sizeof (dhcp_request_parameters); - - /* - * Lease time. - * For the REQUEST, return the lease time the server offered. - */ - call->vend[len++] = DHCP_LEASE; - call->vend[len++] = 4; - temp = htonl (dhcp_lease_time); - memcpy (&call->vend[len], &temp, sizeof (unsigned long)); - len += 4; - - /* - * Host name. - */ - hostname = malloc (MAXHOSTNAMELEN, 0, M_NOWAIT); - if (hostname != NULL) - { - if (gethostname (hostname, MAXHOSTNAMELEN) == 0) - { - call->vend[len++] = DHCP_HOST; - call->vend[len++] = strlen (hostname); - strcpy ((char*) &call->vend[len], hostname); - len += strlen (hostname); - } - free (hostname, 0); - } - - /* - * End. - */ - call->vend[len++] = DHCP_OPTION_END; - call->secs = 0; - - return len; -} - -/* - * Variables for the DHCP task. - */ -static struct dhcp_packet dhcp_req; -static rtems_id dhcp_task_id; - -/* - * The DHCP task counts until half the lease time has expired. - * When this period is up, it sends a DHCP REQUEST packet to the - * server again to renew the lease. - * If the lease is renewed, the task starts counting again. - * If the lease is not renewed, the task retries until it is. - * - * The task will not rebind if the lease is not renewed. - */ -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; - rtems_status_code ev_st; - - sdl = (struct sockaddr_dl *) _sdl; - - count = dhcp_elapsed_time; - - while (true) - { - /* - * Sleep until the next poll - */ - timeout = RTEMS_MILLISECONDS_TO_TICKS (1000); - ev_st = rtems_event_receive (RTEMS_EVENT_0, - RTEMS_WAIT | RTEMS_EVENT_ANY, - timeout, &event_out); - - /* - * Check if not a poll timeout. So when ANY event received, exit task. - * Actually, only event RTEMS_EVENT_0 sent from rtem_dhcp_failsafe.c - * if "failsafe" dhcp enabled when interface down. Otherwise, no - * event should occur, just timeout. - */ - if(ev_st != RTEMS_TIMEOUT) - break; - - count++; - - if (count >= (dhcp_lease_time / 2)) - { - rtems_bsdnet_semaphore_obtain (); - - dhcp_request_req (&call, &dhcp_req, sdl, true); - - /* - * Send the Request. - */ - error = bootpc_call ((struct bootp_packet *)&call, - (struct bootp_packet *)&dhcp_req, procp, NULL, 0); - if (error) { - rtems_bsdnet_semaphore_release (); - printf ("DHCP call failed -- error %d", error); - continue; - } - - /* - * Check for DHCP ACK/NACK - */ - if (memcmp (&dhcp_req.vend[0], - dhcp_magic_cookie, - sizeof (dhcp_magic_cookie)) != 0) - { - rtems_bsdnet_semaphore_release (); - printf ("DHCP server did not send Magic Cookie.\n"); - continue; - } - - /* - * We have an ack. Clear the DNS entries that have been assigned by a previous - * DHCP request. - */ - clean_dns_entries (); - - /* - * Process this requests options. - */ - process_options (&dhcp_req.vend[4], sizeof (dhcp_req.vend) - 4); - - if (dhcp_message_type != DHCP_ACK) - { - rtems_bsdnet_semaphore_release (); - printf ("DHCP server did not accept the DHCP request"); - continue; - } - - rtems_bsdnet_semaphore_release (); - - count = 0; - } - } - - - dhcp_task_id = 0; - printf ("dhcpc: exiting lease renewal task.\n"); - rtems_task_exit(); - -} - -/* - * Start the DHCP task. - */ -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; -} - -/* - * Check if the chosen interface already has an IP. - */ -static int -dhcp_interface_has_ip (struct ifreq *ireq, struct socket *so, struct proc *procp) -{ - struct sockaddr_in* sin; - int error; - - /* - * Check if the interface is already up. - */ - error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, procp); - if (error) - return 0; - - if ((ireq->ifr_flags & IFF_UP) == 0) - return 0; - - sin = (struct sockaddr_in *)&ireq->ifr_addr; - bzero ((caddr_t)sin, sizeof (struct sockaddr_in)); - sin->sin_len = sizeof (struct sockaddr_in); - sin->sin_family = AF_INET; - error = ifioctl (so, SIOCGIFADDR, (caddr_t)ireq, procp); - if (error) - return 0; - - if (sin->sin_addr.s_addr != 0) - return 1; - - return 0; -} - -/* - * DCHP Client Routine - * - The first DHCP offer is always accepted - * - No DHCP DECLINE message is sent if ARPing fails - * - * return value: - * 0: ok - * < 0: failed to startup or configure interface - */ -static int -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 error; - struct sockaddr_in myaddr; - struct ifaddr *ifa; - struct sockaddr_dl *sdl = NULL; - struct proc *procp = NULL; - char expected_dhcp_payload[7]; - - clean_dns_entries(); - - /* - * 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){ - printf ("dhcpc_init: no suitable interface\n"); - return -1; - } - - 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) { - printf ("dhcpc_init: socreate, error: %s\n", strerror(error)); - return -1; - } - - if (!dhcp_interface_has_ip (&ireq, so, procp)) - 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){ - printf ("dhcpc_init: Unable to find HW address\n"); - soclose (so); - return -1; - } - if (sdl->sdl_alen != EALEN) { - printf ("dhcpc_init: HW address len is %d, expected value is %d\n", - sdl->sdl_alen, EALEN); - soclose (so); - return -1; - } - - - /* - * Build the DHCP Discover - */ - dhcp_discover_req (&call, sdl, &xid); - - /* - * Expect a DHCP offer as response to DHCP discover - */ - memcpy(expected_dhcp_payload, dhcp_magic_cookie, sizeof(dhcp_magic_cookie)); - expected_dhcp_payload[sizeof(dhcp_magic_cookie) ]=0x35; /* DHCP */ - expected_dhcp_payload[sizeof(dhcp_magic_cookie)+1]=0x01; /* Length : 1 */ - expected_dhcp_payload[sizeof(dhcp_magic_cookie)+2]=0x02; /* DHCP_OFFER */ - - /* - * Send the Discover. - */ - error = bootpc_call ((struct bootp_packet *)&call, - (struct bootp_packet *)&reply, procp, - expected_dhcp_payload, sizeof(expected_dhcp_payload)); - if (error) { - printf ("BOOTP call failed -- %s\n", strerror(error)); - soclose (so); - return -1; - } - - /* - * Check for DHCP OFFER - */ - if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0) { - printf ("DHCP server did not send Magic Cookie.\n"); - soclose (so); - return -1; - } - - process_options (&reply.vend[4], sizeof (reply.vend) - 4); - - if (dhcp_message_type != DHCP_OFFER) { - printf ("DHCP server did not send a DHCP Offer.\n"); - soclose (so); - return -1; - } - - /* - * Expect a DHCP_ACK as response to the DHCP REQUEST - * No need to reinitialize the whole expected_dhcp_payload variable, - * header and first two bytes of the payload are filled from DHCP offer - */ - expected_dhcp_payload[sizeof(dhcp_magic_cookie)+2]=0x05; /* DHCP_ACK */ - - /* - * Send a DHCP REQUEST - */ - dhcp_request_req (&call, &reply, sdl, true); - - error = bootpc_call ((struct bootp_packet *)&call, - (struct bootp_packet *)&reply, procp, - expected_dhcp_payload, sizeof(expected_dhcp_payload)); - if (error) { - printf ("BOOTP call failed -- %s\n", strerror(error)); - soclose (so); - return -1; - } - - /* - * Check for DHCP ACK/NACK - */ - if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0) { - printf ("DHCP server did not send Magic Cookie.\n"); - soclose (so); - return -1; - } - - process_options (&reply.vend[4], sizeof (reply.vend) - 4); - - if (dhcp_message_type != DHCP_ACK) { - printf ("DHCP server did not accept the DHCP request\n"); - soclose (so); - return -1; - } - - /* - * 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) - process_options (&reply.vend[4], sizeof (reply.vend) - 4); - - if (dhcp_option_overload & 1) - process_options ((unsigned char*) reply.file, sizeof reply.file); - else - if (reply.file[0]) - rtems_bsdnet_bootp_boot_file_name = strdup (reply.file); - - if (dhcp_option_overload & 2) - process_options ((unsigned char*) 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(myaddr.sin_addr.s_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(rtems_bsdnet_bootp_server_address.s_addr, - hn, dn); - } - - if (dhcp_gotlogserver) { - rtems_rootfs_append_host_rec(rtems_bsdnet_log_host_address.s_addr, - "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++) { - char addrbuf[INET_ADDRSTRLEN]; - strcpy(buf, "nameserver "); - strcat(buf, inet_ntoa_r(rtems_bsdnet_ntpserver[i], addrbuf)); - 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); - - /* - * Start the DHCP task if the lease isn't infinite. - */ - if (dhcp_lease_time != 0xffffffff) - dhcp_start_task (sdl, &reply, 150); - - soclose (so); - - return 0; -} - -/* - * - * RTEMS Entry point to DHCP client - * - */ -void rtems_bsdnet_do_dhcp (void) -{ - bool update = true; - rtems_bsdnet_semaphore_obtain (); - while( dhcp_init (update) < 0 ) { - update = false; - rtems_bsdnet_semaphore_release(); - rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(1000)); - rtems_bsdnet_semaphore_obtain (); - } - rtems_bsdnet_semaphore_release (); -} - -int rtems_bsdnet_do_dhcp_timeout( void ) -{ - int return_value; - - rtems_bsdnet_semaphore_obtain (); - return_value = dhcp_init (false); - rtems_bsdnet_semaphore_release (); - - return return_value; -} - -void rtems_bsdnet_dhcp_down (void) -{ - if(dhcp_task_id != 0) { - rtems_event_send (dhcp_task_id, RTEMS_EVENT_0); - } -} - -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, - const char* hostname) -{ - 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; - - /* - * If an infinite lease has been granted, no task is needed. - */ - if (lease_time == 0xffffffff) - return; - - /* - * 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) { - printf ("dhcpc: no matching interface\n"); - return; - } - - 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) { - printf ("dhcpc: no matching interface address\n"); - return; - } - - /* - * Set up given values in a simulated DHCP reply. - */ - 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; - - if (hostname) - { - sethostname ((char *) hostname, strlen (hostname)); - dhcp_hostname = bootp_strdup_realloc (dhcp_hostname, hostname); - } - - dhcp_start_task (sdl, &reply, 150); -} |