diff options
author | Chris Johns <chrisj@rtems.org> | 2008-05-01 02:57:49 +0000 |
---|---|---|
committer | Chris Johns <chrisj@rtems.org> | 2008-05-01 02:57:49 +0000 |
commit | 50303dfbd1c7cd9f101242908eaf0404c58b4af7 (patch) | |
tree | 4ce817d7cd613fe32d5968ca6b440f44d1b68df9 /cpukit/libnetworking | |
parent | 2008-04-30 Joel Sherrill <joel.sherrill@oarcorp.com> (diff) | |
download | rtems-50303dfbd1c7cd9f101242908eaf0404c58b4af7.tar.bz2 |
2008-05-01 Maarten Van Es <maarten@mind.be>
* libnetworking/rtems/rtems_dhcp.c: Removed panic()s. Added
interface for rtems_dhcp_failsafe.
* libnetworking/rtems/rtems_dhcp.h: Added interface for
rtems_dhcp_failsafe.
2008-05-01 Arnout Vandecappelle <arnout@mind.be>
* libnetworking/nfs/bootp_subr: Allow some errors for sosend() and
return on timeout in bootpc_call(). Removed panic()s.
* libnetworking/rtems/rtems_glue.c: Fix the cast for the
SIOCAIFADDR ioctl call.
* libnetworking/rtems/rtems_dhcp_failsafe.c,
libnetworking/rtems/rtems_dhcp_failsafe.h: New.
* libnetworking/Makefile.am, libnetworking/preinstall.am: Added
rtems_dhcp_failsafe.c and rtems_dhcp_failsafe.h files.
Diffstat (limited to 'cpukit/libnetworking')
-rw-r--r-- | cpukit/libnetworking/Makefile.am | 5 | ||||
-rw-r--r-- | cpukit/libnetworking/nfs/bootp_subr.c | 183 | ||||
-rw-r--r-- | cpukit/libnetworking/preinstall.am | 4 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/dhcp.h | 2 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_dhcp.c | 238 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_dhcp_failsafe.c | 372 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_dhcp_failsafe.h | 29 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_glue.c | 2 |
8 files changed, 692 insertions, 143 deletions
diff --git a/cpukit/libnetworking/Makefile.am b/cpukit/libnetworking/Makefile.am index a75e4e5fc4..e07ec5f3df 100644 --- a/cpukit/libnetworking/Makefile.am +++ b/cpukit/libnetworking/Makefile.am @@ -112,12 +112,13 @@ include_nfsclient_HEADERS = nfsclient/nfsargs.h nfsclient/nfsdiskless.h include_rtemsdir = $(includedir)/rtems include_rtems_HEADERS = rtems/rtems_bsdnet.h rtems/rtems_bsdnet_internal.h \ - rtems/dhcp.h rtems/tftp.h rtems/ftpfs.h rtems/mkrootfs.h + rtems/dhcp.h rtems/rtems_dhcp_failsafe.h rtems/tftp.h rtems/ftpfs.h \ + rtems/mkrootfs.h include_rtems_HEADERS += rtems/rtems_mii_ioctl.h libnetworking_a_SOURCES += rtems/sghostname.c rtems/issetugid.c \ rtems/rtems_glue.c rtems/rtems_malloc_mbuf.c rtems/rtems_syscall.c \ - rtems/rtems_bootp.c rtems/rtems_dhcp.c \ + rtems/rtems_bootp.c rtems/rtems_dhcp.c rtems/rtems_dhcp_failsafe.c \ rtems/rtems_showmbuf.c rtems/rtems_showroute.c rtems/rtems_showifstat.c \ rtems/rtems_showipstat.c rtems/rtems_showicmpstat.c \ rtems/rtems_showtcpstat.c rtems/rtems_showudpstat.c rtems/rtems_select.c \ diff --git a/cpukit/libnetworking/nfs/bootp_subr.c b/cpukit/libnetworking/nfs/bootp_subr.c index 64753f178b..a6bbe67a68 100644 --- a/cpukit/libnetworking/nfs/bootp_subr.c +++ b/cpukit/libnetworking/nfs/bootp_subr.c @@ -78,7 +78,7 @@ /* * What is the longest we will wait before re-sending a request? * Note this is also the frequency of "RPC timeout" messages. - * The re-send loop count sup linearly to this maximum, so the + * The re-send loop counts up linearly to this maximum, so the * first complaint will happen after (1+2+3+4+5)=15 seconds. */ #define MAX_RESEND_DELAY 5 /* seconds */ @@ -377,8 +377,7 @@ bootpc_call(call,reply,procp) * but delay each re-send by an increasing amount. * If the delay hits the maximum, start complaining. */ - timo = 0; - for (;;) { + for (timo=1; timo <= MAX_RESEND_DELAY; timo++) { /* Send BOOTP request (or re-send). */ aio.iov_base = (caddr_t) call; @@ -391,20 +390,24 @@ bootpc_call(call,reply,procp) auio.uio_offset = 0; auio.uio_resid = sizeof(*call); auio.uio_procp = procp; - error = sosend(so, nam, &auio, NULL, NULL, 0); if (error) { printf("bootpc_call: sosend: %d\n", error); - goto out; + switch (error) { + case ENOBUFS: /* No buffer space available */ + case ENETUNREACH: /* Network is unreachable */ + case ENETDOWN: /* Network interface is not configured */ + case EHOSTDOWN: /* Host is down */ + case EHOSTUNREACH: /* Host is unreachable */ + case EMSGSIZE: /* Message too long */ + /* This is a possibly transient error. + We can still receive replies from previous attempts. */ + break; + default: + goto out; + } } - /* Determine new timeout. */ - if (timo < MAX_RESEND_DELAY) - timo++; - else - printf("BOOTP timeout for server 0x%x\n", - (int)ntohl(sin->sin_addr.s_addr)); - /* * Wait for up to timo seconds for a reply. * The socket receive timeout was set to 1 second. @@ -455,6 +458,9 @@ bootpc_call(call,reply,procp) } /* while secs */ } /* forever send/receive */ + printf("BOOTP timeout for server 0x%x\n", + (int)ntohl(sin->sin_addr.s_addr)); + error = ETIMEDOUT; goto out; @@ -482,18 +488,21 @@ bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so, * IFF_UP set blindly, interface selection can be clobbered. */ error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, procp); - if (error) - panic("bootpc_fakeup_interface: GIFFLAGS, error=%d", error); + if (error) { + printf("bootpc_fakeup_interface: GIFFLAGS, error=%s\n", strerror(error)); + return error; + } ireq->ifr_flags |= IFF_UP; error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, procp); - if (error) - panic("bootpc_fakeup_interface: SIFFLAGS, error=%d", error); + if (error) { + printf("bootpc_fakeup_interface: SIFFLAGS, error=%s\n", strerror(error)); + return error; + } /* * Do enough of ifconfig(8) so that the chosen interface * can talk to the servers. (just set the address) */ - /* addr is 0.0.0.0 */ sin = (struct sockaddr_in *)&ireq->ifr_addr; @@ -502,8 +511,10 @@ bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so, sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp); - if (error) - panic("bootpc_fakeup_interface: set if addr, error=%d", error); + if (error) { + printf("bootpc_fakeup_interface: set if addr, error=%s\n", strerror(error)); + return error; + } /* netmask is 0.0.0.0 */ @@ -513,8 +524,10 @@ bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so, sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp); - if (error) - panic("bootpc_fakeup_interface: set if net addr, error=%d", error); + if (error) { + printf("bootpc_fakeup_interface: set if netmask, error=%s\n", strerror(error)); + return error; + } /* Broadcast is 255.255.255.255 */ @@ -524,8 +537,11 @@ bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so, sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_BROADCAST; error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp); - if (error) - panic("bootpc_fakeup_interface: set if broadcast addr, error=%d", error); + if (error) { + printf("bootpc_fakeup_interface: set broadcast addr, error=%s\n", strerror(error)); + return error; + } + /* Add default route to 0.0.0.0 so we can send data */ @@ -601,8 +617,10 @@ bootpc_adjust_interface(struct ifreq *ireq,struct socket *so, */ bcopy(netmask,&ireq->ifr_addr,sizeof(*netmask)); error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp); - if (error) - panic("nfs_boot: set if netmask, error=%d", error); + if (error) { + printf("bootpc_adjust_interface: set netmask, error=%s\n", strerror(error)); + return error; + } /* Broadcast is with host part of IP address all 1's */ @@ -612,13 +630,17 @@ bootpc_adjust_interface(struct ifreq *ireq,struct socket *so, sin->sin_family = AF_INET; sin->sin_addr.s_addr = myaddr->sin_addr.s_addr | ~ netmask->sin_addr.s_addr; error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp); - if (error) - panic("bootpc_call: set if broadcast addr, error=%d", error); + if (error) { + printf("bootpc_adjust_interface: set broadcast addr, error=%s\n", strerror(error)); + return error; + } bcopy(myaddr,&ireq->ifr_addr,sizeof(*myaddr)); error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp); - if (error) - panic("nfs_boot: set if addr, error=%d", error); + if (error) { + printf("bootpc_adjust_interface: set if addr, error=%s\n", strerror(error)); + return error; + } /* Add new default route */ @@ -628,11 +650,10 @@ bootpc_adjust_interface(struct ifreq *ireq,struct socket *so, (struct sockaddr *) &oldmask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL); if (error) { - printf("nfs_boot: add net route, error=%d\n", error); - return error; + printf("bootpc_adjust_interface: add net route, error=%d\n", error); } - return 0; + return error; } #if !defined(__rtems__) @@ -758,24 +779,30 @@ processOptions (unsigned char *optbuf, int optbufSize) switch (code) { case 1: /* Subnet mask */ - if (len!=4) - panic("bootpc: subnet mask len is %d",len); + if (len!=4) { + printf("bootpc: subnet mask len is %d\n",len); + continue; + } bcopy (p, &dhcp_netmask.sin_addr, 4); dhcp_gotnetmask = 1; break; case 2: /* Time offset */ - if (len!=4) - panic("bootpc: time offset len is %d",len); + if (len!=4) { + printf("bootpc: time offset len is %d\n",len); + continue; + } bcopy (p, &rtems_bsdnet_timeoffset, 4); rtems_bsdnet_timeoffset = ntohl (rtems_bsdnet_timeoffset); break; case 3: /* Routers */ - if (len % 4) - panic ("bootpc: Router Len is %d", len); + if (len % 4) { + printf ("bootpc: Router Len is %d\n", len); + continue; + } if (len > 0) { bcopy(p, &dhcp_gw.sin_addr, 4); dhcp_gotgw = 1; @@ -784,8 +811,10 @@ processOptions (unsigned char *optbuf, int optbufSize) case 42: /* NTP servers */ - if (len % 4) - panic ("bootpc: time server Len is %d", len); + if (len % 4) { + printf ("bootpc: time server Len is %d\n", len); + continue; + } { int tlen = 0; while ((tlen < len) && @@ -804,8 +833,10 @@ processOptions (unsigned char *optbuf, int optbufSize) case 6: /* Domain Name servers */ - if (len % 4) - panic ("bootpc: DNS Len is %d", len); + if (len % 4) { + printf ("bootpc: DNS Len is %d", len); + continue; + } { int dlen = 0; while ((dlen < len) && @@ -824,18 +855,23 @@ processOptions (unsigned char *optbuf, int optbufSize) case 12: /* Host name */ - if (len>=MAXHOSTNAMELEN) - panic ("bootpc: hostname >=%d bytes", MAXHOSTNAMELEN); - if (sethostname ((char *)p, len) < 0) - panic("Can't set host name"); + if (len>=MAXHOSTNAMELEN) { + printf ("bootpc: hostname >=%d bytes", MAXHOSTNAMELEN); + continue; + } + if (sethostname ((char *)p, len) < 0) { + printf("bootpc: Can't set host name"); + } printf("Hostname is %s\n", p); dhcp_hostname = bootp_strdup_realloc(dhcp_hostname,(char *)p); break; case 7: /* Log servers */ - if (len % 4) - panic ("bootpc: Log server Len is %d", len); + if (len % 4) { + printf ("bootpc: Log server Len is %d", len); + continue; + } if (len > 0) { bcopy(p, &rtems_bsdnet_log_host_address, 4); dhcp_gotlogserver = 1; @@ -856,8 +892,10 @@ processOptions (unsigned char *optbuf, int optbufSize) case 52: /* DHCP option override */ - if (len != 1) - panic ("bootpc: DHCP option overload len is %d", len); + if (len != 1) { + printf ("bootpc: DHCP option overload len is %d", len); + continue; + } dhcpOptionOverload = p[0]; break; @@ -872,8 +910,10 @@ processOptions (unsigned char *optbuf, int optbufSize) */ case 54: /* DHCP server */ - if (len != 4) - panic ("bootpc: DHCP server len is %d", len); + if (len != 4) { + printf ("bootpc: DHCP server len is %d", len); + continue; + } bcopy(p, &rtems_bsdnet_bootp_server_address, 4); dhcp_gotserver = 1; break; @@ -955,20 +995,23 @@ bootpc_init(int update_files) if ((ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) break; - if (ifp == NULL) - panic("bootpc_init: no suitable interface"); + if (ifp == NULL) { + printf("bootpc_init: no suitable interface\n"); + return; + } bzero(&ireq,sizeof(ireq)); sprintf(ireq.ifr_name, "%s%d", ifp->if_name,ifp->if_unit); printf("bootpc_init: using network interface '%s'\n", ireq.ifr_name); - if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp)) != 0) - panic("nfs_boot: socreate, error=%d", error); - - bootpc_fakeup_interface(&ireq,so,procp); + if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp)) != 0) { + printf("bootpc_init: socreate, error=%d", error); + return; + } + if (bootpc_fakeup_interface(&ireq,so,procp) != 0) { + return; + } - printf("Bootpc testing starting\n"); - /* Get HW address */ for (ifa = ifp->if_addrlist;ifa; ifa = ifa->ifa_next) @@ -977,11 +1020,15 @@ bootpc_init(int update_files) sdl->sdl_type == IFT_ETHER) break; - if (!sdl) - panic("bootpc: Unable to find HW address"); - if (sdl->sdl_alen != EALEN ) - panic("bootpc: HW address len is %d, expected value is %d", - sdl->sdl_alen,EALEN); + if (!sdl) { + printf("bootpc: Unable to find HW address\n"); + return; + } + if (sdl->sdl_alen != EALEN ) { + printf("bootpc: HW address len is %d, expected value is %d\n", + sdl->sdl_alen,EALEN); + return; + } printf("bootpc hw address is "); delim=""; @@ -1018,8 +1065,10 @@ bootpc_init(int update_files) error = bootpc_call(&call,&reply,procp); - if (error) - panic("BOOTP call failed -- error %d", error); + if (error) { + printf("BOOTP call failed -- error %d", error); + return; + } /* * Initialize network address structures diff --git a/cpukit/libnetworking/preinstall.am b/cpukit/libnetworking/preinstall.am index 6637892502..090c09ffef 100644 --- a/cpukit/libnetworking/preinstall.am +++ b/cpukit/libnetworking/preinstall.am @@ -290,6 +290,10 @@ $(PROJECT_INCLUDE)/rtems/dhcp.h: rtems/dhcp.h $(PROJECT_INCLUDE)/rtems/$(dirstam $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/dhcp.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/dhcp.h +$(PROJECT_INCLUDE)/rtems/rtems_dhcp_failsafe.h: rtems/rtems_dhcp_failsafe.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtems_dhcp_failsafe.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtems_dhcp_failsafe.h + $(PROJECT_INCLUDE)/rtems/tftp.h: rtems/tftp.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/tftp.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/tftp.h diff --git a/cpukit/libnetworking/rtems/dhcp.h b/cpukit/libnetworking/rtems/dhcp.h index f8cde76a41..fde94b8e4d 100644 --- a/cpukit/libnetworking/rtems/dhcp.h +++ b/cpukit/libnetworking/rtems/dhcp.h @@ -29,6 +29,8 @@ extern "C" * Perform DHCP. */ void rtems_bsdnet_do_dhcp (void); +int rtems_bsdnet_do_dhcp_timeout (void); +void rtems_bsdnet_dhcp_down (void); /* * Maintain a DHCP offer that has already been accepted. diff --git a/cpukit/libnetworking/rtems/rtems_dhcp.c b/cpukit/libnetworking/rtems/rtems_dhcp.c index db5783269b..16e5952f6b 100644 --- a/cpukit/libnetworking/rtems/rtems_dhcp.c +++ b/cpukit/libnetworking/rtems/rtems_dhcp.c @@ -10,6 +10,12 @@ */ /* + * Added interface to terminate DHCP task, and removed panics. + * Arnout Vandecappelle <arnout@mind.be>, Essensium/Mind + * Maarten Van Es <maarten@mind.be>, Essensium/Mind + */ + +/* * Copyright (c) 1995 Gordon Ross, Adam Glass * Copyright (c) 1992 Regents of the University of California. * All rights reserved. @@ -186,7 +192,6 @@ extern int bootpc_adjust_interface (struct ifreq *ireq, struct proc *procp); extern void *bootp_strdup_realloc (char *dst, const char *src); -extern int nfs_diskless_valid; /* * Variables @@ -271,6 +276,8 @@ process_options (unsigned char *optbuf, int optbufSize) int code, ncode; char *p; + dhcp_message_type = 0; + ncode = optbuf[0]; while (j < optbufSize) { @@ -303,24 +310,30 @@ process_options (unsigned char *optbuf, int optbufSize) { case 1: /* Subnet mask */ - if (len != 4) - panic ("dhcpc: subnet mask len is %d", len); + if (len != 4) { + printf ("dhcpc: subnet mask len is %d\n", len); + continue; + } memcpy (&dhcp_netmask.sin_addr, p, 4); dhcp_gotnetmask = 1; break; case 2: /* Time offset */ - if (len != 4) - panic ("dhcpc: time offset len is %d", len); + if (len != 4) { + printf ("dhcpc: time offset len is %d\n", len); + continue; + } memcpy (&rtems_bsdnet_timeoffset, p, 4); rtems_bsdnet_timeoffset = ntohl (rtems_bsdnet_timeoffset); break; case 3: /* Routers */ - if (len % 4) - panic ("dhcpc: Router Len is %d", len); + if (len % 4) { + printf ("dhcpc: Router Len is %d\n", len); + continue; + } if (len > 0) { memcpy (&dhcp_gw.sin_addr, p, 4); @@ -330,8 +343,10 @@ process_options (unsigned char *optbuf, int optbufSize) case 42: /* NTP servers */ - if (len % 4) - panic ("dhcpc: time server Len is %d", len); + if (len % 4) { + printf ("dhcpc: time server Len is %d\n", len); + continue; + } { int tlen = 0; while ((tlen < len) && @@ -349,8 +364,10 @@ process_options (unsigned char *optbuf, int optbufSize) case 6: /* Domain Name servers */ - if (len % 4) - panic ("dhcpc: DNS Len is %d", len); + if (len % 4) { + printf ("dhcpc: DNS Len is %d\n", len); + continue; + } { int dlen = 0; while ((dlen < len) && @@ -368,10 +385,12 @@ process_options (unsigned char *optbuf, int optbufSize) case 12: /* Host name */ - if (len >= MAXHOSTNAMELEN) - panic ("dhcpc: hostname >= %d bytes", MAXHOSTNAMELEN); + if (len >= MAXHOSTNAMELEN) { + printf ("dhcpc: hostname >= %d bytes\n", MAXHOSTNAMELEN); + len = MAXHOSTNAMELEN-1; + } if (sethostname (p, len) < 0) - panic ("dhcpc: can't set host name"); + printf ("dhcpc: can't set host name"); if (dhcp_hostname != NULL) { dhcp_hostname = realloc (dhcp_hostname, len); @@ -383,8 +402,10 @@ process_options (unsigned char *optbuf, int optbufSize) case 7: /* Log servers */ - if (len % 4) - panic ("dhcpc: Log server Len is %d", len); + if (len % 4) { + printf ("dhcpc: Log server Len is %d\n", len); + continue; + } if (len > 0) { memcpy (&rtems_bsdnet_log_host_address, p, 4); @@ -406,7 +427,7 @@ process_options (unsigned char *optbuf, int optbufSize) case 50: /* DHCP Requested IP Address */ if (len != 4) - panic ("dhcpc: DHCP option requested IP len is %d", len); + printf ("dhcpc: DHCP option requested IP len is %d", len); /* * although nothing happens here, this case keeps the client * from complaining about unknown options. The Requested IP @@ -416,23 +437,29 @@ process_options (unsigned char *optbuf, int optbufSize) case 51: /* DHCP Lease Length */ - if (len != 4) - panic ("dhcpc: DHCP option lease-length len is %d", len); + if (len != 4) { + printf ("dhcpc: DHCP option lease-length len is %d", len); + continue; + } memcpy (&dhcp_lease_time, &p[0], 4); dhcp_lease_time = ntohl (dhcp_lease_time); break; case 52: /* DHCP option override */ - if (len != 1) - panic ("dhcpc: DHCP option overload len is %d", len); + if (len != 1) { + printf ("dhcpc: DHCP option overload len is %d", len); + continue; + } dhcp_option_overload = p[0]; break; case 53: /* DHCP message */ - if (len != 1) - panic ("dhcpc: DHCP message len is %d", len); + if (len != 1) { + printf ("dhcpc: DHCP message len is %d", len); + continue; + } dhcp_message_type = p[0]; break; @@ -447,8 +474,10 @@ process_options (unsigned char *optbuf, int optbufSize) */ case 54: /* DHCP server */ - if (len != 4) - panic ("dhcpc: DHCP server len is %d", len); + if (len != 4) { + printf ("dhcpc: DHCP server len is %d", len); + continue; + } memcpy (&rtems_bsdnet_bootp_server_address, p, 4); dhcp_gotserver = 1; break; @@ -667,13 +696,28 @@ dhcp_task (rtems_task_argument _sdl) unsigned int timeout = 0; int error; struct proc *procp = NULL; + int disconnected; sdl = (struct sockaddr_dl *) _sdl; count = dhcp_elapsed_time; - + disconnected = 0; + + while (TRUE) { + /* + * Sleep until the next poll + */ + timeout = TOD_MILLISECONDS_TO_TICKS (1000); + rtems_event_receive (RTEMS_EVENT_0, + RTEMS_WAIT | RTEMS_EVENT_ANY, + timeout, &event_out); + + if(event_out & RTEMS_EVENT_0) break; + + count++; + if (count >= (dhcp_lease_time / 2)) { rtems_bsdnet_semaphore_obtain (); @@ -684,10 +728,12 @@ dhcp_task (rtems_task_argument _sdl) * Send the Request. */ error = bootpc_call (&call, &dhcp_req, procp); - - if (error) - panic ("DHCP call failed -- error %d", error); - + if (error) { + rtems_bsdnet_semaphore_release (); + printf ("DHCP call failed -- error %d", error); + continue; + } + /* * Check for DHCP ACK/NACK */ @@ -696,7 +742,8 @@ dhcp_task (rtems_task_argument _sdl) sizeof (dhcp_magic_cookie)) != 0) { rtems_bsdnet_semaphore_release (); - panic ("DHCP server did not send Magic Cookie.\n"); + printf ("DHCP server did not send Magic Cookie.\n"); + continue; } process_options (&dhcp_req.vend[4], sizeof (dhcp_req.vend) - 4); @@ -704,23 +751,21 @@ dhcp_task (rtems_task_argument _sdl) if (dhcp_message_type != DHCP_ACK) { rtems_bsdnet_semaphore_release (); - panic ("DHCP server did not accept the DHCP request"); + printf ("DHCP server did not accept the DHCP request"); + continue; } rtems_bsdnet_semaphore_release (); count = 0; } - - /* - * Sleep until the next poll - */ - timeout = TOD_MILLISECONDS_TO_TICKS (1000); - rtems_event_receive (RTEMS_EVENT_0, - RTEMS_WAIT | RTEMS_EVENT_ANY, - timeout, &event_out); - count++; } + + + dhcp_task_id = 0; + printf ("dhcpc: exiting lease renewal task.\n"); + rtems_task_delete( RTEMS_SELF); + } /* @@ -795,8 +840,12 @@ dhcp_interface_has_ip (struct ifreq *ireq, struct socket *so, struct proc *procp * DCHP Client Routine * - The first DHCP offer is always accepted * - No DHCP DECLINE message is sent if ARPing fails + * + * return value: + * 0: ok + * < 0: failed to startup or configure interface */ -void +int dhcp_init (int update_files) { struct dhcp_packet call; @@ -811,12 +860,6 @@ dhcp_init (int update_files) struct ifaddr *ifa; struct sockaddr_dl *sdl = NULL; struct proc *procp = NULL; - - /* - * If already filled in, don't touch it here - */ - if (nfs_diskless_valid) - return; /* * If we are to update the files create the root @@ -834,13 +877,18 @@ dhcp_init (int update_files) for (ifp = ifnet; ifp != 0; ifp = ifp->if_next) if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0) break; - if (ifp == NULL) - panic ("dhcpc_init: no suitable interface"); + if (ifp == NULL){ + printf ("dhcpc_init: no suitable interface\n"); + return -1; + } + memset (&ireq, 0, sizeof (ireq)); sprintf (ireq.ifr_name, "%s%d", ifp->if_name, ifp->if_unit); - if ((error = socreate (AF_INET, &so, SOCK_DGRAM, 0, procp)) != 0) - panic ("nfs_boot: socreate, error=%d", error); + if ((error = socreate (AF_INET, &so, SOCK_DGRAM, 0, procp)) != 0) { + printf ("dhcpc_init: socreate, error=%d\n", error); + return -1; + } if (!dhcp_interface_has_ip (&ireq, so, procp)) bootpc_fakeup_interface (&ireq, so, procp); @@ -854,11 +902,15 @@ dhcp_init (int update_files) sdl->sdl_type == IFT_ETHER) break; - if (!sdl) - panic ("dhcpc: Unable to find HW address"); - if (sdl->sdl_alen != EALEN) - panic ("dhcpc: HW address len is %d, expected value is %d", + if (!sdl){ + printf ("dhcpc_init: Unable to find HW address\n"); + return -1; + } + if (sdl->sdl_alen != EALEN) { + printf ("dhcpc_init: HW address len is %d, expected value is %d\n", sdl->sdl_alen, EALEN); + return -1; + } /* * Build the DHCP Discover @@ -869,19 +921,25 @@ dhcp_init (int update_files) * Send the Discover. */ error = bootpc_call (&call, &reply, procp); - if (error) - panic ("BOOTP call failed -- error %d", error); + if (error) { + printf ("BOOTP call failed -- error %d\n", error); + return -1; + } /* * Check for DHCP OFFER */ - if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0) - panic ("DHCP server did not send Magic Cookie.\n"); + if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0) { + printf ("DHCP server did not send Magic Cookie.\n"); + return -1; + } process_options (&reply.vend[4], sizeof (reply.vend) - 4); - if (dhcp_message_type != DHCP_OFFER) - panic ("DHCP server did not send a DHCP Offer.\n"); + if (dhcp_message_type != DHCP_OFFER) { + printf ("DHCP server did not send a DHCP Offer.\n"); + return -1; + } /* * Send a DHCP REQUEST @@ -889,19 +947,25 @@ dhcp_init (int update_files) dhcp_request_req (&call, &reply, sdl, TRUE); error = bootpc_call (&call, &reply, procp); - if (error) - panic ("BOOTP call failed -- error %d", error); + if (error) { + printf ("BOOTP call failed -- error %d\n", error); + return -1; + } /* * Check for DHCP ACK/NACK */ - if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0) - panic ("DHCP server did not send Magic Cookie.\n"); + if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0) { + printf ("DHCP server did not send Magic Cookie.\n"); + return -1; + } process_options (&reply.vend[4], sizeof (reply.vend) - 4); - if (dhcp_message_type != DHCP_ACK) - panic ("DHCP server did not accept the DHCP request"); + if (dhcp_message_type != DHCP_ACK) { + printf ("DHCP server did not accept the DHCP request\n"); + return -1; + } /* * Initialize network address structures @@ -1039,6 +1103,8 @@ dhcp_init (int update_files) dhcp_start_task (sdl, &reply, 150); soclose (so); + + return 0; } /* @@ -1049,10 +1115,32 @@ dhcp_init (int update_files) void rtems_bsdnet_do_dhcp (void) { rtems_bsdnet_semaphore_obtain (); - dhcp_init (TRUE); + while( dhcp_init (TRUE) < 0 ) { + rtems_bsdnet_semaphore_release(); + rtems_task_wake_after(TOD_MILLISECONDS_TO_TICKS(1000)); + rtems_bsdnet_semaphore_obtain (); + } rtems_bsdnet_semaphore_release (); } +int rtems_bsdnet_do_dhcp_timeout( void ) +{ + int return_value; + + rtems_bsdnet_semaphore_obtain (); + return_value = dhcp_init (FALSE); + rtems_bsdnet_semaphore_release (); + + return return_value; +} + +void rtems_bsdnet_dhcp_down (void) +{ + if(dhcp_task_id != 0) { + rtems_event_send (dhcp_task_id, RTEMS_EVENT_0); + } +} + void rtems_bsdnet_do_dhcp_refresh_only (unsigned long xid, unsigned long lease_time, @@ -1092,8 +1180,10 @@ rtems_bsdnet_do_dhcp_refresh_only (unsigned long xid, } } - if (!match) - panic ("dhcpc: no matching interface"); + if (!match) { + printf ("dhcpc: no matching interface\n"); + return; + } for (ifa = mtif->if_addrlist; ifa != NULL; ifa = ifa->ifa_next) if (ifa->ifa_addr->sa_family == AF_LINK && @@ -1101,8 +1191,10 @@ rtems_bsdnet_do_dhcp_refresh_only (unsigned long xid, sdl->sdl_type == IFT_ETHER) break; - if (!match) - panic ("dhcpc: no matching interface"); + if (!match) { + printf ("dhcpc: no matching interface address\n"); + return; + } /* * Set up given values in a simulated DHCP reply. diff --git a/cpukit/libnetworking/rtems/rtems_dhcp_failsafe.c b/cpukit/libnetworking/rtems/rtems_dhcp_failsafe.c new file mode 100644 index 0000000000..3f69882c33 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_dhcp_failsafe.c @@ -0,0 +1,372 @@ +/* + $Id$ + + Description: Wrapper around DHCP client to restart it when the interface + moves to another network. + + Authors: Arnout Vandecappelle <arnout@mind.be>, Essensium/Mind + Maarten Van Es <maarten@mind.be>, Essensium/Mind + (C) Septentrio 2008 + + The license and distribution terms for this file may be + found in the file LICENSE in this distribution or at + http://www.rtems.com/license/LICENSE. + + + To use this functionality, call rtems_bsdnet_do_dhcp_failsafe() or set it + as the bootp member of the rtems_bsdnet_config structure. + + The rtems_bsdnet_do_dhcp_failsafe() function provides the following + functionalities: + + * It starts DHCP on the first non-loopback, non-point-to-point interface. + Before DHCP is started, any existing IP address on that interface is + removed, as well as the default route. + + * If DHCP fails to acquire an address for whatever reason, the interface + is reconfigured with the static address provided in its + rtems_bsdnet_ifconfig structure, and the default route from + rtems_bsdnet_config is restored. + It is possible to change the address in the rtems_bsdnet_ifconfig structure + while the system is running. + + * Optionally, after the interface is configured (either with DHCP or + statically), a task is started to monitor it. When the interface remains + disconnected (i.e. its IFF_RUNNING flag is off) for NETWORK_FAIL_TIMEOUT + seconds, the dhcp lease renewal is stopped. As soon as the interface is + connected again, DHCP is started again as above. + If NETWORK_FAIL_TIMEOUT is set to 0, the monitor task is not started. + + * Optionally, when the interface is disconnected, it is also brought down + for NETWORK_DOWN_TIME seconds. Since this possibly makes the IFF_RUNNING + flag unuseable, the interface is brought up again before the flag is + polled. + If NETWORK_DOWN_TIME is set to 0, the interface is not brought down. + + * Optionally, before DHCP is started, we wait for BROADCAST_DELAY seconds. + This is necessary to allow some routers to perform spanning tree discovery. + + Note that DHCP doesn't work well with multiple interfaces: only one of them + is configured using DHCP, and we can't guarantee it's the same one that is + monitored by this function. + +*/ + +#include <rtems.h> +#include <rtems/error.h> +#include <rtems/rtems_bsdnet.h> +#include <rtems/rtems_bsdnet_internal.h> + +#include <string.h> +#include <stdio.h> +#include <errno.h> + +#include <rtems/dhcp.h> + +struct proc; /* Unused parameter of some functions. */ +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/route.h> +#include <netinet/in.h> /* for sockaddr_in */ +#include <net/if.h> /* for if.h */ +#include <net/if_var.h> /* for in_var.h */ +#include <netinet/in_var.h> /* for in_aliasreq */ +#include <sys/sockio.h> /* for ioctl definitions */ +#include <arpa/inet.h> /* for inet_addr, inet_ntop */ + + +#define NETWORK_FAIL_TIMEOUT 5 /* the number of seconds before the interface is considered disconnected */ +#define NETWORK_DOWN_TIME 30 /* number of seconds the interface remains down */ +#define BROADCAST_DELAY 0 /* Delay (seconds) before broadcasts are sent */ +#define DHCP_MONITOR_PRIORITY 250 /* Low priority */ + +/* + * returns 0 when successful, negative value for failure + */ +static int remove_address(const char *if_name) +{ + struct sockaddr_in address; + struct in_aliasreq ifra; + int retval = 0; + + memset (&address, '\0', sizeof (address)); + address.sin_len = sizeof (address); + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + + /* Remove old default route to 0.0.0.0 */ + if (rtems_bsdnet_rtrequest (RTM_DELETE, (struct sockaddr *)&address, NULL, + (struct sockaddr *)&address, + (RTF_UP | RTF_STATIC), NULL) < 0 ) { + printf ("Failed to delete default route: %s (%d)\n", strerror (errno), errno); + retval = -1; + } + + /* Remove old ip-address */ + if (rtems_bsdnet_ifconfig(if_name, SIOCGIFADDR, &address) < 0) { + printf ("Failed to get if address: %s (%d)\n", strerror (errno), errno); + return -1; + } + + strncpy (ifra.ifra_name, if_name, IFNAMSIZ); + memcpy (&ifra.ifra_addr, &address, sizeof(address)); + if (rtems_bsdnet_ifconfig(if_name, SIOCDIFADDR, &ifra)) { + printf ("Can't delete if address: %s (%d)\n", strerror (errno), errno); + return -1; + } + + return retval; +} + + +#if NETWORK_DOWN_TIME +static int +dhcp_if_down (const char* ifname) +{ + int flags; + if (rtems_bsdnet_ifconfig (ifname, SIOCGIFFLAGS, &flags) < 0) { + printf ("Can't get flags for %s: %s\n", ifname, strerror (errno)); + return -1; + } + if (flags & IFF_UP) { + flags &= ~IFF_UP; + if (rtems_bsdnet_ifconfig (ifname, SIOCSIFFLAGS, &flags) < 0) { + printf ("Can't bring %s down: %s\n", ifname, strerror (errno)); + return -1; + } + } + + return 0; +} +#endif + +static int +dhcp_if_up (const char* ifname) +{ + int flags; + if (rtems_bsdnet_ifconfig (ifname, SIOCGIFFLAGS, &flags) < 0) { + printf ("Can't get flags for %s: %s\n", ifname, strerror (errno)); + return -1; + } + if (!(flags & IFF_UP)) { + flags |= IFF_UP; + if (rtems_bsdnet_ifconfig (ifname, SIOCSIFFLAGS, &flags) < 0) { + printf ("Can't bring %s up: %s\n", ifname, strerror (errno)); + return -1; + } + } + + return 0; +} + + +static int +set_static_address (struct rtems_bsdnet_ifconfig *ifp) +{ + short flags; + struct sockaddr_in address; + struct sockaddr_in netmask; + struct sockaddr_in broadcast; + struct sockaddr_in gateway; + + if (ifp->ip_address != NULL) { + printf("Setting static address for interface %s.\n", ifp->name); + + /* + * Bring interface up + */ + if (dhcp_if_up (ifp->name) < 0) + return -1; + + /* + * Set interface netmask + */ + memset (&netmask, '\0', sizeof netmask); + netmask.sin_len = sizeof netmask; + netmask.sin_family = AF_INET; + netmask.sin_addr.s_addr = inet_addr (ifp->ip_netmask); + if (rtems_bsdnet_ifconfig (ifp->name, SIOCSIFNETMASK, &netmask) < 0) { + printf ("Can't set %s netmask: %s\n", ifp->name, strerror (errno)); + return -1; + } + + /* + * Set interface address + */ + memset (&address, '\0', sizeof address); + address.sin_len = sizeof address; + address.sin_family = AF_INET; + address.sin_addr.s_addr = inet_addr (ifp->ip_address); + if (rtems_bsdnet_ifconfig (ifp->name, SIOCSIFADDR, &address) < 0) { + printf ("Can't set %s address: %s\n", ifp->name, strerror (errno)); + return -1; + } + + /* + * Set interface broadcast address if the interface has the + * broadcast flag set. + */ + if (rtems_bsdnet_ifconfig (ifp->name, SIOCGIFFLAGS, &flags) < 0) { + printf ("Can't read %s flags: %s\n", ifp->name, strerror (errno)); + return -1; + } + if (flags & IFF_BROADCAST) { + memset (&broadcast, '\0', sizeof broadcast); + broadcast.sin_len = sizeof broadcast; + broadcast.sin_family = AF_INET; + broadcast.sin_addr.s_addr = address.sin_addr.s_addr | ~netmask.sin_addr.s_addr; + + if (rtems_bsdnet_ifconfig (ifp->name, SIOCSIFBRDADDR, &broadcast) < 0) { + struct in_addr in_addr; + char buf[20]; + + in_addr.s_addr = broadcast.sin_addr.s_addr; + if (!inet_ntop (AF_INET, &in_addr, buf, sizeof (buf))) + strcpy (buf, "?.?.?.?"); + printf ("Can't set %s broadcast address %s: %s\n", ifp->name, buf, strerror (errno)); + } + } + } + + /* + * Set default route + */ + if (rtems_bsdnet_config.gateway) { + address.sin_addr.s_addr = INADDR_ANY; + netmask.sin_addr.s_addr = INADDR_ANY; + memset (&gateway, '\0', sizeof gateway); + gateway.sin_len = sizeof gateway; + gateway.sin_family = AF_INET; + gateway.sin_addr.s_addr = inet_addr (rtems_bsdnet_config.gateway); + + if (rtems_bsdnet_rtrequest (RTM_ADD, + (struct sockaddr *) &address, + (struct sockaddr *) &gateway, + (struct sockaddr *) &netmask, + (RTF_UP | RTF_GATEWAY | RTF_STATIC), + NULL + ) < 0) { + printf ("Can't set default route: %s\n", strerror (errno)); + return -1; + } + } + + return 0; +} + +static void +do_dhcp_init (struct rtems_bsdnet_ifconfig *ifp) +{ +#if BROADCAST_DELAY + /* Wait before sending broadcast. */ + rtems_task_wake_after(TOD_MILLISECONDS_TO_TICKS(BROADCAST_DELAY * 1000)); +#endif + + printf ("starting dhcp client...\n"); + + remove_address(ifp->name); + if (rtems_bsdnet_do_dhcp_timeout () != 0) { + remove_address(ifp->name); + set_static_address (ifp); /* use static ip-address if dhcp failed */ + } + +} + +/* + * Main dhcp monitor thread + */ +static void dhcp_monitor_task (rtems_task_argument ifp_arg) +{ + struct rtems_bsdnet_ifconfig *ifp = (struct rtems_bsdnet_ifconfig *)ifp_arg; + char *ifname = ifp->name; + unsigned int downcount = 0; + int ifflags; + int must_renew = FALSE; + + while (TRUE) { + if (rtems_bsdnet_ifconfig(ifname, SIOCGIFFLAGS, &ifflags) < 0) { + printf ("Failed to get if flags: %s (%d)\n", strerror (errno), errno); + goto error_out; + } + + if ((ifflags & IFF_RUNNING) != 0) { + if(must_renew) { + must_renew = FALSE; + do_dhcp_init(ifp); + } + downcount = 0; + } else { + if (downcount < NETWORK_FAIL_TIMEOUT) { + downcount++; + + if (downcount == NETWORK_FAIL_TIMEOUT) { + printf ("lost network connection...\n"); + rtems_bsdnet_dhcp_down (); + must_renew = TRUE; +#if NETWORK_DOWN_TIME + dhcp_if_down(ifname); + rtems_task_wake_after(TOD_MILLISECONDS_TO_TICKS(NETWORK_DOWN_TIME * 1000)); + dhcp_if_up(ifname); + downcount = 0; +#endif + } + } + } + + rtems_task_wake_after(TOD_MILLISECONDS_TO_TICKS(1000)); + } + +error_out: + printf("Stopping dhcp monitoring application.\n"); + rtems_task_delete(RTEMS_SELF); +} + +/* +* initialize dhcp monitoring application +* start dhcp monitoring thread +*/ +void rtems_bsdnet_do_dhcp_failsafe (void) +{ + rtems_status_code sc; + rtems_id id; + struct rtems_bsdnet_ifconfig *ifp; + int ifflags; + + /* Find a suitable interface */ + for (ifp = rtems_bsdnet_config.ifconfig; ifp; ifp = ifp->next) { + if (rtems_bsdnet_ifconfig (ifp->name, SIOCGIFFLAGS, &ifflags) < 0) + continue; + if ((ifflags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0) + break; + } + if (ifp == NULL){ + printf ("dhcpc_failsafe: no suitable interface\n"); + return; + } + printf("starting dhcp on interface %s\n", ifp->name); + do_dhcp_init(ifp); + +#if NETWORK_FAIL_TIMEOUT + sc = rtems_task_create (rtems_build_name ('d','h','c','m'), + DHCP_MONITOR_PRIORITY, + 2048, + RTEMS_PREEMPT | + RTEMS_NO_TIMESLICE | + RTEMS_NO_ASR | + RTEMS_INTERRUPT_LEVEL (0), + RTEMS_LOCAL, + &id); + + if (sc != RTEMS_SUCCESSFUL) { + printf ("Failed to create dhcp monitor task, code %d\n", sc); + return; + } + + sc = rtems_task_start (id, dhcp_monitor_task, (rtems_task_argument) ifp); + + if (sc != RTEMS_SUCCESSFUL) { + printf ("Failed to start dhcp monitor task, code %d\n", sc); + } +#endif +} + diff --git a/cpukit/libnetworking/rtems/rtems_dhcp_failsafe.h b/cpukit/libnetworking/rtems/rtems_dhcp_failsafe.h new file mode 100644 index 0000000000..24c1c900c0 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_dhcp_failsafe.h @@ -0,0 +1,29 @@ +/* + $Id$ + + Description: Wrapper around DHCP client to restart it when the interface + moves to another network. + + Authors: Arnout Vandecappelle <arnout@mind.be>, Essensium/Mind + Maarten Van Es <maarten@mind.be>, Essensium/Mind + (C) Septentrio 2008 + + The license and distribution terms for this file may be + found in the file LICENSE in this distribution or at + http://www.rtems.com/license/LICENSE. +*/ + +#ifndef _RTEMS_DHCP_FAILSAFE_H_ +#define _RTEMS_DHCP_FAILSAFE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void rtems_bsdnet_do_dhcp_failsafe (void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cpukit/libnetworking/rtems/rtems_glue.c b/cpukit/libnetworking/rtems/rtems_glue.c index 88f05dad90..52db0e0f49 100644 --- a/cpukit/libnetworking/rtems/rtems_glue.c +++ b/cpukit/libnetworking/rtems/rtems_glue.c @@ -1127,7 +1127,7 @@ int rtems_bsdnet_ifconfig (const char *ifname, uint32_t cmd, void *param) case SIOCAIFADDR: case SIOCDIFADDR: - r = ioctl(s, cmd, (struct freq *) param); + r = ioctl(s, cmd, (struct ifreq *) param); break; default: |