diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-08-17 09:51:26 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-08-17 09:51:26 -0600 |
commit | 45ae398fe34e373700a02e08c0f779e572862525 (patch) | |
tree | a48ee28cc5816be0ba00d12d5f26b4367dc37dde /apps/nshlib/nsh_netinit.c | |
parent | 83bd793f672c95bc632b1467f7e090ca7a6b4038 (diff) | |
download | px4-nuttx-45ae398fe34e373700a02e08c0f779e572862525.tar.gz px4-nuttx-45ae398fe34e373700a02e08c0f779e572862525.tar.bz2 px4-nuttx-45ae398fe34e373700a02e08c0f779e572862525.zip |
Extend the NSH network initialization logic. There is now an option that will create a network monitor thread that will monitor the state of the link. When the link goes down, the code will attempt to gracefully put the Ethernet driver in a down state; When the link comes back, the code will attempt to bring the network back up.
Diffstat (limited to 'apps/nshlib/nsh_netinit.c')
-rw-r--r-- | apps/nshlib/nsh_netinit.c | 289 |
1 files changed, 285 insertions, 4 deletions
diff --git a/apps/nshlib/nsh_netinit.c b/apps/nshlib/nsh_netinit.c index 647d0eebd..e04591f7b 100644 --- a/apps/nshlib/nsh_netinit.c +++ b/apps/nshlib/nsh_netinit.c @@ -42,13 +42,30 @@ #include <nuttx/config.h> +/* Is network initialization debug forced on? */ + +#ifdef CONFIG_NSH_NETINIT_DEBUG +# undef CONFIG_DEBUG_VERBOSE +# define CONFIG_DEBUG_VERBOSE 1 +# undef CONFIG_DEBUG_NET +# define CONFIG_DEBUG_NET 1 +#endif + +#include <sys/ioctl.h> + +#include <stdint.h> +#include <unistd.h> +#include <string.h> #include <pthread.h> +#include <signal.h> #include <debug.h> #include <net/if.h> #include <arpa/inet.h> #include <netinet/in.h> +#include <nuttx/net/mii.h> + #include <apps/netutils/netlib.h> #if defined(CONFIG_NSH_DHCPC) || defined(CONFIG_NSH_DNS) # include <apps/netutils/dnsclient.h> @@ -83,6 +100,14 @@ # define NET_DEVNAME "eth0" #endif +/* While the network is up, the network monitor really does nothing. It + * will wait for a very long time while waiting, it can be awakened by a + * signal indicating a change in network status. + */ + +#define A_REALLY_LONG_TIME (60*60) /* One hour in seconds */ +#define A_SHORT_TIME (2) /* 2 seconds */ + /**************************************************************************** * Private Types ****************************************************************************/ @@ -96,14 +121,14 @@ ****************************************************************************/ /**************************************************************************** - * Name: nsh_netinit_thread + * Name: nsh_netinit_configure * * Description: * Initialize the network per the selected NuttX configuration * ****************************************************************************/ -pthread_addr_t nsh_netinit_thread(pthread_addr_t arg) +static void nsh_netinit_configure(void) { struct in_addr addr; #if defined(CONFIG_NSH_DHCPC) @@ -207,7 +232,263 @@ pthread_addr_t nsh_netinit_thread(pthread_addr_t arg) #endif nvdbg("Exit\n"); - return OK; +} + +/**************************************************************************** + * Name: nsh_netinit_signal + * + * Description: + * This signal handler responds to changes in PHY status. + * + ****************************************************************************/ + +#ifdef CONFIG_NSH_NETINIT_MONITOR +static void nsh_netinit_signal(int signo, FAR siginfo_t *siginfo, + FAR void * context) +{ + volatile bool *event = (volatile bool *)siginfo->si_value.sival_ptr; + + nlldbg("Entry: event=%p\n", event); + DEBUGASSERT(event); + *event = true; + nllvdbg("Exit\n"); +} +#endif + +/**************************************************************************** + * Name: nsh_netinit_monitor + * + * Description: + * Monitor link status, gracefully taking the link up and down as the + * link becomes available or as the link is lost. + * + ****************************************************************************/ + +#ifdef CONFIG_NSH_NETINIT_MONITOR +static int nsh_netinit_monitor(void) +{ + struct ifreq ifr; + struct sigaction act; + volatile bool event; + bool devup; + int ret; + int sd; + + nvdbg("Entry\n"); + + /* Get a socket descriptor that we can use to communicate with the network + * interface driver. + */ + + sd = socket(AF_INET, SOCK_DGRAM, 0); + if (sd < 0) + { + ret = -errno; + DEBUGASSERT(ret < 0); + + ndbg("ERROR: Failed to create a socket: %d\n", ret); + goto errout; + } + + /* Attach a signal handler so that we do not lose PHY events */ + + act.sa_sigaction = nsh_netinit_signal; + act.sa_flags = SA_SIGINFO; + + ret = sigaction(CONFIG_NSH_NETINIT_SIGNO, &act, NULL); + if (ret < 0) + { + ret = -errno; + DEBUGASSERT(ret < 0); + + ndbg("ERROR: sigaction() failed: %d\n", ret); + goto errout_with_socket; + } + + /* Configure to receive a signal on changes in link status */ + + strncpy(ifr.ifr_name, NET_DEVNAME, IFNAMSIZ); + ifr.ifr_mii_notify_pid = 0; /* PID=0 means this task */ + ifr.ifr_mii_notify_signo = CONFIG_NSH_NETINIT_SIGNO; + ifr.ifr_mii_notify_arg = (FAR void *)&event; + + ret = ioctl(sd, SIOCMIINOTIFY, (unsigned long)&ifr); + if (ret < 0) + { + ret = -errno; + DEBUGASSERT(ret < 0); + + ndbg("ERROR: ioctl(SIOCMIINOTIFY) failed: %d\n", ret); + goto errout_with_sigaction; + } + + /* Now loop, waiting for changes in link status */ + + for (;;) + { + /* This should catch any events that occur while we are not listening */ + + event = false; + + /* Does the driver think that the link is up or down? */ + + strncpy(ifr.ifr_name, NET_DEVNAME, IFNAMSIZ); + + ret = ioctl(sd, SIOCGIFFLAGS, (unsigned long)&ifr); + if (ret < 0) + { + ret = -errno; + DEBUGASSERT(ret < 0); + + ndbg("ERROR: ioctl(SIOCGIFFLAGS) failed: %d\n", ret); + goto errout_with_notification; + } + + devup = ((ifr.ifr_flags & IFF_UP) != 0); + + /* Get the current PHY address in use. This probably does not change, + * but just in case... + * + * NOTE: We are assuming that the network device name is preserved in + * the ifr structure. + */ + + ret = ioctl(sd, SIOCGMIIPHY, (unsigned long)&ifr); + if (ret < 0) + { + ret = -errno; + DEBUGASSERT(ret < 0); + + ndbg("ERROR: ioctl(SIOCGMIIPHY) failed: %d\n", ret); + goto errout_with_notification; + } + + /* Read the PHY status register */ + + ifr.ifr_mii_reg_num = MII_MSR; + + ret = ioctl(sd, SIOCGMIIREG, (unsigned long)&ifr); + if (ret < 0) + { + ret = -errno; + DEBUGASSERT(ret < 0); + + ndbg("ERROR: ioctl(SIOCGMIIREG) failed: %d\n", ret); + goto errout_with_notification; + } + + nvdbg("%s: devup=%d PHY address=%02x MSR=%04x\n", + devup, ifr.ifr_name, ifr.ifr_mii_phy_id, ifr.ifr_mii_val_out); + + /* Check for link up or down */ + + if ((ifr.ifr_mii_val_out & MII_MSR_LINKSTATUS) != 0) + { + /* Link up... does the drive think that the link is up? */ + + if (!devup) + { + /* No... We just transitioned from link down to link up. + * Bring the link up. + */ + + nvdbg("Bringing the link up\n"); + + ifr.ifr_flags = IFF_UP; + ret = ioctl(sd, SIOCSIFFLAGS, (unsigned long)&ifr); + if (ret < 0) + { + ret = -errno; + DEBUGASSERT(ret < 0); + + ndbg("ERROR: ioctl(SIOCSIFFLAGS) failed: %d\n", ret); + goto errout_with_notification; + } + + /* And wait for a short delay. We will want to recheck the + * link status again soon. + */ + + sleep(A_SHORT_TIME); + } + else + { + /* The link is still up. Take a long, well-deserved rest */ + + sleep(A_REALLY_LONG_TIME); + } + } + else + { + /* Link down... Was the driver link state already down? */ + + if (devup) + { + /* No... we just transitioned from link up to link down. Take + * the link down. + */ + + nvdbg("Taking the link down\n"); + + ifr.ifr_flags = IFF_DOWN; + ret = ioctl(sd, SIOCSIFFLAGS, (unsigned long)&ifr); + if (ret < 0) + { + ret = -errno; + DEBUGASSERT(ret < 0); + + ndbg("ERROR: ioctl(SIOCSIFFLAGS) failed: %d\n", ret); + goto errout_with_notification; + } + } + + /* In either case, wait for the short, configurable delay */ + + usleep(1000*CONFIG_NSH_NETINIT_RETRYMSEC); + } + } + + /* TODO: Stop the PHY notifications and remove the signal handler. This + * is important because the 'event' value is on the stack it is about to + * disappear! + */ + +errout_with_notification: +# warning Missing logic +errout_with_sigaction: +# warning Missing logic +errout_with_socket: + close(sd); +errout: + ndbg("Aborting\n"); + return ret; +} +#endif + +/**************************************************************************** + * Name: nsh_netinit_thread + * + * Description: + * Initialize the network per the selected NuttX configuration + * + ****************************************************************************/ + +static pthread_addr_t nsh_netinit_thread(pthread_addr_t arg) +{ + nvdbg("Entry\n"); + + /* Configure the network */ + + nsh_netinit_configure(); + +#ifdef CONFIG_NSH_NETINIT_MONITOR + /* Monitor the network status */ + + nsh_netinit_monitor(); +#endif + + nvdbg("Exit\n"); + return NULL; } /**************************************************************************** @@ -262,7 +543,7 @@ int nsh_netinit(void) #else /* Perform network initialization sequentially */ - (void)nsh_netinit_thread(NULL); + nsh_netinit_configure(); #endif } |