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

4.11
Last change on this file since c62129c5 was c62129c5, checked in by Martin Galvan <martin.galvan@…>, on 09/02/15 at 21:54:25

cpukit/libnetworking/rtems/rtems_dhcp.c: Fix leak on realloc failure for dhcp_hostname.

Closes #2405.

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