#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <linux/route.h>
#include <linux/if_ether.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <getopt.h>
#include <stdio.h>

/*
 * Global information
 */
static char *pszProgram;

/*********************************************************************
 *
 * Function: usage
 *
 * Description:
 *        Print the program usage.
 *
 * Entry:
 *        none.
 *
 * Returns:
 *        none.
 */

void usage (void)
  {
    fprintf (stderr, "usage: %s [-t] network_device\n", pszProgram);
  }

/*********************************************************************
 *
 * Function: decode_type
 *
 * Description:
 *      Translate the type name to the corresponding socket ioctl
 *      value.
 *
 * Entry:
 *      name    - pointer to the parameter name value
 * 
 * Returns:
 *      The socket ioctl code or zero for an error.
 */

int decode_type (char *name)
  {
    char    buffer[20];
    char    *ptr;

    typedef struct _kwds
      {
	int    value;
	char   *name;
      } kwds;

    kwds *kwd_ptr;
/*
 * List of keywords and their meanings
 */
    kwds kwd_list[] =
      { { SIOCGIFFLAGS,		"flags"},
	{ SIOCGIFADDR,		"addr"},
	{ SIOCGIFDSTADDR,	"dstaddr"},
	{ SIOCGIFDSTADDR,	"dstaddr"},
	{ SIOCGIFBRDADDR,	"brdaddr"},
	{ SIOCGIFNETMASK,	"netmask"},
	{ SIOCGIFMETRIC,	"metric"},
	{ SIOCGIFMTU,		"mtu"},
	{ SIOCGIFHWADDR,	"hwaddr"},
	{ SIOCGIFSLAVE,		"slave"},
	{ 0,			(char*) 0}
      };
/*
 * Fetch the name and convert it to lower case
 */
    strncpy (buffer, name, sizeof (buffer));
    buffer [sizeof (buffer)-1] = '\0';
    ptr = buffer;
    while (*ptr)
      {
	*ptr = tolower (*ptr);
	++ptr;
      }
/*
 * Locate the string in the list.
 */
    kwd_ptr = kwd_list;
    while (kwd_ptr->name != (char *) 0)
      {
	if (strcmp (kwd_ptr->name, buffer) == 0)
	  {
	    break;
	  }
	++kwd_ptr;
      }
/*
 * Return the value for the keyword
 */
    return (kwd_ptr->value);
  }

/*********************************************************************
 *
 * Function: main
 *
 * Description:
 *      Main entry to the program
 *
 * Entry:
 *      argc    - number of arguments
 *      argv    - vector to the argument list
 *
 * Returns:
 *      The completion status. 0 for success. 1 for error.
 */

int main (int argc, char **argv)
  {
    static char szOptions[] = "t:";
    struct ifreq   ifr;
    int    funct;
    int    nOpt;
    int    sock;
    char   *device;
/*
 * Initialize to scan the arguments
 */
    pszProgram = argv[0];
    funct      = 0;
/*
 *  Decode the options in the command
 */
    nOpt = getopt (argc, argv, szOptions);
    while (nOpt != EOF)
      {
	switch (nOpt)
	  {
/*
 * Type of information from the device
 */
	  case 't':
	    funct = decode_type (optarg);
	    if (funct == 0)
	      {
		usage();
		return 1;
	      }
	    break;
/*
 * The option is invalid
 */
	  case '?':
	  default:
	    usage();
	    return 1;
	  }
	nOpt = getopt (argc, argv, szOptions);
      }
/*
 * Process the device name
 */
    if (optind >= argc || funct == 0)
      {
	usage();
	return 1;
      }

    device = argv[optind];
/*
 * Allocate a socket to do the request
 */
    sock = socket (AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
      {
	perror ("socket(AF_INET) error");
	return 1;
      }
/*
 * Do the request to read the device status
 */
    memset (&ifr, 0, sizeof (ifr));
    ifr.ifr_addr.sa_family = AF_INET;
    strncpy (ifr.ifr_name, device, sizeof (ifr.ifr_name));

    if (ioctl (sock, funct, (caddr_t) &ifr) < 0)
      {
	perror ("ioctl error");
	close (sock);
	return 1;
      }
/*
 * Decode and output the proper setting
 */
    switch (funct)
      {
      case SIOCGIFFLAGS:		/* get flags			*/
	printf ("%d\n", ifr.ifr_flags);
	break;

      case SIOCGIFADDR:			/* get PA address		*/
	printf ("%s\n", inet_ntoa (((struct sockaddr_in *)
				    &ifr.ifr_addr)->sin_addr));
	break;

      case SIOCGIFDSTADDR:		/* get remote PA address	*/
	printf ("%s\n", inet_ntoa (((struct sockaddr_in *)
				    &ifr.ifr_dstaddr)->sin_addr));
	break;

      case SIOCGIFBRDADDR:		/* get broadcast PA address	*/
	printf ("%s\n", inet_ntoa (((struct sockaddr_in *)
				    &ifr.ifr_broadaddr)->sin_addr));
	break;

      case SIOCGIFNETMASK:		/* get network PA mask		*/
	printf ("%s\n", inet_ntoa (((struct sockaddr_in *)
				    &ifr.ifr_netmask)->sin_addr));
	break;

      case SIOCGIFMETRIC:		/* get metric			*/
	printf ("%d\n", ifr.ifr_metric);
	break;

      case SIOCGIFMTU:			/* get MTU size			*/
	printf ("%d\n", ifr.ifr_mtu);
	break;

      case SIOCGIFHWADDR:		/* Get hardware address		*/
	printf ("%s\n", inet_ntoa (((struct sockaddr_in *)
				    &ifr.ifr_hwaddr)->sin_addr));
	break;

      case SIOCGIFSLAVE:		/* Driver slaving support	*/
	printf ("%s\n", ifr.ifr_slave);
	break;
      }
/*
 * Close the socket and return success.
 */
    close (sock);
    return (0);
  }
