Page 1 of 1

GPIO LED showing network connection

Posted: Sat Feb 09, 2013 5:45 pm
by conradv
Hi,

I want to have a set of LEDs showing the state of the RPi. I have found that GPIO14 shows the state of the filesystem so that can be used to know if the system is on or off. However, I would like to add an LED to show if the network is connected or not. I know that the RPi has the onboard LEDs showing this state but I need to have an external LED to show the network state. Ideally, I would drive the LED from the GPIO pins and not solder directly on the RPi.

I have a sort of semi functional solution but when I unplug the network cable, it does not turn off the LED.

Code: Select all

#include <stdio.h>
#include <wiringPi.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>

#include <errno.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <stdlib.h>

#define NETLED	0

void show_address_info( struct ifaddrs *ifa ){
  struct sockaddr_in *s4;
  struct sockaddr_in6 *s6;
  /* ipv6 addresses have to fit in this buffer */
  char buf[64];

  if (AF_INET == ifa->ifa_addr->sa_family){
    s4 = (struct sockaddr_in *)(ifa->ifa_addr);
    if (NULL == inet_ntop(ifa->ifa_addr->sa_family, (void *)&(s4->sin_addr), buf, sizeof(buf))){
      printf("%s: inet_ntop failed!\n", ifa->ifa_name);
	digitalWrite(NETLED, 0);
    } else {
      printf("IPv4 addr %s: %s\n", ifa->ifa_name, buf);
	digitalWrite(NETLED, 1);
    }
  }
  else if (AF_INET6 == ifa->ifa_addr->sa_family) {
    s6 = (struct sockaddr_in6 *)(ifa->ifa_addr);
    if (NULL == inet_ntop(ifa->ifa_addr->sa_family, (void *)&(s6->sin6_addr), buf, sizeof(buf))) {
      printf("%s: inet_ntop failed!\n", ifa->ifa_name);
    } else {
      printf("IPv6 addr %s: %s\n", ifa->ifa_name, buf);
      }
  }

}


int main(int argc, char *argv[])
{
  if (wiringPiSetup () == -1)
    return 1 ;

  pinMode(NETLED, OUTPUT);
  
  struct ifaddrs *myaddrs, *ifa;
  int status;
  
for(;;){
  status = getifaddrs(&myaddrs);
  if (status != 0){
    perror("getifaddrs failed!");
    exit(1);
  }

  for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next){
    if (NULL == ifa->ifa_addr){
      continue;
    }
    if ((ifa->ifa_flags & IFF_UP) == 0) {
      continue;
    }
    show_address_info(ifa);
  }
  freeifaddrs(myaddrs);
  delay(1000);
}
  return 0;

}
Thanks in advance

Conrad

Re: GPIO LED showing network connection

Posted: Sat Feb 09, 2013 8:14 pm
I think your check is basically flawed - you're looking for the IP address on the interface - which is going to stay there if you unplug the cable - although it's possible that some "network managers" will remove the IP address if they detect that the cable is unplugged..

So... You need to go deeper to work out if the cable is unplugged, or hasn't had an address yet - so you can use the above to see if it's had an address ,but to see if the cable is unplugged then look at the mii-tool command.

e.g. sudo mii-tool eth0

I've actually no idea what that does internally, but the source code is available, so getting it and working out what it does to detect cable presence - or not would be your next task! (or you could just call mii-tool once a second and parse the ouput...)

-Gordon

Re: GPIO LED showing network connection

Posted: Sat Feb 09, 2013 10:12 pm
by bgreat
Here is a simple C application that will print the current state of an interface. You can enter the interface name as an argument, otherwise it defaults to eth0.

if_flags.c:

Code: Select all

/********************************************************************/
/* Simple network interface status application                      */
/* Opens a socket and gets the interface flags for the selected     */
/* interface (or eth0)                                              */
/*                                                                  */
/* Prints flag values of interest to stdout                         */
/*                                                                  */
/*  Build: gcc -o if_flags if_flags.c                               */
/*                                                                  */
/* W. Greathouse 9-Feb-2013                                         */
/*                                                                  */
/* Source code published "as is" and with no restrictions on use    */
/********************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>     
#include <sys/ioctl.h>  /* ioctl()  */
#include <sys/socket.h> /* socket() */
#include <arpa/inet.h>  
#include <unistd.h>     /* close()  */
#include <linux/if.h>   /* struct ifreq */

struct IF_FLAG_INFO { int flag; char *tstr; char *fstr; } if_flag_info[] =
{
    { IFF_UP,           "Interface Up",     "Interface Down",   },
    { IFF_BROADCAST,    "Broadcast",        "No broadcast",     },
    { IFF_DEBUG,        "Debug enabled",    NULL,               },
    { IFF_LOOPBACK,     "Loopback",         NULL,               },
    { IFF_POINTOPOINT,  "Point to Point",   NULL,               },
    { IFF_POINTOPOINT,  "No trailers",      NULL,               },
    { IFF_RUNNING,      "Running",          NULL,               },
    { IFF_NOARP,        "No ARP",           NULL,               },
    { IFF_PROMISC,      "Promiscuous mode", NULL,               },
    { IFF_ALLMULTI,     "Rcv all multicast",NULL,               },
    { IFF_MASTER,       "Master",           NULL,               },
    { IFF_SLAVE,        "Slave",            NULL,               },
    { IFF_MULTICAST,    "Multicast",        "No multicast"      },
    { 0,                NULL,               NULL,               }
};

int main(int argc, char* argv[])
{
    int i;
    int fd;
    int rc;
    struct ifreq ethreq;
    char *ifname = "eth0";

    if (argc > 1)
        ifname = argv[1];

    /* Open a dummy socket so we have a descriptor for ioctl */
    fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (fd < 0)
    {
        perror("socket");
        return(1);
    }

    memset(&ethreq, 0, sizeof(ethreq));

    /* set the name of the interface we wish to check */
    strncpy(ethreq.ifr_name, ifname, IFNAMSIZ);

    /* grab flags associated with this interface */
    rc = ioctl(fd, SIOCGIFFLAGS, &ethreq);
    if (rc < 0)
    {
        perror("ioctl");
        return(2);
    }

    printf("Flags for %s\n", ifname);
    for (i=0; if_flag_info[i].flag != 0; i++)
    {
        if (ethreq.ifr_flags & if_flag_info[i].flag && if_flag_info[i].tstr)
            printf("  %s\n", if_flag_info[i].tstr);
        else if (if_flag_info[i].fstr)
            printf("  %s\n", if_flag_info[i].fstr);
    }

    close(fd);

    return 0;
}
Example:

Code: Select all

[email protected] ~ $ ./if_flags
Flags for eth0
  Interface Up
  Broadcast
  Multicast
[email protected] ~ $ ./if_flags wlan0
Flags for wlan0
  Interface Up
  Broadcast
  Running
  Multicast
The "Running" state is probably of interest for determining if the network cable is connected/disconnected for eth0. In the example above, I do not have an Ethernet cable connected, so I do not have a "Running" status.

Enjoy!
Bill

Re: GPIO LED showing network connection

Posted: Sun Feb 10, 2013 8:02 pm
by conradv
Thanks for your suggestions. Will try them and will let you know the outcome.