source: rtems/cpukit/libnetworking/rtems/rtems_dhcp.c @ 787f51f

5
Last change on this file since 787f51f was 787f51f, checked in by Sebastian Huber <sebastian.huber@…>, on 06/06/17 at 09:08:16

Do not include <sys/ioctl.h> in kernel-space

Update #2833.

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