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

5
Last change on this file since cb68253 was cb68253, checked in by Sebastian Huber <sebastian.huber@…>, on 09/07/18 at 04:19:02

network: Use kernel/user space header files

Add and use <machine/rtems-bsd-kernel-space.h> and
<machine/rtems-bsd-user-space.h> similar to the libbsd to avoid command
line defines and defines scattered throught the code base.

Simplify cpukit/libnetworking/Makefile.am.

Update #3375.

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