mirror of
https://github.com/apache/nuttx-apps.git
synced 2025-10-21 06:11:35 +08:00
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.
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user