source: rtems/cpukit/libnetworking/rtems/rtems_dhcp.c @ d9b8e29

4.104.114.84.95
Last change on this file since d9b8e29 was d9b8e29, checked in by Chris Johns <chrisj@…>, on Jun 30, 2005 at 4:01:12 AM

DHCP server for RTEMS.

  • Property mode set to 100644
File size: 29.4 KB
Line 
1/*     
2 *  DCHP client for RTEMS
3 *  Andrew Bythell, <abythell@nortelnetworks.com>
4 *  based on and uses subroutines from c/src/libnetworking/nfs/bootp_subr.c
5 */
6
7/*
8 * DHCP task added.
9 * Brendan Gannon, <bgannon@cybertec.com.au>
10 */
11
12/*
13 * Copyright (c) 1995 Gordon Ross, Adam Glass
14 * Copyright (c) 1992 Regents of the University of California.
15 * All rights reserved.
16 *
17 * This software was developed by the Computer Systems Engineering group
18 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
19 * contributed to Berkeley.
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
23 * are met:
24 * 1. Redistributions of source code must retain the above copyright
25 *    notice, this list of conditions and the following disclaimer.
26 * 2. Redistributions in binary form must reproduce the above copyright
27 *    notice, this list of conditions and the following disclaimer in the
28 *    documentation and/or other materials provided with the distribution.
29 * 3. All advertising materials mentioning features or use of this software
30 *    must display the following acknowledgement:
31 *      This product includes software developed by the University of
32 *      California, Lawrence Berkeley Laboratory and its contributors.
33 * 4. Neither the name of the University nor the names of its contributors
34 *    may be used to endorse or promote products derived from this software
35 *    without specific prior written permission.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 *
49 */
50
51/*
52 * WARNING:
53 *   This file should be moved into c/src/libnetworking/nfs
54 *   and the following two #ifndef...#endif blocks and the #undefs at
55 *   the end of the file should be removed
56 */
57
58#ifndef _COMPILING_BSD_KERNEL_
59#define _COMPILING_BSD_KERNEL_
60#endif
61
62#ifndef KERNEL
63#define KERNEL
64#endif
65
66#ifndef __INSIDE_RTEMS_BSD_TCPIP_STACK__
67#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
68#endif
69
70#ifndef __BSD_VISIBLE
71#define __BSD_VISIBLE 1
72#endif
73
74#if HAVE_CONFIG_H
75#include "config.h"
76#endif
77
78#include <rtems.h>
79#include <rtems/error.h>
80#include <rtems/rtems_bsdnet.h>
81#include <rtems/bsdnet/servers.h>
82
83#include <string.h>
84#include <stdlib.h>
85
86#include <sys/ioctl.h>
87#include <sys/param.h>          /* for MAXHOSTNAMELEN */
88#include <sys/systm.h>
89#include <sys/socketvar.h>      /* for socreat() soclose() */
90#include <sys/socket.h>
91
92#include <net/if.h>
93#include <net/if_var.h>
94#include <netinet/in.h>         /* for NBO-HBO conversions */
95#include <net/if_types.h>       /* for IFT_ETHER */
96#include <net/if_dl.h>          /* for LLADDR */
97
98#include <sys/stat.h>
99#include <sys/types.h>
100#include <fcntl.h>
101#include <rtems/mkrootfs.h>
102
103#include "rtems/dhcp.h"
104
105#ifndef EALEN
106#define EALEN 6
107#endif
108
109/*
110 *DHCP flags
111 */
112#define DHCP_BROADCAST 0x8000
113#define DHCP_UNICAST   0x0000
114
115/*
116 * DHCP Op Codes
117 */
118#define DHCP_BOOTREQUEST 1
119#define DHCP_BOOTREPLY   2
120
121/*
122 * DHCP Messages
123 */
124#define DHCP_DISCOVER 1
125#define DHCP_OFFER    2
126#define DHCP_REQUEST  3
127#define DHCP_DECLINE  4
128#define DHCP_ACK      5
129#define DHCP_NACK     6
130#define DHCP_RELEASE  7
131
132/*
133 * DHCP Options
134 */
135#define DHCP_OPTION_PAD    0
136#define DHCP_SUBNET        1
137#define DHCP_GATEWAY       3
138#define DHCP_DNS           6
139#define DHCP_HOST          12
140#define DHCP_DOMAIN_NAME   15
141#define DHCP_NETMASK       28
142#define DHCP_REQUESTED_IP  50
143#define DHCP_LEASE         51
144#define DHCP_MESSAGE       53
145#define DHCP_SERVER        54
146#define DHCP_PARAMETERS    55
147#define DHCP_OPTION_END    255
148
149/*
150 * Definitions from RFC
151 */
152struct dhcp_packet
153{
154  u_int8_t       op;
155  u_int8_t       htype;
156  u_int8_t       hlen;
157  u_int8_t       hops;
158  u_int32_t      xid;
159  u_int16_t      secs;
160  u_int16_t      flags;
161  struct in_addr ciaddr;
162  struct in_addr yiaddr;
163  struct in_addr siaddr;
164  struct in_addr giaddr;
165  unsigned char  chaddr[16];
166  char           sname[64];
167  char           file[128];
168  unsigned char  vend[312];
169};
170
171/*
172 * External Declarations for Functions found in
173 * rtems/c/src/libnetworking/nfs/
174 */
175extern int bootpc_call (struct dhcp_packet *call,
176                        struct dhcp_packet *reply,
177                        struct proc *procp);
178extern int bootpc_fakeup_interface (struct ifreq *ireq,
179                                    struct socket *so,
180                                    struct proc *procp);
181extern int bootpc_adjust_interface (struct ifreq *ireq,
182                                    struct socket *so,
183                                    struct sockaddr_in *myaddr,
184                                    struct sockaddr_in *netmask,
185                                    struct sockaddr_in *gw,
186                                    struct proc *procp);
187extern void *bootp_strdup_realloc (char *dst,
188                                   const char *src);
189extern int nfs_diskless_valid;
190
191/*
192 * Variables
193 */
194static int                dhcp_option_overload = 0;
195static char               dhcp_gotgw = 0;
196static char               dhcp_gotnetmask = 0;
197static char               dhcp_gotserver = 0;
198static char               dhcp_gotlogserver = 0;
199static struct sockaddr_in dhcp_netmask;
200static struct sockaddr_in dhcp_gw;
201static char               *dhcp_hostname;
202static int                dhcp_message_type = 0;
203static unsigned long      dhcp_lease_time;
204static unsigned long      dhcp_elapsed_time = 0;
205static const char         dhcp_magic_cookie[4] = { 99, 130, 83, 99 };
206static const char         dhcp_request_parameters[5] = { DHCP_SUBNET,
207                                                         DHCP_GATEWAY,
208                                                         DHCP_DNS,
209                                                         DHCP_HOST,
210                                                         DHCP_DOMAIN_NAME };
211
212/*
213 * Format an IP address in dotted decimal.
214 */
215void
216format_ip (unsigned long ip, char* buffer)
217{
218  sprintf (buffer,
219           "%lu.%lu.%lu.%lu",
220          (ip >> 24),
221          (ip >> 16) & 0xff,
222          (ip >>  8) & 0xff,
223          (ip        & 0xff));
224
225  return;
226}
227
228/*
229 * Print the IP setup
230 */
231static void
232printsetup (const char     *iface,
233            struct in_addr ip_addr,
234            struct in_addr mask_addr,
235            struct in_addr srv_addr,
236            struct in_addr gw_addr)
237{
238  unsigned long ip;
239  char ip_str[15];
240
241  printf ("dhcpc: %s: ", iface);
242 
243  ip = ntohl (ip_addr.s_addr);
244  format_ip (ip, ip_str);
245  printf ("inet: %-15s ", ip_str);
246 
247  ip = ntohl (mask_addr.s_addr);
248  format_ip (ip, ip_str);
249  printf ("mask: %-15s\n", ip_str);
250
251  ip = ntohl (srv_addr.s_addr);
252  format_ip (ip, ip_str);
253  printf   ("             srv: %-15s ", ip_str);
254 
255  ip = ntohl (gw_addr.s_addr);
256  format_ip (ip, ip_str);
257  printf ("  gw: %-15s\n", ip_str);
258 
259  return;
260}
261
262/*
263 * Process options from the DHCP packet.
264 * Based on BOOTP routine.
265 */
266static void
267process_options (unsigned char *optbuf, int optbufSize)
268{
269  int j = 0;
270  int len;
271  int code, ncode;
272  char *p;
273
274  ncode = optbuf[0];
275  while (j < optbufSize)
276  {
277    code = optbuf[j] = ncode;
278    if (code == 255)
279      return;
280    if (code == 0)
281    {
282      j++;
283      continue;
284    }
285    len = optbuf[j + 1];
286    j += 2;
287   
288    if ((len + j) >= optbufSize)
289    {
290      printf ("Truncated field for code %d", code);
291      return;
292    }
293   
294    ncode = optbuf[j + len];
295    optbuf[j + len] = '\0';
296    p = (char*) &optbuf[j];
297    j += len;
298
299    /*
300     * Process the option
301     */
302    switch (code)
303    {
304      case 1:
305        /* Subnet mask */
306        if (len != 4)
307          panic ("dhcpc: subnet mask len is %d", len);
308        memcpy (&dhcp_netmask.sin_addr, p, 4);
309        dhcp_gotnetmask = 1;
310        break;
311
312      case 2:
313        /* Time offset */
314        if (len != 4)
315          panic ("dhcpc: time offset len is %d", len);
316        memcpy (&rtems_bsdnet_timeoffset, p, 4);
317        rtems_bsdnet_timeoffset = ntohl (rtems_bsdnet_timeoffset);
318        break;
319
320      case 3:
321        /* Routers */
322        if (len % 4)
323          panic ("dhcpc: Router Len is %d", len);
324        if (len > 0)
325        {
326          memcpy (&dhcp_gw.sin_addr, p, 4);
327          dhcp_gotgw = 1;
328        }
329        break;
330
331      case 42:
332        /* NTP servers */
333        if (len % 4)
334          panic ("dhcpc: time server Len is %d", len);
335        {
336          int tlen = 0;
337          while ((tlen < len) &&
338                 (rtems_bsdnet_ntpserver_count <
339                  sizeof rtems_bsdnet_config.ntp_server /
340                  sizeof rtems_bsdnet_config.ntp_server[0]))
341          {
342            memcpy (&rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count],
343                    p + tlen, 4);
344            rtems_bsdnet_ntpserver_count++;
345            tlen += 4;
346          }
347        }
348        break;
349
350      case 6:
351        /* Domain Name servers */
352        if (len % 4)
353          panic ("dhcpc: DNS Len is %d", len);
354        {
355          int dlen = 0;
356          while ((dlen < len) &&
357                 (rtems_bsdnet_nameserver_count <
358                  sizeof rtems_bsdnet_config.name_server /
359                  sizeof rtems_bsdnet_config.name_server[0]))
360          {
361            memcpy (&rtems_bsdnet_nameserver
362                    [rtems_bsdnet_nameserver_count], p + dlen, 4);
363            rtems_bsdnet_nameserver_count++;
364            dlen += 4;
365          }
366        }
367        break;
368
369      case 12:
370        /* Host name */
371        if (len >= MAXHOSTNAMELEN)
372          panic ("dhcpc: hostname >= %d bytes", MAXHOSTNAMELEN);
373        if (sethostname (p, len) < 0)
374          panic ("dhcpc: can't set host name");
375        if (dhcp_hostname != NULL)
376        {
377          dhcp_hostname = realloc (dhcp_hostname, len);
378          strncpy (dhcp_hostname, p, len);
379        }
380        else
381          dhcp_hostname = strndup (p, len);
382        break;
383
384      case 7:
385        /* Log servers */
386        if (len % 4)
387          panic ("dhcpc: Log server Len is %d", len);
388        if (len > 0)
389        {
390          memcpy (&rtems_bsdnet_log_host_address, p, 4);
391          dhcp_gotlogserver = 1;
392        }
393        break;
394
395      case 15:
396        /* Domain name */
397        if (p[0])
398        {
399          rtems_bsdnet_domain_name = strdup (p);
400        }
401        break;
402
403      case 16:          /* Swap server IP address. unused */
404        break;
405
406      case 50:
407        /* DHCP Requested IP Address */
408        if (len != 4)
409          panic ("dhcpc: DHCP option requested IP len is %d", len);
410        /*
411         * although nothing happens here, this case keeps the client
412         * from complaining about unknown options.  The Requested IP
413         * is necessary to return to the server for a DHCP REQUEST
414         */
415        break;
416
417      case 51:
418        /* DHCP Lease Length */
419        if (len != 4)
420          panic ("dhcpc: DHCP option lease-length len is %d", len);
421        memcpy (&dhcp_lease_time, &p[0], 4);
422        dhcp_lease_time = ntohl (dhcp_lease_time);
423        break;
424       
425      case 52:
426        /* DHCP option override */
427        if (len != 1)
428          panic ("dhcpc: DHCP option overload len is %d", len);
429        dhcp_option_overload = p[0];
430        break;
431
432      case 53:
433        /* DHCP message */
434        if (len != 1)
435          panic ("dhcpc: DHCP message len is %d", len);
436        dhcp_message_type = p[0];
437        break;
438
439      case 128:         /* Site-specific option for DHCP servers that
440                   *   a) don't supply tag 54
441                   * and
442                   *   b) don't supply the server address in siaddr
443                   * For example, on Solaris 2.6 in.dhcpd, include in the dhcptab:
444                   *    Bootsrv s Site,128,IP,1,1
445                   * and use that symbol in the macro that defines the client:
446                   *    Bootsrv=<tftp-server-ip-address>
447                   */
448      case 54:
449        /* DHCP server */
450        if (len != 4)
451          panic ("dhcpc: DHCP server len is %d", len);
452        memcpy (&rtems_bsdnet_bootp_server_address, p, 4);
453        dhcp_gotserver = 1;
454        break;
455
456      case 66:
457        /* DHCP server name option */
458        if (p[0])
459          rtems_bsdnet_bootp_server_name = strdup (p);
460        break;
461
462      case 67:
463        /* DHCP bootfile option */
464        if (p[0])
465          rtems_bsdnet_bootp_boot_file_name = strdup (p);
466        break;
467
468      default:
469        break;
470    }
471  }
472}
473
474/*
475 * Generate the packet for a DHCP DISCOVER.
476 */
477static int
478dhcp_discover_req (struct dhcp_packet* call,
479                   struct sockaddr_dl *sdl,
480                   unsigned long *xid)
481{
482  int len = 0;
483 
484  memset (call, 0, sizeof (struct dhcp_packet));
485
486  /*
487   * Send a DHCP DISCOVER Message
488   */
489  call->op = DHCP_BOOTREQUEST;
490  call->htype = 1;              /* 10mb ethernet */
491  call->hlen = sdl->sdl_alen;   /* Hardware address length */
492  call->hops = 0;
493  (*xid)++;
494  call->xid = htonl (*xid);
495  call->flags = htons (DHCP_BROADCAST);
496 
497  memcpy (&call->chaddr, LLADDR (sdl), sdl->sdl_alen);
498
499  /*
500   * Magic cookie.
501   */
502  memcpy (&call->vend[len], dhcp_magic_cookie, sizeof (dhcp_magic_cookie));
503  len += sizeof (dhcp_magic_cookie);
504
505  /*
506   * DHCP Message type.
507   */
508  call->vend[len++] = DHCP_MESSAGE;
509  call->vend[len++] = 1;
510  call->vend[len++] = DHCP_DISCOVER;
511
512  /*
513   * DHCP Parameter request list
514   */
515  call->vend[len++] = DHCP_PARAMETERS;
516  call->vend[len++] = sizeof (dhcp_request_parameters);
517  memcpy (&call->vend[len], &dhcp_request_parameters, sizeof (dhcp_request_parameters));
518  len += sizeof (dhcp_request_parameters);
519
520  /*
521   * Lease time.
522   */
523  call->vend[len++] = DHCP_LEASE;
524  call->vend[len++] = 4;
525  memset (&call->vend[len], 0xFF, 4);   /* request infinite lease time */
526  len += 4;
527
528  /*
529   * End.
530   */
531  call->vend[len++] = DHCP_OPTION_END;
532  call->secs = 0;
533
534  return len;
535}
536
537/*
538 * Generate the packet for a DHCP REQUEST.
539 */
540static int
541dhcp_request_req (struct dhcp_packet* call,
542                  struct dhcp_packet* reply,
543                  struct sockaddr_dl *sdl,
544                  int broadcast)
545{
546  int           len = 0;
547  unsigned long temp;
548  char          *hostname;
549 
550  memset (call, 0, sizeof (struct dhcp_packet));
551
552  /*
553   * Send a DHCP REQUEST Message
554   */
555  call->op = DHCP_BOOTREQUEST;
556  call->htype = 1;              /* 10mb ethernet */
557  call->hlen = sdl->sdl_alen;   /* Hardware address length */
558  call->hops = 0;
559  call->xid = reply->xid;
560  if (broadcast)
561    call->flags = htons (DHCP_BROADCAST);
562  else
563  {
564    call->flags = htons (DHCP_UNICAST);
565    call->ciaddr = reply->yiaddr;
566  }
567  memcpy (&call->chaddr, LLADDR (sdl), sdl->sdl_alen);
568
569  /*
570   * Magic cookie.
571   */
572  memcpy (&call->vend[len], dhcp_magic_cookie, sizeof (dhcp_magic_cookie));
573  len += sizeof (dhcp_magic_cookie);
574
575  /*
576   * DHCP Message type.
577   */
578  call->vend[len++] = DHCP_MESSAGE;
579  call->vend[len++] = 1;
580  call->vend[len++] = DHCP_REQUEST;
581
582  /*
583   * DHCP server
584   */
585  if (broadcast)
586  {
587    call->vend[len++] = DHCP_SERVER;
588    call->vend[len++] = sizeof (rtems_bsdnet_bootp_server_address);
589    memcpy (&call->vend[len], &rtems_bsdnet_bootp_server_address,
590            sizeof (rtems_bsdnet_bootp_server_address));
591    len += sizeof (rtems_bsdnet_bootp_server_address);
592  }
593
594  /*
595   * Requested IP
596   */
597  call->vend[len++] = DHCP_REQUESTED_IP;
598  call->vend[len++] = sizeof (reply->yiaddr);
599  memcpy (&call->vend[len], &reply->yiaddr, sizeof (reply->yiaddr));
600  len += sizeof (reply->yiaddr);
601 
602  /*
603   * DHCP Parameter request list
604   */
605  call->vend[len++] = DHCP_PARAMETERS;
606  call->vend[len++] = sizeof (dhcp_request_parameters);
607  memcpy (&call->vend[len], &dhcp_request_parameters, sizeof (dhcp_request_parameters));
608  len += sizeof (dhcp_request_parameters);
609
610  /*
611   * Lease time.
612   * For the REQUEST, return the lease time the server offered.
613   */
614  call->vend[len++] = DHCP_LEASE;
615  call->vend[len++] = 4;
616  temp = htonl (dhcp_lease_time);
617  memcpy (&call->vend[len], &temp, sizeof (unsigned long));
618  len += 4;
619
620  /*
621   * Host name.
622   */
623  hostname = malloc (MAXHOSTNAMELEN, 0, M_NOWAIT);
624  if (hostname != NULL)
625  {
626    if (gethostname (hostname, MAXHOSTNAMELEN) == 0)
627    {
628      call->vend[len++] = DHCP_HOST;
629      call->vend[len++] = strlen (hostname);
630      strcpy ((char*) &call->vend[len], hostname);
631      len += strlen (hostname);
632    }
633    free (hostname, 0);
634  }
635
636  /*
637   * End.
638   */
639  call->vend[len++] = DHCP_OPTION_END;
640  call->secs = 0;
641
642  return len;
643}
644
645/*
646 * Variables for the DHCP task.
647 */
648static struct dhcp_packet dhcp_req;
649static rtems_id           dhcp_task_id;
650
651/*
652 * The DHCP task counts until half the lease time has expired.
653 * When this period is up, it sends a DHCP REQUEST packet to the
654 * server again to renew the lease.
655 * If the lease is renewed, the task starts counting again.
656 * If the lease is not renewed, the task retries until it is.
657 *
658 * The task will not rebind if the lease is not renewed.
659 */
660static void
661dhcp_task (rtems_task_argument _sdl)
662{
663  unsigned long       count;
664  struct dhcp_packet  call;
665  struct sockaddr_dl  *sdl;
666  rtems_event_set     event_out;
667  unsigned int        timeout = 0;
668  int                 error;
669  struct proc *procp = NULL;
670 
671  sdl = (struct sockaddr_dl *) _sdl;
672 
673  count = dhcp_elapsed_time;
674 
675  while (TRUE)
676  {
677    if (count >= (dhcp_lease_time / 2))
678    {
679      rtems_bsdnet_semaphore_obtain ();
680     
681      dhcp_request_req (&call, &dhcp_req, sdl, TRUE);
682
683      /*
684       * Send the Request.
685       */
686      error = bootpc_call (&call, &dhcp_req, procp);
687     
688      if (error)
689        panic ("DHCP call failed -- error %d", error);
690     
691      /*
692       * Check for DHCP ACK/NACK
693       */
694      if (memcmp (&dhcp_req.vend[0],
695                  dhcp_magic_cookie,
696                  sizeof (dhcp_magic_cookie)) != 0)
697      {
698        rtems_bsdnet_semaphore_release ();
699        panic ("DHCP server did not send Magic Cookie.\n");
700      }
701 
702      process_options (&dhcp_req.vend[4], sizeof (dhcp_req.vend) - 4);
703 
704      if (dhcp_message_type != DHCP_ACK)
705      {
706        rtems_bsdnet_semaphore_release ();
707        panic ("DHCP server did not accept the DHCP request");
708      }
709     
710      rtems_bsdnet_semaphore_release ();
711     
712      count = 0;
713    }
714
715    /*
716     * Sleep until the next poll
717     */
718    timeout = TOD_MILLISECONDS_TO_TICKS (1000);
719    rtems_event_receive (RTEMS_EVENT_0,
720                         RTEMS_WAIT | RTEMS_EVENT_ANY,
721                         timeout, &event_out);
722    count++;
723  }
724}
725
726/*
727 * Start the DHCP task.
728 */
729static rtems_status_code
730dhcp_start_task (struct sockaddr_dl *sdl,
731                 struct dhcp_packet *reply,
732                 int priority)
733{
734  rtems_status_code sc;
735 
736  memcpy (&dhcp_req, reply, sizeof (struct dhcp_packet));
737
738  sc = rtems_task_create (rtems_build_name ('d','h','c','p'),
739                          priority,
740                          2048,
741                          RTEMS_PREEMPT |
742                          RTEMS_NO_TIMESLICE |
743                          RTEMS_NO_ASR |
744                          RTEMS_INTERRUPT_LEVEL (0),
745                          RTEMS_LOCAL,
746                          &dhcp_task_id);
747
748  if (sc != RTEMS_SUCCESSFUL)
749    return sc;
750
751  sc = rtems_task_start (dhcp_task_id,
752                         dhcp_task,
753                         (rtems_task_argument) sdl);
754
755  if (sc != RTEMS_SUCCESSFUL)
756    return sc;
757
758  return RTEMS_SUCCESSFUL;
759}
760
761/*
762 * Check if the chosen interface already has an IP.
763 */
764static int
765dhcp_interface_has_ip (struct ifreq *ireq, struct socket *so, struct proc *procp)
766{
767  struct sockaddr_in* sin;
768  int error;
769 
770  /*
771   * Check if the interface is already up.
772   */
773  error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, procp);
774  if (error)
775    return 0;
776 
777  if ((ireq->ifr_flags & IFF_UP) == 0)
778    return 0;
779
780  sin = (struct sockaddr_in *)&ireq->ifr_addr;
781  bzero ((caddr_t)sin, sizeof (struct sockaddr_in));
782  sin->sin_len = sizeof (struct sockaddr_in);
783  sin->sin_family = AF_INET;
784  error = ifioctl (so, SIOCGIFADDR, (caddr_t)ireq, procp);
785  if (error)
786    return 0;
787
788  if (sin->sin_addr.s_addr != 0)
789    return 1;
790
791  return 0;
792}
793
794/*
795 *  DCHP Client Routine
796 *    - The first DHCP offer is always accepted
797 *    - No DHCP DECLINE message is sent if ARPing fails
798 */
799void
800dhcp_init (int update_files)
801{
802  struct dhcp_packet   call;
803  struct dhcp_packet   reply;
804  static unsigned long xid = ~0xFF;
805  struct ifreq         ireq;
806  struct ifnet         *ifp;
807  struct socket        *so;
808  int                  len;
809  int                  error;
810  struct sockaddr_in   myaddr;
811  struct ifaddr        *ifa;
812  struct sockaddr_dl   *sdl = NULL;
813  struct proc          *procp = NULL;
814 
815  /*
816   * If already filled in, don't touch it here
817   */
818  if (nfs_diskless_valid)
819    return;
820
821  /*
822   * If we are to update the files create the root
823   * file structure.
824   */
825  if (update_files)
826    if (rtems_create_root_fs () < 0) {
827      printf("Error creating the root filesystem.\nFile not created.\n");
828      update_files = 0;
829    }
830 
831  /*
832   * Find a network interface.
833   */
834  for (ifp = ifnet; ifp != 0; ifp = ifp->if_next)
835    if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0)
836      break;
837  if (ifp == NULL)
838    panic ("dhcpc_init: no suitable interface");
839  memset (&ireq, 0, sizeof (ireq));
840  sprintf (ireq.ifr_name, "%s%d", ifp->if_name, ifp->if_unit);
841
842  if ((error = socreate (AF_INET, &so, SOCK_DGRAM, 0, procp)) != 0)
843    panic ("nfs_boot: socreate, error=%d", error);
844
845  if (!dhcp_interface_has_ip (&ireq, so, procp))
846    bootpc_fakeup_interface (&ireq, so, procp);
847
848  /*
849   * Get HW address
850   */
851  for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
852    if (ifa->ifa_addr->sa_family == AF_LINK &&
853        (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) &&
854        sdl->sdl_type == IFT_ETHER)
855      break;
856
857  if (!sdl)
858    panic ("dhcpc: Unable to find HW address");
859  if (sdl->sdl_alen != EALEN)
860    panic ("dhcpc: HW address len is %d, expected value is %d",
861           sdl->sdl_alen, EALEN);
862
863  /*
864   * Build the DHCP Discover
865   */
866  len = dhcp_discover_req (&call, sdl, &xid);
867
868  /*
869   * Send the Discover.
870   */
871  error = bootpc_call (&call, &reply, procp);
872  if (error)
873    panic ("BOOTP call failed -- error %d", error);
874
875  /*
876   * Check for DHCP OFFER
877   */
878  if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0)
879    panic ("DHCP server did not send Magic Cookie.\n");
880
881  process_options (&reply.vend[4], sizeof (reply.vend) - 4);
882 
883  if (dhcp_message_type != DHCP_OFFER)
884    panic ("DHCP server did not send a DHCP Offer.\n");
885
886  /*
887   * Send a DHCP REQUEST
888   */
889  dhcp_request_req (&call, &reply, sdl, TRUE);
890 
891  error = bootpc_call (&call, &reply, procp);
892  if (error)
893    panic ("BOOTP call failed -- error %d", error);
894
895  /*
896   * Check for DHCP ACK/NACK
897   */
898  if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0)
899    panic ("DHCP server did not send Magic Cookie.\n");
900 
901  process_options (&reply.vend[4], sizeof (reply.vend) - 4);
902 
903  if (dhcp_message_type != DHCP_ACK)
904    panic ("DHCP server did not accept the DHCP request");
905
906  /*
907   * Initialize network address structures
908   */
909  memset (&myaddr, 0, sizeof (myaddr));
910  memset (&dhcp_netmask, 0, sizeof (dhcp_netmask));
911  memset (&dhcp_gw, 0, sizeof (dhcp_gw));
912  myaddr.sin_len = sizeof (myaddr);
913  myaddr.sin_family = AF_INET;
914  dhcp_netmask.sin_len = sizeof (dhcp_netmask);
915  dhcp_netmask.sin_family = AF_INET;
916  dhcp_gw.sin_len = sizeof (dhcp_gw);
917  dhcp_gw.sin_family = AF_INET;
918
919  /*
920   * Set our address
921   */
922  myaddr.sin_addr = reply.yiaddr;
923
924  /*
925   * Process BOOTP/DHCP options
926   */
927  if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) == 0)
928    process_options (&reply.vend[4], sizeof (reply.vend) - 4);
929 
930  if (dhcp_option_overload & 1)
931    process_options ((unsigned char*) reply.file, sizeof reply.file);
932  else
933    if (reply.file[0])
934      rtems_bsdnet_bootp_boot_file_name = strdup (reply.file);
935 
936  if (dhcp_option_overload & 2)
937    process_options ((unsigned char*) reply.sname, sizeof reply.sname);
938  else
939    if (reply.sname[0])
940      rtems_bsdnet_bootp_server_name = strdup (reply.sname);
941
942  /*
943   * Use defaults if values were not supplied by BOOTP/DHCP options
944   */
945  if (!dhcp_gotnetmask)
946  {
947    if (IN_CLASSA (ntohl (myaddr.sin_addr.s_addr)))
948      dhcp_netmask.sin_addr.s_addr = htonl (IN_CLASSA_NET);
949    else if (IN_CLASSB (ntohl (myaddr.sin_addr.s_addr)))
950      dhcp_netmask.sin_addr.s_addr = htonl (IN_CLASSB_NET);
951    else
952      dhcp_netmask.sin_addr.s_addr = htonl (IN_CLASSC_NET);
953  }
954 
955  if (!dhcp_gotserver)
956    rtems_bsdnet_bootp_server_address = reply.siaddr;
957 
958  if (!dhcp_gotgw)
959    dhcp_gw.sin_addr = reply.giaddr;
960 
961  if (!dhcp_gotlogserver)
962    rtems_bsdnet_log_host_address = rtems_bsdnet_bootp_server_address;
963
964  printsetup (ifp->if_name, myaddr.sin_addr, dhcp_netmask.sin_addr,
965              rtems_bsdnet_bootp_server_address, dhcp_gw.sin_addr);
966
967  /*
968   * Update the files if we are asked too.
969   */
970  if (update_files) {
971    char *dn = rtems_bsdnet_domain_name;
972    char *hn = dhcp_hostname;
973    if (!dn)
974      dn = "mydomain";
975    if (!hn)
976    {
977      hn = "me";
978      sethostname (hn, strlen (hn));
979    }
980    rtems_rootfs_append_host_rec(*((unsigned long*) &myaddr.sin_addr), hn, dn);
981
982    /*
983     * Should the given domainname be used here ?
984     */
985    if (dhcp_gotserver) {
986      if (rtems_bsdnet_bootp_server_name)
987        hn = rtems_bsdnet_bootp_server_name;
988      else
989        hn = "bootps";
990      rtems_rootfs_append_host_rec(*((unsigned long *) &rtems_bsdnet_bootp_server_address),
991                                   hn, dn);
992    }
993
994    if (dhcp_gotlogserver) {
995      rtems_rootfs_append_host_rec(*((unsigned long *) &rtems_bsdnet_log_host_address),
996                                   "logs", dn);
997    }
998
999    /*
1000     * Setup the DNS configuration file /etc/resolv.conf.
1001     */
1002    if (rtems_bsdnet_nameserver_count) {
1003      int        i;
1004      char       buf[64];
1005      const char *bufl[1];
1006
1007      bufl[0] = buf;
1008     
1009#define MKFILE_MODE (S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH)
1010     
1011      if (rtems_bsdnet_domain_name &&
1012          (strlen(rtems_bsdnet_domain_name) < (sizeof(buf) - 1))) {
1013        strcpy(buf, "search ");
1014        strcat(buf, rtems_bsdnet_domain_name);
1015        strcat(buf, "\n");
1016        rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl);
1017      }
1018
1019      for (i = 0; i < rtems_bsdnet_nameserver_count; i++) {
1020        strcpy(buf, "nameserver ");
1021        strcat(buf, inet_ntoa(rtems_bsdnet_ntpserver[i]));
1022        strcat(buf, "\n");
1023        if (rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl))
1024          break;
1025      }
1026    }
1027  }
1028 
1029  /*
1030   * Configure the interface with the new settings
1031   */
1032  error = bootpc_adjust_interface (&ireq, so,
1033                                   &myaddr, &dhcp_netmask, &dhcp_gw, procp);
1034
1035  /*
1036   * Start the DHCP task if the lease isn't infinite.
1037   */
1038  if (dhcp_lease_time != 0xffffffff)
1039    dhcp_start_task (sdl, &reply, 150);
1040 
1041  soclose (so);
1042}
1043
1044/*
1045 *
1046 *  RTEMS Entry point to DHCP client
1047 *
1048 */
1049void rtems_bsdnet_do_dhcp (void)
1050{
1051  rtems_bsdnet_semaphore_obtain ();
1052  dhcp_init (TRUE);
1053  rtems_bsdnet_semaphore_release ();
1054}
1055
1056void
1057rtems_bsdnet_do_dhcp_refresh_only (unsigned long xid,
1058                                   unsigned long lease_time,
1059                                   unsigned long elapsed_time,
1060                                   unsigned long ip_address,
1061                                   unsigned long srv_address,
1062                                   const char*   hostname)
1063{
1064  struct dhcp_packet reply;
1065  struct ifnet       *ifp = NULL;
1066  struct ifaddr      *ifa = NULL;
1067  struct sockaddr_dl *sdl = NULL;
1068  struct sockaddr_in *sin = NULL;
1069  int                match = 0;
1070  struct ifnet       *mtif = NULL;
1071
1072  /*
1073   * If an infinite lease has been granted, no task is needed.
1074   */
1075  if (lease_time == 0xffffffff)
1076    return;
1077 
1078  /*
1079   * Find a network interface.
1080   */
1081  for (ifp = ifnet; (ifp != NULL) && !match; ifp = ifp->if_next)
1082    if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0)
1083      for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
1084        if (ifa->ifa_addr->sa_family == AF_INET)
1085        {
1086          sin = (struct sockaddr_in *) ifa->ifa_addr;
1087          if (sin->sin_addr.s_addr == htonl (ip_address))
1088          {
1089            mtif = ifp;
1090            match = 1;
1091            break;
1092          }
1093        }
1094
1095  if (!match)
1096    panic ("dhcpc: no matching interface");
1097
1098  for (ifa = mtif->if_addrlist; ifa != NULL; ifa = ifa->ifa_next)
1099    if (ifa->ifa_addr->sa_family == AF_LINK &&
1100        (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) &&
1101        sdl->sdl_type == IFT_ETHER)
1102      break;
1103 
1104  if (!match)
1105    panic ("dhcpc: no matching interface");
1106
1107  /*
1108   * Set up given values in a simulated DHCP reply.
1109   */
1110  memset (&reply, 0x00, sizeof (reply));
1111  reply.xid = htonl (xid);
1112  reply.yiaddr.s_addr = htonl (ip_address);
1113  reply.siaddr.s_addr = htonl (srv_address);
1114  if (reply.siaddr.s_addr != rtems_bsdnet_bootp_server_address.s_addr)
1115  {
1116    memcpy (&rtems_bsdnet_bootp_server_address, &reply.siaddr,
1117            sizeof (reply.siaddr));
1118  }
1119
1120  dhcp_lease_time = lease_time;
1121  dhcp_elapsed_time = elapsed_time;
1122 
1123  if (hostname)
1124  {
1125    sethostname ((char *) hostname, strlen (hostname));
1126    dhcp_hostname = bootp_strdup_realloc (dhcp_hostname, hostname);
1127  }
1128
1129  dhcp_start_task (sdl, &reply, 150);
1130}
1131
1132#undef D_COMPILING_BSD_KERNEL
1133#undef KERNEL
Note: See TracBrowser for help on using the repository browser.