summaryrefslogtreecommitdiff
path: root/apps/nshlib/nsh_netinit.c
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-08-17 09:51:26 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-08-17 09:51:26 -0600
commit45ae398fe34e373700a02e08c0f779e572862525 (patch)
treea48ee28cc5816be0ba00d12d5f26b4367dc37dde /apps/nshlib/nsh_netinit.c
parent83bd793f672c95bc632b1467f7e090ca7a6b4038 (diff)
downloadpx4-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.c289
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
}