C code to look if the iface is up, using MII.

[ permalink ] [ download ]
/*

    This program is free software; you can redistribute it
    and/or modify it under the terms of the GNU General Public
    License as published by the Free Software Foundation.

    Based on David A. Hinds "mii-tools" code.

 */


#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <net/if.h>  
#include <string.h>
#include <errno.h>

//Necessary data, from mii.h

#include <linux/sockios.h>

#ifndef SIOCGMIIPHY
#define SIOCGMIIREG (SIOCDEVPRIVATE+1) 	/* Read any PHY register */
#endif

#include <linux/types.h>

/* This data structure is used for all the MII ioctl's */
struct mii_data {
    __u16	phy_id;
    __u16	reg_num;
    __u16	val_in;
    __u16	val_out;
};


#define MII_BMSR		0x01
#define MII_BMSR_LINK_VALID	0x0004
#define MII_BMCR		0x00

static struct ifreq ifr;

//set to 1 if you want more verbose
int verbose =1;


/*
 * This func ups the iface. using the socket ioctl iface.
 */

void int_up (int skfd, char* ifname)
{
    struct ifreq ifr;
    
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    
    if (skfd && ioctl(skfd, SIOCGIFFLAGS, &ifr) >= 0) {
        strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
        ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
         ioctl(skfd, SIOCSIFFLAGS, &ifr);
    }
}

void int_down (int skfd, char* ifname)
{
    struct ifreq ifr;
    
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    
    if (skfd && ioctl(skfd, SIOCGIFFLAGS, &ifr) >= 0) {
        strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
        ifr.ifr_flags &= ~IFF_UP;
        ioctl(skfd, SIOCSIFFLAGS, &ifr);
    }
}


/****************************************************************/

static int mdio_read(int skfd, int location)
{
    struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
    mii->reg_num = location;
    if (ioctl(skfd, SIOCGMIIREG, &ifr) < 0) {
	fprintf(stderr, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
		strerror(errno));
	return -1;
    }
    return mii->val_out;
}



int islinkup(int sock)
{
  int mii_val[32], i, bmsr;
    mdio_read(sock, MII_BMSR);
    for (i = 0; i < ((verbose > 1) ? 32 : 8); i++)
	mii_val[i] = mdio_read(sock, i);

    if (mii_val[MII_BMCR] == 0xffff) {
	fprintf(stderr, "  No MII transceiver present!.\n");
	return -1;
    }

    bmsr = mii_val[MII_BMSR];
    return (bmsr & MII_BMSR_LINK_VALID) ? 1 : 0;
  
}



/*
 * For this works on, the driver should implement the MII interface.
 * Drivers knows who don't implement : pcnet32 :^P
 * Tested on a sky2 / e100
 */


static int do_one_xcvr(char *ifname)
{
  int skfd; 
  if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) {
    perror("socket");
    fprintf(stderr, "  The int does not exist!.\n");
    return 1;
  }
  
  int_up(skfd, ifname);     
  
  sleep (5);

  /* Get the vitals from the interface. */
  strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
  if (ioctl(skfd, SIOCGMIIPHY, &ifr) < 0) {
    if ((errno != ENODEV))
      fprintf(stderr, "SIOCGMIIPHY on '%s' failed: %s\n",
              ifname, strerror(errno));
    return 1;
  }
  

  if (islinkup(skfd))
    {
      printf ("La interfaz está levantada!\n");
    }else printf ("La interafaz esta caída\n");
 
   int_down(skfd, ifname);
  return 0;
}


/*For testing pourposes.*/
int main (int argc, char * argv [])
{
  if (argc != 2)
  {
    printf ("Introduce el nombre de la interfaz!!\n");
    return 1;
  }
    int ret =do_one_xcvr(argv[1]);
    if (ret != 0)
      printf ("Error on definition...!!!!\n");
}
hits counter