source: rtems/cpukit/libnetworking/rtems/rtems_dhcp.c @ 046fe12b

4.104.115
Last change on this file since 046fe12b was 046fe12b, checked in by Chris Johns <chrisj@…>, on 04/28/09 at 11:12:03

2009-04-28 Chris Johns <chrisj@…>

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