#if 0
i have written this sample program to get the interface address
but it seems to give me only the lo interface how do i get information 
about the eth0 interface
can somebody gimme some pointers here

-SIGTERM
amit
#endif

/* original name = testIPv6.c */
/* author:  amit.limaye@patni.com */

/* gcc [-DSENDTO] -O2 rtnl_test.c -o rtnl_test */

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
//#include<bits/sockaddr.h>

///#define SENDTO	1	// undef => use bind/send, defined => use sendto;

#define PROGNAME		"rtnl_test"
#define VERSION			"0.1"
#define BUFF_SIZE		(64 * 1024)
#define TEMP_SIZE		50

#define RTA_SESSION		(RTA_CACHEINFO + 1)
#define	RTA_HOPLIMIT		(RTA_SESSION + 1)
#define RTA_RTINFO		(RTA_HOPLIMIT + 1)

struct rta_rtinfo {
	__s32	rta_obsolete;
	__u32	rta_sernum;
};

int seqnum = 0;

void die (char *msg)
{
	if (errno)
		fprintf (stderr, "[%s]: err = %d (0x%x)\n",
				msg, errno, errno);
	exit (2);
}

void usage (void)
{
	fprintf (stderr, "%s [options]  {ver. %s}\n", PROGNAME, VERSION);
	fprintf (stderr, "  options:   -h     help\n");
	fprintf (stderr, "             -r     route info (IPv4)\n");
	fprintf (stderr, "             -s     route info (IPv6)\n");
	exit (1);
}

int route_info (char which)
{
	int route4info = which == 'r';
	int sockfd = 0;
	struct sockaddr_nl nladdr;
	char buff[BUFF_SIZE];
	struct iovec iov = {
		.iov_base = buff,
		.iov_len = BUFF_SIZE
	};
	struct msghdr buff_msghdr = {
		.msg_name = (void *)&nladdr,
		.msg_namelen = sizeof(nladdr),
		.msg_iov = &iov,
		.msg_iovlen = 1,
		.msg_control = NULL,
		.msg_controllen = 0,
		.msg_flags = 0
	};
	char temp_addr[TEMP_SIZE] = "";
	int len = 0;
	int err;
	struct {
		struct nlmsghdr nlh;
		struct rtmsg rtm;
		
	} req;
	struct nlmsghdr *reply;
	struct rtmsg *rtm;
	struct rtattr *rta;
	struct rta_cacheinfo *rtcache;
	struct rta_rtinfo    *rtinfo;

	memset(buff, 0, BUFF_SIZE);
	// get a NETLINK_ROUTE[6] socket:
	sockfd = socket(PF_NETLINK, SOCK_DGRAM, route4info ? NETLINK_ROUTE : NETLINK_ROUTE6);
	if (sockfd < 0)
		die ("socket");

	nladdr.nl_family = AF_NETLINK;
	nladdr.nl_pad = 0;
	nladdr.nl_pid = 0;		// target in kernel
	nladdr.nl_groups = 0;
#ifndef SENDTO
	err = bind(sockfd, (struct sockaddr *)&nladdr, sizeof(struct sockaddr_nl));
	if (err < 0)
		die ("bind");
#endif

	memset (&req, 0, sizeof (req));
	req.nlh.nlmsg_len = sizeof (req);
	req.nlh.nlmsg_type = RTM_GETROUTE;
	req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
	req.nlh.nlmsg_pid = 0;
	req.nlh.nlmsg_seq = ++seqnum;
	req.rtm.rtm_family = route4info ? AF_INET : AF_INET6;
	///req.rtm.rtm_flags |= RTM_F_CLONED;	// TBD: ???
#ifndef SENDTO
	err = send(sockfd, &req, req.nlh.nlmsg_len, 0);
#else
	err = sendto(sockfd, &req, req.nlh.nlmsg_len, 0, (struct sockaddr *)&nladdr,
			sizeof(struct  sockaddr_nl));
#endif
	if (err < 0)
		die ("send(to)");

	err = recvmsg(sockfd, &buff_msghdr, 0);
	if (err < 0)
		die ("recvmsg");

	reply = (struct nlmsghdr *)buff;
	rtm  = NLMSG_DATA(reply);
	rta = IFLA_RTA(rtm);
	len = reply->nlmsg_len;
	printf("Length is %d\n", len);

	printf ("static rtmsg header fields:\n");
	printf ("  family: %d | dst_len: %d | src_len: %d | TOS: %d\n",
			rtm->rtm_family, rtm->rtm_dst_len,
			rtm->rtm_src_len, rtm->rtm_tos);
	printf ("  rttblID: %d | protocol: %d | scope: %d | type: %d | flags: 0x%x\n",
			rtm->rtm_table, rtm->rtm_protocol,
			rtm->rtm_scope, rtm->rtm_type, rtm->rtm_flags);
	printf ("rtm attributes:\n");

	while(RTA_OK(rta, len)) {
	switch(rta->rta_type) {
	case RTA_DST:
		///inet_ntop(AF_INET, RTA_DATA(rta), temp_addr, TEMP_SIZE);
		printf("route_dst_addr: %s\n", temp_addr);
		break;		
	case RTA_SRC:
		///inet_ntop(AF_INET, RTA_DATA(rta), temp_addr, TEMP_SIZE);
		printf("route_src_addr: %s\n", temp_addr);
		break;
	case RTA_IIF:
		printf("input iface index: %d\n", RTA_DATA(rta));
		break;	
	case RTA_OIF:
		printf("output iface index: %d\n", RTA_DATA(rta));
		break;	
	case RTA_GATEWAY:
		///inet_ntop(AF_INET, RTA_DATA(rta), temp_addr, TEMP_SIZE);
		printf("route_gw_addr: %s\n", temp_addr);
		break;	
	case RTA_PRIORITY:
		printf("route priority: %d\n", RTA_DATA(rta));
		break;	
	case RTA_PREFSRC:
		printf("preferred src: %d\n", RTA_DATA(rta));
		break;	
	case RTA_METRICS:
		printf("route metric: %d\n", RTA_DATA(rta));
		break;	
	case RTA_MULTIPATH:
		printf("route mpath: %d\n", RTA_DATA(rta));
		break;	
	case RTA_PROTOINFO:
		printf("route proto info: %d\n", RTA_DATA(rta));
		break;	
	case RTA_FLOW:
		printf("route flow: %d\n", RTA_DATA(rta));
		break;	
	case RTA_CACHEINFO:
		rtcache = (struct rta_cacheinfo *) &buff;
		printf("cache info: clntref: %d, lastuse: %d, expires: %d, error: %d, used: %d\n",
				rtcache->rta_clntref, rtcache->rta_lastuse,
				rtcache->rta_expires, rtcache->rta_error, rtcache->rta_used);
		printf("            id: %d, ts: %d, tsage: %d\n",
				rtcache->rta_id, rtcache->rta_ts, rtcache->rta_tsage);
		break;
	case RTA_RTINFO:
		rtinfo = (struct rta_rtinfo *) &buff;
		printf ("route info2: obsolete: %d, sernum: %d\n",
				rtinfo->rta_obsolete, rtinfo->rta_sernum);
		break;
	default:
		printf("Unknown rta_type (%d)\n", rta->rta_type);
		break;
	}
	printf("\nLooping to next RTA_\n");
	rta = RTA_NEXT(rta, len);
	}
	return 0;
} // end route_info;

int main (int argc, char *argv [])
{
	int ix;
	char ch;

	if (argc == 1)
		usage ();

	for (ix = 1; ix < argc; ix++) {
		if (*argv [ix] != '-')
			usage ();
		ch = *(argv [ix] + 1);
		switch (ch) {
		case 'r':
		case 's':
			route_info (ch);
			break;
		default:
		case 'h':
			usage ();
			break;
		}
	}

} // end main;

// end rtnl_test.c;
