RE: netlink documentation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> -----Original Message-----
> From: linux-net-owner@xxxxxxxxxxxxxxx
> [mailto:linux-net-owner@xxxxxxxxxxxxxxx]On Behalf Of
> apalaios@xxxxxxxxxxxx
> Sent: Wednesday, August 17, 2005 12:02 PM
> To: linux-net@xxxxxxxxxxxxxxx
> Subject: netlink documentation
> 
> Hi.. do u have in mind any netlink documentation?? I want to 
> write some c code
> for changing network queues and class ffor htb tbf and cbq.. 
> Anythink in mind?
> 

The documentation that have been able to find on how to use the netlink
sockets interface has been incomplete and in many cases incorrect. So in
pursuit of trying to understand how the netlink sockets interface works,
I wrote the following six, short, simple, standalone c programs that
allow one to dump and modify the link, address and routing tables via
the netlink interface. These programs are based on some code I found on
a kernel newbies web site and some usage of strace to figure out what
the standard tools do.

They aren't a substitute for good documentation, but writing, debugging
and using them helped me to understand the interface better than I did a
while ago, so maybe they will help others, too. Another source that I
found useful was the source code to the iproute2 package ip program.

Each program resides in a single .c file, the names of which are:

	link_get.c - displays the table of network interfaces
	link_set.c - configs a given network interface UP (uses ioctl
instead of netlink)
	addr_get.c - displays the table of network addresses
	addr_set.c - configures a network address
	route_get.c - displays the tables of routes (surprise to me,
there are more than I thought)
	route_set.c - configures a default gateway

I've pasted the source to each program to the end of this email.

Jeff Haran
Brocade Communications Systems

++++++++++++++ link_get.c +++++++++++++++++++++++++=

/* 8-04-2005, jharan,

	stolen from:
http://mail.nl.linux.org/kernelnewbies/2003-12/msg00138.html
	then modified to retrieve link information
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <asm/types.h>
#include <netinet/ether.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
/* #include <linux/netdevice.h> */
#include <sys/types.h>
#include <unistd.h>
#define _GNU_SOURCE
#include <getopt.h>
#include <string.h>

#define NL_BUFSIZE 8192

typedef struct {
	__u16 nlmsg_type;
	char *name;
} nlmsg_type_name;

#define NLMSG_NAME_INIT(name) { name, #name }

nlmsg_type_name nlmsg_type_table[] = {
	NLMSG_NAME_INIT(NLMSG_NOOP),
	NLMSG_NAME_INIT(NLMSG_ERROR),
	NLMSG_NAME_INIT(NLMSG_DONE),
	NLMSG_NAME_INIT(NLMSG_OVERRUN),
	NLMSG_NAME_INIT(RTM_NEWLINK),
	NLMSG_NAME_INIT(RTM_DELLINK),
	NLMSG_NAME_INIT(RTM_GETLINK),
	NLMSG_NAME_INIT(RTM_NEWADDR),
	NLMSG_NAME_INIT(RTM_DELADDR),
	NLMSG_NAME_INIT(RTM_GETADDR),
	NLMSG_NAME_INIT(RTM_NEWROUTE),
	NLMSG_NAME_INIT(RTM_DELROUTE),
	NLMSG_NAME_INIT(RTM_GETROUTE),
	NLMSG_NAME_INIT(RTM_NEWNEIGH),
	NLMSG_NAME_INIT(RTM_DELNEIGH),
	NLMSG_NAME_INIT(RTM_GETNEIGH),
	NLMSG_NAME_INIT(RTM_NEWRULE),
	NLMSG_NAME_INIT(RTM_DELRULE),
	NLMSG_NAME_INIT(RTM_GETRULE),
	NLMSG_NAME_INIT(RTM_NEWQDISC),
	NLMSG_NAME_INIT(RTM_DELQDISC),
	NLMSG_NAME_INIT(RTM_GETQDISC),
	NLMSG_NAME_INIT(RTM_NEWTCLASS),
	NLMSG_NAME_INIT(RTM_DELTCLASS),
	NLMSG_NAME_INIT(RTM_GETTCLASS),
	NLMSG_NAME_INIT(RTM_NEWTFILTER),
	NLMSG_NAME_INIT(RTM_DELTFILTER),
	NLMSG_NAME_INIT(RTM_GETTFILTER),
	NLMSG_NAME_INIT(RTM_MAX),
	{ 0, 0 }	/* end of table marker */
};

char *lookup_nlmsg_type(__u16 nlmsg_type)
{
	int i;

	for (i = 0; nlmsg_type_table[i].name; ++i) {
		if (nlmsg_type_table[i].nlmsg_type == nlmsg_type)
			return nlmsg_type_table[i].name;
	}
	return ("unknown nlmsg_type");
}

typedef struct {
	int nlmsg_flag;
	char *name;
} nlmsg_flags_name;

#define NLMSG_FLAGS_INIT(name) { name, #name }

nlmsg_flags_name nlmsg_flags_table[] = {
	NLMSG_FLAGS_INIT(NLM_F_REQUEST),
	NLMSG_FLAGS_INIT(NLM_F_MULTI),
	NLMSG_FLAGS_INIT(NLM_F_ACK),
	NLMSG_FLAGS_INIT(NLM_F_ECHO),
	NLMSG_FLAGS_INIT(NLM_F_ROOT),
	NLMSG_FLAGS_INIT(NLM_F_MATCH),
	NLMSG_FLAGS_INIT(NLM_F_ATOMIC),
	NLMSG_FLAGS_INIT(NLM_F_REPLACE),
	NLMSG_FLAGS_INIT(NLM_F_EXCL),
	NLMSG_FLAGS_INIT(NLM_F_CREATE),
	NLMSG_FLAGS_INIT(NLM_F_APPEND),
	{ 0, 0 }	/* end of table marker */
};

__u16 print_nlmsg_flags(__u16 nlmsg_flags)
{
	int i;

	/* while some flag bits are still set */
	while (nlmsg_flags) {
		/* search table for a flag where we know what it is */
		for (i = 0; nlmsg_flags_table[i].name; ++i) {
			/* known flag? */
			if (nlmsg_flags_table[i].nlmsg_flag &
nlmsg_flags) {
				/* print its name */
				fprintf(stdout, "%s ",
nlmsg_flags_table[i].name); 
				/* reset the flag */
				nlmsg_flags &=
~nlmsg_flags_table[i].nlmsg_flag;
				break;
			}
		}
		/* if we couldn't find any matching flags, bail */
		if (!nlmsg_flags_table[i].name)
			break;
	}
	/* if any unknown flags left, display them numerically */
	if (nlmsg_flags)
		fprintf(stdout, "mystery flags 0x%x", nlmsg_flags);
	return nlmsg_flags;
}

typedef struct {
	unsigned int iff_flag;
	char *name;
} iff_flags_name;

#define IFF_FLAGS_INIT(name) { name, #name }

iff_flags_name iff_flags_table[] = {
	IFF_FLAGS_INIT(IFF_UP),
	IFF_FLAGS_INIT(IFF_BROADCAST),
	IFF_FLAGS_INIT(IFF_DEBUG),
	IFF_FLAGS_INIT(IFF_LOOPBACK),
	IFF_FLAGS_INIT(IFF_POINTOPOINT),
	IFF_FLAGS_INIT(IFF_NOTRAILERS),
	IFF_FLAGS_INIT(IFF_RUNNING),
	IFF_FLAGS_INIT(IFF_NOARP),
	IFF_FLAGS_INIT(IFF_PROMISC),
	IFF_FLAGS_INIT(IFF_ALLMULTI),
	IFF_FLAGS_INIT(IFF_MASTER),
	IFF_FLAGS_INIT(IFF_SLAVE),
	IFF_FLAGS_INIT(IFF_MULTICAST),
	IFF_FLAGS_INIT(IFF_PORTSEL),
	IFF_FLAGS_INIT(IFF_AUTOMEDIA),
	{ 0, 0 }	/* end of table marker */
};

unsigned int print_iff_flags(unsigned int iff_flags)
{
	int i;

	/* while some flag bits are still set */
	while (iff_flags) {
		/* search table for a flag where we know what it is */
		for (i = 0; iff_flags_table[i].name; ++i) {
			/* known flag? */
			if (iff_flags_table[i].iff_flag & iff_flags) {
				/* print its name */
				fprintf(stdout, "%s ",
iff_flags_table[i].name); 
				/* reset the flag */
				iff_flags &=
~iff_flags_table[i].iff_flag;
				break;
			}
		}
		/* if we couldn't find any matching flags, bail */
		if (!iff_flags_table[i].name)
			break;
	}
	/* if any unknown flags left, display them numerically */
	if (iff_flags)
		fprintf(stdout, "mystery flags 0x%x", iff_flags);
	return iff_flags;
}

int readSock(int sockFd, char *bufPtr, int seqNum, int pId)
{
	struct nlmsghdr *nlHdr;
	int readLen = 0, flag = 0, msgLen = 0;

	do{
		/* Recieve response from kernel */
		if ((readLen = recv(sockFd, bufPtr, NL_BUFSIZE - msgLen,
0)) < 0){
			perror("SOCK READ: ");
			return -1;
		}
		nlHdr = (struct nlmsghdr *)bufPtr;

		fprintf(stdout, "nlmsg_type = %d %s\n",
			nlHdr->nlmsg_type,
lookup_nlmsg_type(nlHdr->nlmsg_type));
		fprintf(stdout, "nlmsg_flags = 0x%x ",
nlHdr->nlmsg_flags);
		print_nlmsg_flags(nlHdr->nlmsg_flags);
		fprintf(stdout, "\n");

		/* Check if header is valid */
		if (NLMSG_OK(nlHdr, readLen) == 0) {
			fprintf(stdout, "NLMSG_OK == 0\n");
			return -1;
		}

		/* check for error packet */
		if (nlHdr->nlmsg_type == NLMSG_ERROR) {
			struct nlmsgerr *errHdr;

			errHdr = (struct nlmsgerr *) NLMSG_DATA(nlHdr);
			fprintf(stdout,
				"Received NLMSG_ERROR, error = %d %s\n",
					errHdr->error,
strerror(-(errHdr->error)));
			return -1;
		}

		/* Check if its the last message */
		if (nlHdr->nlmsg_type == NLMSG_DONE)	{
			flag = 1;
			break;
		} else {
			/* Move the buffer pointer appropriately */
			bufPtr += readLen;
			msgLen += readLen;
		}
#if 1
	/* jharan, though it seems to work, not clear to me that the
following
		is "correct". I think we should only be looking for the
NLMSG_DONE
		to terminate, like is done above  */
		if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0){
			flag = 1;
			break;
		}
#endif
	} while ((nlHdr->nlmsg_seq != seqNum) ||
		(nlHdr->nlmsg_pid != pId) || (flag == 0));
	return msgLen;
}

void fmt_mac(char *buf, unsigned char *mac)
{
	sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x",
		mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

void parseIfInfo(struct nlmsghdr *nlHdr)
{
	struct ifinfomsg *ifInfo;
	struct rtattr *rtAttr;
	int rtLen;
/*	struct net_device_stats *pstats; */
	char tempBuf[100];

	ifInfo = (struct ifinfomsg *)NLMSG_DATA(nlHdr);

	fprintf(stdout,
"=============================================\n");

	fprintf(stdout, "ifinfomsg:ifi_family %d\n",
ifInfo->ifi_family);
	fprintf(stdout, "ifinfomsg:ifi_type %d", ifInfo->ifi_type);
	if (ifInfo->ifi_type == ARPHRD_ETHER)
		fprintf(stdout, " ARPHDR_ETHER\n");
	else if (ifInfo->ifi_type == ARPHRD_LOOPBACK)
		fprintf(stdout, " ARPHDR_LOOPBACK\n");
	else
		fprintf(stdout, " mystery ifi_type\n");

	fprintf(stdout, "ifinfomsg:ifi_index %d\n", ifInfo->ifi_index);
	fprintf(stdout, "ifinfomsg:ifi_flags 0x%x ", ifInfo->ifi_flags);
	print_iff_flags(ifInfo->ifi_flags);
	fprintf(stdout, "\n");
	fprintf(stdout, "ifinfomsg:ifi_change 0x%x\n",
ifInfo->ifi_change);

	rtAttr = (struct rtattr *)IFLA_RTA(ifInfo);
	rtLen = IFLA_PAYLOAD(nlHdr);
	for(;RTA_OK(rtAttr,rtLen);rtAttr = RTA_NEXT(rtAttr,rtLen)){
		fprintf(stdout, "rta_type %d %d:", rtAttr->rta_type,
rtAttr->rta_len);
		switch(rtAttr->rta_type)	{
		case IFLA_IFNAME:
			fprintf(stdout, "IFLA_IFNAME: %s\n",(char *)
RTA_DATA(rtAttr));
			break;
		case IFLA_ADDRESS:
			/* gonna assume this is a 6 byte MAC address */
			/* but how do you figure out the length of this?
*/
			/* it is NOT rtAttr->rta_length */
			fmt_mac(tempBuf, RTA_DATA(rtAttr));
			fprintf(stdout, "IFLA_ADDRESS: %s\n", tempBuf);
			break;
		case IFLA_BROADCAST:
			/* gonna assume this is a 6 byte MAC address */
			/* but how do you figure out the length of this?
*/
			/* it is NOT rtAttr->rta_length */
			fmt_mac(tempBuf, RTA_DATA(rtAttr));
			fprintf(stdout, "IFLA_BROADCAST: %s\n",
tempBuf);
			break;
		case IFLA_MTU:
			fprintf(stdout, "IFLA_MTU: %d\n",
				*((unsigned int *) RTA_DATA(rtAttr)));
			break;
		case IFLA_QDISC:
			fprintf(stdout, "IFLA_QDISC: %s\n",(char *)
RTA_DATA(rtAttr));
			break;
		case IFLA_STATS:
			/* cant figure out how to include the definition
of
				net_device_stats via linux/netdevice.h
w/o a bunch
				of other compilation problems. the first
ulong
				of this pointer should contain the num
of RX
				packets */
			fprintf(stdout, "IFLA_STATS: %ld\n",
				*((unsigned long *) RTA_DATA(rtAttr)));
			break;
		default:
			fprintf(stdout, "\n");
			break;
		}
	}
	return;
}

unsigned short command_ifi_type;
int command_ifi_index;
int command_ack;
int command_any_args;

struct option long_options[] = {
	{ "index", required_argument, 0, 'i'},
	{ "type", required_argument, 0, 't'},
	{ "ack", no_argument, 0, 'a'},
	{ 0, 0, 0, 0}
};

char short_options[] = "i:t:a";

int parse_command_line(int argc, char *argv[])
{

	int rc;
	int option_index;
	unsigned int x;

	while (1)
	{
		rc = getopt_long(argc, argv, short_options,
			long_options, &option_index);
		switch (rc) {
			case 'i' :
				sscanf(optarg, "%d",
&command_ifi_index);
				printf("command_ifi_index = %d\n",
command_ifi_index);
				command_any_args++;
				break;
			case 't' :
				sscanf(optarg, "%u", &x);
				command_ifi_type = (unsigned short) x;
				printf("command_ifi_type = %u\n",
command_ifi_type);
				command_any_args++;
				break;
			case 'a' :
				command_ack = 1;
				printf("acknowledgement enabled\n");
				break;
			case -1 :
				break;
			default :
				printf("unrecognized option %c (%d)\n",
rc, rc);
				break;
		}

		if (rc == -1)
			break;
	}

	return 0;
}

int main(int argc, char *argv[])
{
	struct nlmsghdr *nlMsg;
	struct ifinfomsg *linkMsg;
	char msgBuf[NL_BUFSIZE];
	int sock, len, msgSeq = 0;

	if (parse_command_line(argc, argv))
		return -1;

	/* Create Socket */
	if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
{
		perror("Socket Creation: ");
		return -1;
	}

	memset(msgBuf, 0, NL_BUFSIZE);

	nlMsg = (struct nlmsghdr *)msgBuf;
	linkMsg = (struct ifinfomsg *)NLMSG_DATA(nlMsg);

	/* apply any command line parameters to linkMsg */
	if (command_ifi_type)
		linkMsg->ifi_type = command_ifi_type;
	if (command_ifi_index)
		linkMsg->ifi_index = command_ifi_index;

	/* For getting interface addresses */
	nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
	nlMsg->nlmsg_type = RTM_GETLINK;

	nlMsg->nlmsg_flags = NLM_F_REQUEST;
#if 0
	/* it appears that only NLM_F_REQUEST | NLM_F_ROOT is supported
		by the RTM_GETLINK service. when I attempt to setup the
		fields of ifinfomsg sent to the kernel as above, I
either
		get all links back when NLM_F_ROOT is specified or an
		error message when its not, jharan, 8-08-2005 */
	if (!command_any_args)
#endif
		nlMsg->nlmsg_flags |= NLM_F_ROOT;

	/* it appears the NLM_F_ACK has no effect on gets. guess this
		makes sense given that the get response is sufficent
		acknowledgement, jharan, 8-08-2005 */
	if (command_ack)
		nlMsg->nlmsg_flags |= NLM_F_ACK;

	nlMsg->nlmsg_seq = msgSeq++;
	nlMsg->nlmsg_pid = getpid();

	if(write(sock, nlMsg, nlMsg->nlmsg_len) < 0){
		printf("Write To Socket Failed...\n");
		return -1;
	}

	if((len = readSock(sock, msgBuf, msgSeq, getpid())) < 0){
		printf("Read From Socket Failed...\n");
		return -1;
	}
	printf("readSock() returned %d\n", len);

	for(;NLMSG_OK(nlMsg,len);nlMsg = NLMSG_NEXT(nlMsg,len)){
		/* For getting interface addresses */
		parseIfInfo(nlMsg);

	}
	close(sock);
 	return 0;
}

++++++++++ link_set.c ++++++++++++++++++++

/* 8-16-2005, jharan,

	link up program, uses ioctls instead of netlink socket
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/sockios.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>

int main(int argc, char *argv[])
{
	int sd;
	char *dev;
	int rc;
	struct ifreq ifr;

	if (argc < 2) {
		printf("usage: %s <device name>\n", argv[0]);
		return -1;
	}

	dev = argv[1];

	sd = socket(PF_INET, SOCK_DGRAM, 0);
	if (sd < 0) {
		perror("socket failed");
		return -1;
	}

	strcpy(ifr.ifr_name, dev);
	rc = ioctl(sd, SIOCGIFFLAGS, &ifr);
	if (rc) {
		perror("ioctl SIOCGIFFLAGS failed");
		close(sd);
		return -1;
	}
	printf("device %s (0x%x) is currently %s\n",
		dev, ifr.ifr_flags, ifr.ifr_flags & IFF_UP ? "up" :
"down");
	if (!(ifr.ifr_flags & IFF_UP)) {
		ifr.ifr_flags |= IFF_UP;
		printf("setting up\n");
		rc = ioctl(sd, SIOCSIFFLAGS, &ifr);
		if (rc) {
			perror("ioctl SIOCSIFFLAGS failed");
			close(sd);
			return -1;
		}
	}

	close(sd);
	return 0;
}

++++++++++++++++++ addr_get.c ++++++++++++++++++++++++++

/* 8-04-2005, jharan,

	stolen from:
http://mail.nl.linux.org/kernelnewbies/2003-12/msg00138.html

	then modified

Hi all,
 i am including a piece of code i have written to get the network
interfaces
and their IP addresses using rtnetlink. Please do let me know if there
is a better way of doing this.

*/

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <asm/types.h>
#include <netinet/ether.h>
#include <netinet/in.h>
#include <net/if.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/types.h>
#include <unistd.h>

#define NL_BUFSIZE 8192

typedef struct {
	__u16 nlmsg_type;
	char *name;
} nlmsg_type_name;

#define NLMSG_NAME_INIT(name) { name, #name }

nlmsg_type_name nlmsg_type_table[] = {
	NLMSG_NAME_INIT(NLMSG_NOOP),
	NLMSG_NAME_INIT(NLMSG_ERROR),
	NLMSG_NAME_INIT(NLMSG_DONE),
	NLMSG_NAME_INIT(NLMSG_OVERRUN),
	NLMSG_NAME_INIT(RTM_NEWLINK),
	NLMSG_NAME_INIT(RTM_DELLINK),
	NLMSG_NAME_INIT(RTM_GETLINK),
	NLMSG_NAME_INIT(RTM_NEWADDR),
	NLMSG_NAME_INIT(RTM_DELADDR),
	NLMSG_NAME_INIT(RTM_GETADDR),
	NLMSG_NAME_INIT(RTM_NEWROUTE),
	NLMSG_NAME_INIT(RTM_DELROUTE),
	NLMSG_NAME_INIT(RTM_GETROUTE),
	NLMSG_NAME_INIT(RTM_NEWNEIGH),
	NLMSG_NAME_INIT(RTM_DELNEIGH),
	NLMSG_NAME_INIT(RTM_GETNEIGH),
	NLMSG_NAME_INIT(RTM_NEWRULE),
	NLMSG_NAME_INIT(RTM_DELRULE),
	NLMSG_NAME_INIT(RTM_GETRULE),
	NLMSG_NAME_INIT(RTM_NEWQDISC),
	NLMSG_NAME_INIT(RTM_DELQDISC),
	NLMSG_NAME_INIT(RTM_GETQDISC),
	NLMSG_NAME_INIT(RTM_NEWTCLASS),
	NLMSG_NAME_INIT(RTM_DELTCLASS),
	NLMSG_NAME_INIT(RTM_GETTCLASS),
	NLMSG_NAME_INIT(RTM_NEWTFILTER),
	NLMSG_NAME_INIT(RTM_DELTFILTER),
	NLMSG_NAME_INIT(RTM_GETTFILTER),
	NLMSG_NAME_INIT(RTM_MAX),
	{ 0, 0 }	/* end of table marker */
};

char *lookup_nlmsg_type(__u16 nlmsg_type)
{
	int i;

	for (i = 0; nlmsg_type_table[i].name; ++i) {
		if (nlmsg_type_table[i].nlmsg_type == nlmsg_type)
			return nlmsg_type_table[i].name;
	}
	return ("unknown nlmsg_type");
}

typedef struct {
	int nlmsg_flag;
	char *name;
} nlmsg_flags_name;

#define NLMSG_FLAGS_INIT(name) { name, #name }

nlmsg_flags_name nlmsg_flags_table[] = {
	NLMSG_FLAGS_INIT(NLM_F_REQUEST),
	NLMSG_FLAGS_INIT(NLM_F_MULTI),
	NLMSG_FLAGS_INIT(NLM_F_ACK),
	NLMSG_FLAGS_INIT(NLM_F_ECHO),
	NLMSG_FLAGS_INIT(NLM_F_ROOT),
	NLMSG_FLAGS_INIT(NLM_F_MATCH),
	NLMSG_FLAGS_INIT(NLM_F_ATOMIC),
	NLMSG_FLAGS_INIT(NLM_F_REPLACE),
	NLMSG_FLAGS_INIT(NLM_F_EXCL),
	NLMSG_FLAGS_INIT(NLM_F_CREATE),
	NLMSG_FLAGS_INIT(NLM_F_APPEND),
	{ 0, 0 }	/* end of table marker */
};

__u16 print_nlmsg_flags(__u16 nlmsg_flags)
{
	int i;

	/* while some flag bits are still set */
	while (nlmsg_flags) {
		/* search table for a flag where we know what it is */
		for (i = 0; nlmsg_flags_table[i].name; ++i) {
			/* known flag? */
			if (nlmsg_flags_table[i].nlmsg_flag &
nlmsg_flags) {
				/* print its name */
				fprintf(stdout, "%s ",
nlmsg_flags_table[i].name); 
				/* reset the flag */
				nlmsg_flags &=
~nlmsg_flags_table[i].nlmsg_flag;
				break;
			}
		}
		/* if we couldn't find any matching flags, bail */
		if (!nlmsg_flags_table[i].name)
			break;
	}
	/* if any unknown flags left, display them numerically */
	if (nlmsg_flags)
		fprintf(stdout, "mystery flags 0x%x", nlmsg_flags);
	return nlmsg_flags;
}


int readSock(int sockFd, char *bufPtr, int seqNum, int pId)
{
	struct nlmsghdr *nlHdr;
	int readLen = 0, flag = 0, msgLen = 0;

	do{
		/* Recieve response from kernel */
		if ((readLen = recv(sockFd, bufPtr, NL_BUFSIZE - msgLen,
0)) < 0){
			perror("SOCK READ: ");
			return -1;
		}
		nlHdr = (struct nlmsghdr *)bufPtr;

		/* Check if header is valid */
		if ((NLMSG_OK(nlHdr, readLen) == 0) ||
(nlHdr->nlmsg_type == NLMSG_ERROR)){
			perror("Error in recieved packet");
			return -1;
		}

		fprintf(stdout, "nlmsg_type = %d %s\n",
			nlHdr->nlmsg_type,
lookup_nlmsg_type(nlHdr->nlmsg_type));
		fprintf(stdout, "nlmsg_flags = 0x%x ",
nlHdr->nlmsg_flags);
		print_nlmsg_flags(nlHdr->nlmsg_flags);
		fprintf(stdout, "\n");

		/* Check if its the last message */
		if (nlHdr->nlmsg_type == NLMSG_DONE)	{
			flag = 1;
			break;
		} else {
			/* Move the buffer pointer appropriately */
			bufPtr += readLen;
			msgLen += readLen;
		}
#if 0
	/* jharan, though it seems to work, not clear to me that the
following
		is "correct". I think we should only be looking for the
NLMSG_DONE
		to terminate, like is done above  */
		if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0){
			flag = 1;
			break;
		}
#endif
	} while ((nlHdr->nlmsg_seq != seqNum) ||
		(nlHdr->nlmsg_pid != pId) || (flag == 0));
	return msgLen;
}

void parseIfAddr(struct nlmsghdr *nlHdr)
{
	struct ifaddrmsg *ifAddrs;
	struct rtattr *rtAttr;
	int rtLen;
	unsigned char ifa_flags;
	char tempBuf[100];

	ifAddrs = (struct ifaddrmsg *)NLMSG_DATA(nlHdr);

	fprintf(stdout,
"=============================================\n");
	fprintf(stdout, "ifaddrmsg:ifa_family %d\n",
ifAddrs->ifa_family);
	if (ifAddrs->ifa_family == AF_INET)
		fprintf(stdout, "\tAF_INET\n");
	else
		fprintf(stdout, "\tmystery family\n");
	fprintf(stdout, "ifaddrmsg:ifa_prefixlen %d\n",
ifAddrs->ifa_prefixlen);
	fprintf(stdout, "ifaddrmsg:ifa_flags 0x%x\n\t",
ifAddrs->ifa_flags);
	/* decode and reset flags */
	ifa_flags = ifAddrs->ifa_flags;
	if (ifa_flags & IFA_F_SECONDARY) {
		fprintf(stdout, "IFA_F_SECONDARY, ");
		ifa_flags &= ~IFA_F_SECONDARY;
	}
	if (ifa_flags & IFA_F_DEPRECATED) {
		fprintf(stdout, "IFA_F_DEPRECATED, ");
		ifa_flags &= ~IFA_F_DEPRECATED;
	}
	if (ifa_flags & IFA_F_TENTATIVE) {
		fprintf(stdout, "IFA_F_TENTATIVE, ");
		ifa_flags &= ~IFA_F_TENTATIVE;
	}
	if (ifa_flags & IFA_F_PERMANENT) {
		fprintf(stdout, "IFA_F_PERMANENT, ");
		ifa_flags &= ~IFA_F_PERMANENT;
	}
	/* display remaining flags we couldn't decode */
	fprintf(stdout, "mystery flags 0x%x\n", ifa_flags);

	fprintf(stdout, "ifaddrmsg:ifa_scope %d\n\t",
ifAddrs->ifa_scope);
	if (ifAddrs->ifa_scope == RT_SCOPE_UNIVERSE)
		fprintf(stdout,"RT_SCOPE_UNIVERSE\n");
	else if (ifAddrs->ifa_scope == RT_SCOPE_SITE)
		fprintf(stdout,"RT_SCOPE_SITE\n");
	else if (ifAddrs->ifa_scope == RT_SCOPE_LINK)
		fprintf(stdout,"RT_SCOPE_LINK\n");
	else if (ifAddrs->ifa_scope == RT_SCOPE_HOST)
		fprintf(stdout,"RT_SCOPE_HOST\n");
	else if (ifAddrs->ifa_scope == RT_SCOPE_NOWHERE)
		fprintf(stdout,"RT_SCOPE_NOWHERE\n");
	else
		fprintf(stdout,"mystery scope\n");

	fprintf(stdout, "ifaddrmsg:ifa_index %d\n", ifAddrs->ifa_index);

	rtAttr = (struct rtattr *)IFA_RTA(ifAddrs);
	rtLen = IFA_PAYLOAD(nlHdr);
	for(;RTA_OK(rtAttr,rtLen);rtAttr = RTA_NEXT(rtAttr,rtLen)){
		fprintf(stdout, "rta_type %d:", rtAttr->rta_type);
		switch(rtAttr->rta_type)	{
		case IFA_ADDRESS:
			inet_ntop(AF_INET, RTA_DATA(rtAttr), tempBuf,
sizeof(tempBuf));
			fprintf(stdout, "IFA_ADDRESS: %s\n",tempBuf);
			break;
		case IFA_LABEL:
			fprintf(stdout, "IFA_LABEL: %s\n",(char *)
RTA_DATA(rtAttr));
			break;
		case IFA_BROADCAST:
			inet_ntop(AF_INET, RTA_DATA(rtAttr), tempBuf,
sizeof(tempBuf));
			fprintf(stdout, "IFA_BROADCAST: %s\n",tempBuf);
			break;
		case IFA_LOCAL:
			inet_ntop(AF_INET, RTA_DATA(rtAttr), tempBuf,
sizeof(tempBuf));
			fprintf(stdout, "IFA_LOCAL: %s\n",tempBuf);
			break;
		default:
			fprintf(stdout, "\n");
			break;
		}
	}
	return;
}

int main()
{
	struct nlmsghdr *nlMsg;
	struct ifaddrmsg *addrMsg;
	char msgBuf[NL_BUFSIZE];
	int sock, len, msgSeq = 0;

	/* Create Socket */
	if((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
		perror("Socket Creation: ");

	memset(msgBuf, 0, NL_BUFSIZE);

	nlMsg = (struct nlmsghdr *)msgBuf;
	addrMsg = (struct ifaddrmsg *)NLMSG_DATA(nlMsg);

	/* For getting interface addresses */
	nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
	nlMsg->nlmsg_type = RTM_GETADDR;
	nlMsg->nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
	nlMsg->nlmsg_seq = msgSeq++;
	nlMsg->nlmsg_pid = getpid();

	if(write(sock, nlMsg, nlMsg->nlmsg_len) < 0){
		printf("Write To Socket Failed...\n");
		return -1;
	}

	if((len = readSock(sock, msgBuf, msgSeq, getpid())) < 0){
		printf("Read From Socket Failed...\n");
		return -1;
	}

	for(;NLMSG_OK(nlMsg,len);nlMsg = NLMSG_NEXT(nlMsg,len)){
		/* For getting interface addresses */
		parseIfAddr(nlMsg);

	}
	close(sock);
    	return 0;
}

++++++++++++++++++ addr_set.c +++++++++++++++++++++++++++

/* 8-15-2005, jharan,

	unit test program to generate NETLINK addr add requests
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <asm/types.h>
#include <netinet/ether.h>
#include <netinet/in.h>
#include <net/if.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/types.h>
#include <unistd.h>

#define NL_BUFSIZE 8192

typedef struct {
	__u16 nlmsg_type;
	char *name;
} nlmsg_type_name;

#define NLMSG_NAME_INIT(name) { name, #name }

nlmsg_type_name nlmsg_type_table[] = {
	NLMSG_NAME_INIT(NLMSG_NOOP),
	NLMSG_NAME_INIT(NLMSG_ERROR),
	NLMSG_NAME_INIT(NLMSG_DONE),
	NLMSG_NAME_INIT(NLMSG_OVERRUN),
	NLMSG_NAME_INIT(RTM_NEWLINK),
	NLMSG_NAME_INIT(RTM_DELLINK),
	NLMSG_NAME_INIT(RTM_GETLINK),
	NLMSG_NAME_INIT(RTM_NEWADDR),
	NLMSG_NAME_INIT(RTM_DELADDR),
	NLMSG_NAME_INIT(RTM_GETADDR),
	NLMSG_NAME_INIT(RTM_NEWROUTE),
	NLMSG_NAME_INIT(RTM_DELROUTE),
	NLMSG_NAME_INIT(RTM_GETROUTE),
	NLMSG_NAME_INIT(RTM_NEWNEIGH),
	NLMSG_NAME_INIT(RTM_DELNEIGH),
	NLMSG_NAME_INIT(RTM_GETNEIGH),
	NLMSG_NAME_INIT(RTM_NEWRULE),
	NLMSG_NAME_INIT(RTM_DELRULE),
	NLMSG_NAME_INIT(RTM_GETRULE),
	NLMSG_NAME_INIT(RTM_NEWQDISC),
	NLMSG_NAME_INIT(RTM_DELQDISC),
	NLMSG_NAME_INIT(RTM_GETQDISC),
	NLMSG_NAME_INIT(RTM_NEWTCLASS),
	NLMSG_NAME_INIT(RTM_DELTCLASS),
	NLMSG_NAME_INIT(RTM_GETTCLASS),
	NLMSG_NAME_INIT(RTM_NEWTFILTER),
	NLMSG_NAME_INIT(RTM_DELTFILTER),
	NLMSG_NAME_INIT(RTM_GETTFILTER),
	NLMSG_NAME_INIT(RTM_MAX),
	{ 0, 0 }	/* end of table marker */
};

char *lookup_nlmsg_type(__u16 nlmsg_type)
{
	int i;

	for (i = 0; nlmsg_type_table[i].name; ++i) {
		if (nlmsg_type_table[i].nlmsg_type == nlmsg_type)
			return nlmsg_type_table[i].name;
	}
	return ("unknown nlmsg_type");
}

typedef struct {
	int nlmsg_flag;
	char *name;
} nlmsg_flags_name;

#define NLMSG_FLAGS_INIT(name) { name, #name }

nlmsg_flags_name nlmsg_flags_table[] = {
	NLMSG_FLAGS_INIT(NLM_F_REQUEST),
	NLMSG_FLAGS_INIT(NLM_F_MULTI),
	NLMSG_FLAGS_INIT(NLM_F_ACK),
	NLMSG_FLAGS_INIT(NLM_F_ECHO),
	NLMSG_FLAGS_INIT(NLM_F_ROOT),
	NLMSG_FLAGS_INIT(NLM_F_MATCH),
	NLMSG_FLAGS_INIT(NLM_F_ATOMIC),
	NLMSG_FLAGS_INIT(NLM_F_REPLACE),
	NLMSG_FLAGS_INIT(NLM_F_EXCL),
	NLMSG_FLAGS_INIT(NLM_F_CREATE),
	NLMSG_FLAGS_INIT(NLM_F_APPEND),
	{ 0, 0 }	/* end of table marker */
};

__u16 print_nlmsg_flags(__u16 nlmsg_flags)
{
	int i;

	/* while some flag bits are still set */
	while (nlmsg_flags) {
		/* search table for a flag where we know what it is */
		for (i = 0; nlmsg_flags_table[i].name; ++i) {
			/* known flag? */
			if (nlmsg_flags_table[i].nlmsg_flag &
nlmsg_flags) {
				/* print its name */
				fprintf(stdout, "%s ",
nlmsg_flags_table[i].name); 
				/* reset the flag */
				nlmsg_flags &=
~nlmsg_flags_table[i].nlmsg_flag;
				break;
			}
		}
		/* if we couldn't find any matching flags, bail */
		if (!nlmsg_flags_table[i].name)
			break;
	}
	/* if any unknown flags left, display them numerically */
	if (nlmsg_flags)
		fprintf(stdout, "mystery flags 0x%x", nlmsg_flags);
	return nlmsg_flags;
}

int readSock(int sockFd, char *bufPtr, int seqNum, int pId)
{
	struct nlmsghdr *nlHdr;
	int readLen = 0, flag = 0, msgLen = 0;

	do{
		/* Recieve response from kernel */
		if ((readLen = recv(sockFd, bufPtr, NL_BUFSIZE - msgLen,
0)) < 0){
			perror("SOCK READ: ");
			return -1;
		}
		nlHdr = (struct nlmsghdr *)bufPtr;

		/* Check if header is valid */
		if (NLMSG_OK(nlHdr, readLen) == 0) {
			perror("Error in recieved packet");
			return -1;
		}

		fprintf(stdout, "nlmsg_type = %d %s\n",
			nlHdr->nlmsg_type,
lookup_nlmsg_type(nlHdr->nlmsg_type));
		fprintf(stdout, "nlmsg_flags = 0x%x ",
nlHdr->nlmsg_flags);
		print_nlmsg_flags(nlHdr->nlmsg_flags);
		fprintf(stdout, "\n");

		/* Move the buffer pointer appropriately */
		bufPtr += readLen;
		msgLen += readLen;

		/* we expect an NLMSG_ERROR in response to these */
		if (nlHdr->nlmsg_type == NLMSG_ERROR) {
			break;
		}

#if 0
	/* jharan, though it seems to work, not clear to me that the
following
		is "correct". I think we should only be looking for the
NLMSG_DONE
		to terminate, like is done above  */
		if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0){
			flag = 1;
			break;
		}
#endif
	} while ((nlHdr->nlmsg_seq != seqNum) ||
		(nlHdr->nlmsg_pid != pId) || (flag == 0));
	return msgLen;
}

void parseResponse(struct nlmsghdr *nlHdr)
{
	struct nlmsgerr *nlErr;

	nlErr = (struct nlmsgerr *)NLMSG_DATA(nlHdr);
	fprintf(stdout, "nlmsgerr:error %d\n", nlErr->error);
}

/* stole this from oss/iproute2/src/lib/libnetlink.c */
/* it builds up the rtattr fields in the outgoing message buffer */

int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int
alen)
{
	int len = RTA_LENGTH(alen);
	struct rtattr *rta;

	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
		return -1;
	rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
	rta->rta_type = type;
	rta->rta_len = len;
	memcpy(RTA_DATA(rta), data, alen);
	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
	return 0;
}

/* we are trying to generate this:

	sent:

	struct nlmsghdr
	{
		__u32		nlmsg_len;
\x00\x00\x00\x30\ = 48
		__u16		nlmsg_type;		\x00\x14\ =
RTM_NEWADDR
		__u16		nlmsg_flags;	\x00\x05\ =
NLM_F_REQUEST | NLM_F_ACK
		__u32		nlmsg_seq;
\x42\xfa\x15\xbe\
		__u32		nlmsg_pid;
\x00\x00\x00\x00\
	};
	struct ifaddrmsg
	{
		unsigned char	ifa_family;		\x02\ = AF_INET
		unsigned char	ifa_prefixlen;	\x18\ = 24
		unsigned char	ifa_flags;		\x00\ = 0
		unsigned char	ifa_scope;		\x00\ =
RT_SCOPE_UNIVERSE
		int		ifa_index;
\x00\x00\x00\x02\ = 2 (eth0)
	};
	struct rtattr
	{
		unsigned short	rta_len;		\x00\x08\ = 8
		unsigned short	rta_type;		\x00\x02\ =
IFA_LOCAL
	};
	\xc0\xa8\x4e\x9f\ = 192.168.78.159 (specified IP address)
	struct rtattr
	{
		unsigned short	rta_len;		\x00\x08\ = 8
		unsigned short	rta_type;		\x00\x01\ =
IFA_ADDRESS
	};
	\xc0\xa8\x4e\x9f\ = 192.168.78.159 (specified IP address)
	struct rtattr
	{
		unsigned short	rta_len;		\x00\x08\ = 8
		unsigned short	rta_type;		\x00\x04\ =
IFA_BROADCAST
	};
	\xc0\xa8\x4e\xff = 192.168.78.255 (specified broadcast address)

*/

int buildAddrSetCommand(
char *msgBuf,
unsigned int msgSeq,
unsigned char prefixLen,
unsigned char scope,
int ifa_index,
struct in_addr ifa_local,
struct in_addr ifa_address,
struct in_addr ifa_broadcast)
{
	struct nlmsghdr *nlMsg;
	struct ifaddrmsg *addrMsg;

	nlMsg = (struct nlmsghdr *)msgBuf;
	addrMsg = (struct ifaddrmsg *)NLMSG_DATA(nlMsg);

	nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
	nlMsg->nlmsg_type = RTM_NEWADDR;
	nlMsg->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
	nlMsg->nlmsg_seq = msgSeq;
	nlMsg->nlmsg_pid = getpid();

	addrMsg->ifa_family = AF_INET;
	addrMsg->ifa_prefixlen = prefixLen;
	addrMsg->ifa_flags = 0;
	addrMsg->ifa_scope = scope;
	addrMsg->ifa_index = ifa_index;

	if (addattr_l(nlMsg, NL_BUFSIZE, IFA_LOCAL,
		&ifa_local.s_addr, sizeof(ifa_local.s_addr)) < 0) {
		fprintf(stdout, "addattr_l(IFA_LOCAL) failed\n");
		return -1;
	}

	if (addattr_l(nlMsg, NL_BUFSIZE, IFA_ADDRESS,
		&ifa_address.s_addr, sizeof(ifa_address.s_addr)) < 0) {
		fprintf(stdout, "addattr_l(IFA_ADDRESS) failed\n");
		return -1;
	}

	if (addattr_l(nlMsg, NL_BUFSIZE, IFA_BROADCAST,
		&ifa_broadcast.s_addr, sizeof(ifa_broadcast.s_addr)) <
0) {
		fprintf(stdout, "addattr_l(IFA_BROADCAST) failed\n");
		return -1;
	}

	return nlMsg->nlmsg_len;
}

int main(int argc, char *argv[])
{
	struct nlmsghdr *nlMsg;
	char msgBuf[NL_BUFSIZE];
	int sock, len, msgSeq = 0;
	int ifa_index;
	int x;
	unsigned char prefixLen;
	unsigned char scope;
	struct in_addr ifa_local;
	struct in_addr ifa_address;
	struct in_addr ifa_broadcast;

	if (argc < 6) {
		fprintf(stdout,
			"usage: %s ifa_index prefix_len scope IP_address
broadcast_address\n", argv[0]);
		return -1;
	}

	sscanf(argv[1], "%d", &ifa_index);
	sscanf(argv[2], "%d", &x);
	prefixLen = (unsigned char) x;
	
	sscanf(argv[3], "%d", &x);
	scope = (unsigned char) x;
	
	if (!inet_aton(argv[4], &ifa_local)) {
		fprintf(stdout, "inet_aton(%s) ifa_local failed\n",
argv[4]);
		return -1;
	}

	ifa_address = ifa_local;

	if (!inet_aton(argv[5], &ifa_broadcast)) {
		fprintf(stdout, "inet_aton(%s) ifa_broadcast failed\n",
argv[5]);
		return -1;
	}

	printf("ifa_local 0x%x, ifa_address 0x%x, ifa_broadcast 0x%x\n",
		ifa_local.s_addr, ifa_address.s_addr,
ifa_broadcast.s_addr);

	/* Create Socket */
	if((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
		perror("Socket Creation: ");

	memset(msgBuf, 0, NL_BUFSIZE);

	nlMsg = (struct nlmsghdr *)msgBuf;

	if (buildAddrSetCommand(msgBuf, msgSeq++, prefixLen, scope,
			ifa_index, ifa_local, ifa_address,
ifa_broadcast) < 0) {
		fprintf(stdout,"buildAddrSetCommand() failed\n");
		return -1;
	}

	if(write(sock, nlMsg, nlMsg->nlmsg_len) < 0){
		printf("Write To Socket Failed...\n");
		return -1;
	}

	if((len = readSock(sock, msgBuf, msgSeq, getpid())) < 0){
		printf("Read From Socket Failed...\n");
		return -1;
	}

	for(;NLMSG_OK(nlMsg,len);nlMsg = NLMSG_NEXT(nlMsg,len)){
		/* For getting interface addresses */
		parseResponse(nlMsg);

	}
	close(sock);
  	return 0;
}

+++++++++++++++++++++ route_get.c +++++++++++++++++++++++++++++

/* 8-04-2005, jharan,

	stolen from:
http://mail.nl.linux.org/kernelnewbies/2003-12/msg00139.html

Hi all,
 i am including another piece of code which i have written to print the
routes
in the kernel routing table using rtnetlink. Please do let me know if
there
is a better way of doing this.

*/

#include <asm/types.h>
#include <netinet/ether.h>
#include <netinet/in.h>
#include <net/if.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#define _GNU_SOURCE
#include <getopt.h>
#include <string.h>
#include <arpa/inet.h>

#define NL_BUFSIZE 8192

#ifndef IF_NAMESIZE
#define IF_NAMESIZE     16
#endif

struct route_info{
	struct	route_info *next;
	struct in_addr	dstAddr;
	struct in_addr	srcAddr;
	struct in_addr	gateWay;
	char	ifName[IF_NAMESIZE + 50];
};

struct route_info *route_info_head = 0;
struct route_info *route_info_tail = 0;

typedef struct {
	__u16 nlmsg_type;
	char *name;
} nlmsg_type_name;

#define NLMSG_NAME_INIT(name) { name, #name }

nlmsg_type_name nlmsg_type_table[] = {
	NLMSG_NAME_INIT(NLMSG_NOOP),
	NLMSG_NAME_INIT(NLMSG_ERROR),
	NLMSG_NAME_INIT(NLMSG_DONE),
	NLMSG_NAME_INIT(NLMSG_OVERRUN),
	NLMSG_NAME_INIT(RTM_NEWLINK),
	NLMSG_NAME_INIT(RTM_DELLINK),
	NLMSG_NAME_INIT(RTM_GETLINK),
	NLMSG_NAME_INIT(RTM_NEWADDR),
	NLMSG_NAME_INIT(RTM_DELADDR),
	NLMSG_NAME_INIT(RTM_GETADDR),
	NLMSG_NAME_INIT(RTM_NEWROUTE),
	NLMSG_NAME_INIT(RTM_DELROUTE),
	NLMSG_NAME_INIT(RTM_GETROUTE),
	NLMSG_NAME_INIT(RTM_NEWNEIGH),
	NLMSG_NAME_INIT(RTM_DELNEIGH),
	NLMSG_NAME_INIT(RTM_GETNEIGH),
	NLMSG_NAME_INIT(RTM_NEWRULE),
	NLMSG_NAME_INIT(RTM_DELRULE),
	NLMSG_NAME_INIT(RTM_GETRULE),
	NLMSG_NAME_INIT(RTM_NEWQDISC),
	NLMSG_NAME_INIT(RTM_DELQDISC),
	NLMSG_NAME_INIT(RTM_GETQDISC),
	NLMSG_NAME_INIT(RTM_NEWTCLASS),
	NLMSG_NAME_INIT(RTM_DELTCLASS),
	NLMSG_NAME_INIT(RTM_GETTCLASS),
	NLMSG_NAME_INIT(RTM_NEWTFILTER),
	NLMSG_NAME_INIT(RTM_DELTFILTER),
	NLMSG_NAME_INIT(RTM_GETTFILTER),
	NLMSG_NAME_INIT(RTM_MAX),
	{ 0, 0 }	/* end of table marker */
};

char *lookup_nlmsg_type(__u16 nlmsg_type)
{
	int i;

	for (i = 0; nlmsg_type_table[i].name; ++i) {
		if (nlmsg_type_table[i].nlmsg_type == nlmsg_type)
			return nlmsg_type_table[i].name;
	}
	return ("unknown nlmsg_type");
}

typedef struct {
	int nlmsg_flag;
	char *name;
} nlmsg_flags_name;

#define NLMSG_FLAGS_INIT(name) { name, #name }

nlmsg_flags_name nlmsg_flags_table[] = {
	NLMSG_FLAGS_INIT(NLM_F_REQUEST),
	NLMSG_FLAGS_INIT(NLM_F_MULTI),
	NLMSG_FLAGS_INIT(NLM_F_ACK),
	NLMSG_FLAGS_INIT(NLM_F_ECHO),
	NLMSG_FLAGS_INIT(NLM_F_ROOT),
	NLMSG_FLAGS_INIT(NLM_F_MATCH),
	NLMSG_FLAGS_INIT(NLM_F_ATOMIC),
	NLMSG_FLAGS_INIT(NLM_F_REPLACE),
	NLMSG_FLAGS_INIT(NLM_F_EXCL),
	NLMSG_FLAGS_INIT(NLM_F_CREATE),
	NLMSG_FLAGS_INIT(NLM_F_APPEND),
	{ 0, 0 }	/* end of table marker */
};

__u16 print_nlmsg_flags(__u16 nlmsg_flags)
{
	int i;

	/* while some flag bits are still set */
	while (nlmsg_flags) {
		/* search table for a flag where we know what it is */
		for (i = 0; nlmsg_flags_table[i].name; ++i) {
			/* known flag? */
			if (nlmsg_flags_table[i].nlmsg_flag &
nlmsg_flags) {
				/* print its name */
				fprintf(stdout, "%s ",
nlmsg_flags_table[i].name); 
				/* reset the flag */
				nlmsg_flags &=
~nlmsg_flags_table[i].nlmsg_flag;
				break;
			}
		}
		/* if we couldn't find any matching flags, bail */
		if (!nlmsg_flags_table[i].name)
			break;
	}
	/* if any unknown flags left, display them numerically */
	if (nlmsg_flags)
		fprintf(stdout, "mystery flags 0x%x", nlmsg_flags);
	return nlmsg_flags;
}

typedef struct {
	int rtmsg_flag;
	char *name;
} rtmsg_flags_name;

#define RTMSG_FLAGS_INIT(name) { name, #name }

rtmsg_flags_name rtmsg_flags_table[] = {
	RTMSG_FLAGS_INIT(RTM_F_NOTIFY),
	RTMSG_FLAGS_INIT(RTM_F_CLONED),
	RTMSG_FLAGS_INIT(RTM_F_EQUALIZE),
	{ 0, 0 }	/* end of table marker */
};

unsigned int print_rtmsg_flags(unsigned int rtmsg_flags)
{
	int i;

	/* while some flag bits are still set */
	while (rtmsg_flags) {
		/* search table for a flag where we know what it is */
		for (i = 0; rtmsg_flags_table[i].name; ++i) {
			/* known flag? */
			if (rtmsg_flags_table[i].rtmsg_flag &
rtmsg_flags) {
				/* print its name */
				fprintf(stdout, "%s ",
rtmsg_flags_table[i].name); 
				/* reset the flag */
				rtmsg_flags &=
~rtmsg_flags_table[i].rtmsg_flag;
				break;
			}
		}
		/* if we couldn't find any matching flags, bail */
		if (!rtmsg_flags_table[i].name)
			break;
	}
	/* if any unknown flags left, display them numerically */
	if (rtmsg_flags)
		fprintf(stdout, "mystery flags 0x%x", rtmsg_flags);
	return rtmsg_flags;
}

int readSock(int sockFd, char *bufPtr, int seqNum, int pId)
{
	struct nlmsghdr *nlHdr;
	int readLen = 0, flag = 0, msgLen = 0;

	do{
		/* Recieve response from kernel */
		if ((readLen = recv(sockFd, bufPtr, NL_BUFSIZE - msgLen,
0)) < 0){
			perror("SOCK READ: ");
			return -1;
		}
		nlHdr = (struct nlmsghdr *)bufPtr;

		fprintf(stdout, "nlmsg_type = %d %s\n",
			nlHdr->nlmsg_type,
lookup_nlmsg_type(nlHdr->nlmsg_type));
		fprintf(stdout, "nlmsg_flags = 0x%x ",
nlHdr->nlmsg_flags);
		print_nlmsg_flags(nlHdr->nlmsg_flags);
		fprintf(stdout, "\n");

		/* Check if header is valid */
		if (NLMSG_OK(nlHdr, readLen) == 0) {
			fprintf(stdout, "NLMSG_OK == 0\n");
			return -1;
		}

		/* check for error packet */
		if (nlHdr->nlmsg_type == NLMSG_ERROR) {
			struct nlmsgerr *errHdr;

			errHdr = (struct nlmsgerr *) NLMSG_DATA(nlHdr);
			fprintf(stdout,
				"Received NLMSG_ERROR, error = %d %s\n",
					errHdr->error,
strerror(-(errHdr->error)));
			return -1;
		}

		/* Check if its the last message */
		if (nlHdr->nlmsg_type == NLMSG_DONE)	{
			flag = 1;
			break;
		} else {
			/* Move the buffer pointer appropriately */
			bufPtr += readLen;
			msgLen += readLen;
		}
#if 1
	/* jharan, though it seems to work, not clear to me that the
following
		is "correct". I think we should only be looking for the
NLMSG_DONE
		to terminate, like is done above  */
		if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0){
			flag = 1;
			break;
		}
#endif
	} while ((nlHdr->nlmsg_seq != seqNum) ||
		(nlHdr->nlmsg_pid != pId) || (flag == 0));
	return msgLen;
}

/* For printing the routes. */
void printRoute(struct route_info *rtInfo)
{
	char tempBuf[512];

	/* Print Destination address */
	if(rtInfo->dstAddr.s_addr != 0)
		strcpy(tempBuf, (char *)inet_ntoa((struct in_addr)
(rtInfo->dstAddr)));
	else
		sprintf(tempBuf,"*.*.*.*\t");
	fprintf(stdout,"%s\t", tempBuf);

	/* Print Gateway address */
	if(rtInfo->gateWay.s_addr != 0)
		strcpy(tempBuf, (char *)inet_ntoa((struct in_addr)
(rtInfo->gateWay)));
	else
		sprintf(tempBuf,"*.*.*.*\t");
	fprintf(stdout,"%s\t", tempBuf);

	/* Print Interface Name*/
	fprintf(stdout,"%s\t\t", rtInfo->ifName);

	/* Print Source address */
	if(rtInfo->srcAddr.s_addr != 0)
		strcpy(tempBuf, (char *)inet_ntoa((struct in_addr)
(rtInfo->srcAddr)));
	else
		sprintf(tempBuf,"*.*.*.*\t");
	fprintf(stdout,"%s\n", tempBuf);
}

/* For parsing the route info returned */
void parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo)
{
	struct rtmsg *rtMsg;
	struct rtattr *rtAttr;
	int rtLen;
	char tempBuf[100];

	rtMsg = (struct rtmsg *)NLMSG_DATA(nlHdr);

	fprintf(stdout,
"=============================================\n");
	fprintf(stdout, "rtmsg: rtm_family %d\t", rtMsg->rtm_family);
	if (rtMsg->rtm_family == AF_INET)
		fprintf(stdout, "AF_INET\n");
	else
		fprintf(stdout, "mystery\n");

	/* from the data, rtm_dst_len appears the be the number of bits
		set in the subnet mask, e.g. the 8 in 10.0.0.1/8.
		in case  of rtm_dst_len == 32, looks like a host route
*/
	fprintf(stdout, "rtmsg: rtm_dst_len %d\n", rtMsg->rtm_dst_len);
	/* rtm_src_len always seems to be 0, not sure what it means */
	fprintf(stdout, "rtmsg: rtm_src_len %d\n", rtMsg->rtm_src_len);
	fprintf(stdout, "rtmsg: rtm_tos %d\n", rtMsg->rtm_tos);
	fprintf(stdout, "rtmsg: rtm_table %d\t", rtMsg->rtm_table);

	if (rtMsg->rtm_table == RT_TABLE_UNSPEC)
		fprintf(stdout, "RT_TABLE_UNSPEC\n");
	else if (rtMsg->rtm_table == RT_TABLE_DEFAULT)
		fprintf(stdout, "RT_TABLE_DEFAULT\n");
	else if (rtMsg->rtm_table == RT_TABLE_MAIN)
		fprintf(stdout, "RT_TABLE_MAIN\n");
	else if (rtMsg->rtm_table == RT_TABLE_LOCAL)
		fprintf(stdout, "RT_TABLE_LOCAL\n");
	else
		fprintf(stdout, "mystery\n");

	fprintf(stdout, "rtmsg: rtm_protocol %d\t",
rtMsg->rtm_protocol);

	if (rtMsg->rtm_protocol == RTPROT_REDIRECT)
		fprintf(stdout, "RTPROT_REDIRECT\n");
	else if (rtMsg->rtm_protocol == RTPROT_KERNEL)
		fprintf(stdout, "RTPROT_KERNEL\n");
	else if (rtMsg->rtm_protocol == RTPROT_BOOT)
		fprintf(stdout, "RTPROT_BOOT\n");
	else if (rtMsg->rtm_protocol == RTPROT_STATIC)
		fprintf(stdout, "RTPROT_STATIC\n");
	else
		/* there's more of these in rtnetlink.h,
			just handling the common ones for now */
		fprintf(stdout, "mystery\n");

	fprintf(stdout, "rtmsg: rtm_scope %d\t", rtMsg->rtm_scope);

	if (rtMsg->rtm_scope == RT_SCOPE_UNIVERSE)
		fprintf(stdout, "RT_SCOPE_UNIVERSE\n");
	else if (rtMsg->rtm_scope == RT_SCOPE_SITE)
		fprintf(stdout, "RT_SCOPE_SITE\n");
	else if (rtMsg->rtm_scope == RT_SCOPE_LINK)
		fprintf(stdout, "RT_SCOPE_LINK\n");
	else if (rtMsg->rtm_scope == RT_SCOPE_HOST)
		fprintf(stdout, "RT_SCOPE_HOST\n");
	else if (rtMsg->rtm_scope == RT_SCOPE_NOWHERE)
		fprintf(stdout, "RT_SCOPE_NOWHERE\n");
	else
		fprintf(stdout, "mystery\n");

	fprintf(stdout, "rtmsg: rtm_type %d\t", rtMsg->rtm_type);

	if (rtMsg->rtm_type == RTN_UNSPEC)
		fprintf(stdout, "RTN_UNSPEC\n");
	else if (rtMsg->rtm_type == RTN_UNICAST)
		fprintf(stdout, "RTN_UNICAST\n");
	else if (rtMsg->rtm_type == RTN_LOCAL)
		fprintf(stdout, "RTN_LOCAL\n");
	else if (rtMsg->rtm_type == RTN_BROADCAST)
		fprintf(stdout, "RTN_BROADCAST\n");
	else if (rtMsg->rtm_type == RTN_ANYCAST)
		fprintf(stdout, "RTN_ANYCAST\n");
	else if (rtMsg->rtm_type == RTN_MULTICAST)
		fprintf(stdout, "RTN_MULTICAST\n");
	else if (rtMsg->rtm_type == RTN_BLACKHOLE)
		fprintf(stdout, "RTN_BLACKHOLE\n");
	else if (rtMsg->rtm_type == RTN_UNREACHABLE)
		fprintf(stdout, "RTN_UNREACHABLE\n");
	else if (rtMsg->rtm_type == RTN_PROHIBIT)
		fprintf(stdout, "RTN_PROHIBIT\n");
	else if (rtMsg->rtm_type == RTN_THROW)
		fprintf(stdout, "RTN_THROW\n");
	else if (rtMsg->rtm_type == RTN_NAT)
		fprintf(stdout, "RTN_NAT\n");
	else if (rtMsg->rtm_type == RTN_XRESOLVE)
		fprintf(stdout, "RTN_XRESOLVE\n");
	else
		fprintf(stdout, "mystery\n");

	fprintf(stdout, "rtmsg: rtm_flags %d ", rtMsg->rtm_flags);
	print_rtmsg_flags(rtMsg->rtm_flags);
	fprintf(stdout, "\n");

#if 0
	/* If the route is not for AF_INET or does not belong to main
routing table
then return. */
	if((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table !=
RT_TABLE_MAIN))
		return;
#endif

	/* get the rtattr field */
	rtAttr = (struct rtattr *)RTM_RTA(rtMsg);
	rtLen = RTM_PAYLOAD(nlHdr);
	for(;RTA_OK(rtAttr,rtLen);rtAttr = RTA_NEXT(rtAttr,rtLen)){
		switch(rtAttr->rta_type)	{
		case RTA_DST:
			inet_ntop(AF_INET, RTA_DATA(rtAttr), tempBuf,
sizeof(tempBuf));
			fprintf(stdout, "RTA_DST: %s\n",tempBuf);
			rtInfo->dstAddr.s_addr= *(u_int
*)RTA_DATA(rtAttr);
			break;
		case RTA_SRC:
			inet_ntop(AF_INET, RTA_DATA(rtAttr), tempBuf,
sizeof(tempBuf));
			fprintf(stdout, "RTA_SRC: %s\n",tempBuf);
			break;
		case RTA_IIF:
			if (!if_indextoname(*(int *)RTA_DATA(rtAttr),
tempBuf))
				sprintf(tempBuf, "errno %d", errno);
			fprintf(stdout, "RTA_IIF: %s\n", tempBuf);
			break;
		case RTA_OIF:
			if (!if_indextoname(*(int *)RTA_DATA(rtAttr),
tempBuf))
				sprintf(tempBuf, "errno %d", errno);
			fprintf(stdout, "RTA_OIF: %s\n", tempBuf);
			strcpy(rtInfo->ifName, tempBuf);
			break;
		case RTA_GATEWAY:
			inet_ntop(AF_INET, RTA_DATA(rtAttr), tempBuf,
sizeof(tempBuf));
			fprintf(stdout, "RTA_GATEWAY: %s\n",tempBuf);
			rtInfo->gateWay.s_addr = *(u_int
*)RTA_DATA(rtAttr);
			break;
		case RTA_PREFSRC:
			inet_ntop(AF_INET, RTA_DATA(rtAttr), tempBuf,
sizeof(tempBuf));
			fprintf(stdout, "RTA_PREFSRC: %s\n",tempBuf);
			rtInfo->srcAddr.s_addr = *(u_int
*)RTA_DATA(rtAttr);
			break;
		default:
			/* there's more RTA_s under rtattr_type_t in
rtnetlink.h,
				just covering some common ones above */
			fprintf(stdout, "RTA mystery: %d len %d\n",
				rtAttr->rta_type, rtAttr->rta_len);
			break;
		}
	}
	return;
}

unsigned char command_rtm_table;
unsigned char command_rtm_protocol;
unsigned char command_rtm_family;
int command_ack;
int command_any_args;

struct option long_options[] = {
	{ "table", required_argument, 0, 't'},
	{ "protocol", required_argument, 0, 'p'},
	{ "family", required_argument, 0, 'f' },
	{ "ack", no_argument, 0, 'a'},
	{ 0, 0, 0, 0}
};

char short_options[] = "t:p:f:a";

int parse_command_line(int argc, char *argv[])
{
	int rc;
	int option_index;
	unsigned int x;

	while (1)
	{
		rc = getopt_long(argc, argv, short_options,
			long_options, &option_index);
		switch (rc) {
			case 't' :
				sscanf(optarg, "%u", &x);
				command_rtm_table = (unsigned char) x;
				printf("command_rtm_table = %u\n",
command_rtm_table);
				command_any_args++;
				break;
			case 'p' :
				sscanf(optarg, "%u", &x);
				command_rtm_protocol = (unsigned char)
x;
				printf("command_rtm_protcol = %u\n",
command_rtm_protocol);
				command_any_args++;
				break;
			case 'f' :
				sscanf(optarg, "%u", &x);
				command_rtm_family = (unsigned char) x;
				printf("command_rtm_family = %u\n",
command_rtm_family);
				command_any_args++;
				break;
			case 'a' :
				command_ack = 1;
				printf("acknowledgement enabled\n");
				break;
			case -1 :
				break;
			default :
				printf("unrecognized option %c (%d)\n",
rc, rc);
				break;
		}

		if (rc == -1)
			break;
	}

	return 0;
}

int main(int argc, char *argv[])
{
	int sock, len, msgSeq = 0;
	struct nlmsghdr *nlMsg;
	struct rtmsg *rtMsg;
	struct route_info *rtInfo;
	char msgBuf[NL_BUFSIZE];

	if (parse_command_line(argc, argv))
		return -1;

	/* Create Socket */
	if((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
		perror("Socket Creation: ");

	/* Initialize the buffer */
	memset(msgBuf, 0, NL_BUFSIZE);

	/* point the header and the msg structure pointers into the
buffer */
	nlMsg = (struct nlmsghdr *)msgBuf;
	rtMsg = (struct rtmsg *)NLMSG_DATA(nlMsg);

	rtMsg->rtm_table = command_rtm_table;
	rtMsg->rtm_protocol = command_rtm_protocol;
	rtMsg->rtm_family = command_rtm_family;

	/* Fill in the nlmsg header*/
	// Length of message.
	nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	// Get the routes from kernel routing table .
	nlMsg->nlmsg_type = RTM_GETROUTE;


	nlMsg->nlmsg_flags = NLM_F_REQUEST;
#if 0
	/* it appears that only NLM_F_REQUEST | NLM_F_ROOT is supported
		by the RTM_GETROUTE service. when I attempt to setup the
		fields of ifinfomsg sent to the kernel as above, I
either
		get all routes back when NLM_F_ROOT is specified or an
		error message when its not, jharan, 8-08-2005 */
	if (!command_any_args)
#endif
		nlMsg->nlmsg_flags |= NLM_F_ROOT;

	/* it appears the NLM_F_ACK has no effect on gets. guess this
		makes sense given that the get response is sufficent
		acknowledgement, jharan, 8-08-2005 */
	if (command_ack)
		nlMsg->nlmsg_flags |= NLM_F_ACK;

	// Sequence of the message packet.
	nlMsg->nlmsg_seq = msgSeq++;
	// PID of process sending the request.
	nlMsg->nlmsg_pid = getpid();

	/* Send the request */
	if(send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0){
		printf("Write To Socket Failed...\n");
		return -1;
	}

	/* Read the response */
	if((len = readSock(sock, msgBuf, msgSeq, getpid())) < 0)
{
		printf("Read From Socket Failed...\n");
		return -1;
	}

	printf("readSock() returned %d\n", len);

	/* Parse and print the response */
	for(;NLMSG_OK(nlMsg,len);nlMsg = NLMSG_NEXT(nlMsg,len)){
		rtInfo = (struct route_info *) malloc(sizeof(struct
route_info));
		if (!rtInfo) {
			fprintf(stdout, "malloc() failed\n");
			return -1;
		}
		memset(rtInfo, 0, sizeof(struct route_info));
		parseRoutes(nlMsg, rtInfo);
		if (!route_info_head) {
			route_info_head = rtInfo;
			route_info_tail = rtInfo;
		} else {
			route_info_tail->next = rtInfo;
			route_info_tail = rtInfo;
		}
	}
	close(sock);
	/* netstat style display of accumulated data */
	fprintf(stdout,
"============================================\n");
	fprintf(stdout, "Destination\tGateway\t\tInterface\tSource\n");
	for (rtInfo = route_info_head; rtInfo; rtInfo = rtInfo->next)
		printRoute(rtInfo);
  	return 0;
}

++++++++++++++++++++ route_set.c +++++++++++++++++++++++++++++

/* 8-16-2005, jharan,

	unit test program to generate NETLINK route add requests
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <asm/types.h>
#include <netinet/ether.h>
#include <netinet/in.h>
#include <net/if.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/types.h>
#include <unistd.h>

#define NL_BUFSIZE 8192

typedef struct {
	__u16 nlmsg_type;
	char *name;
} nlmsg_type_name;

#define NLMSG_NAME_INIT(name) { name, #name }

nlmsg_type_name nlmsg_type_table[] = {
	NLMSG_NAME_INIT(NLMSG_NOOP),
	NLMSG_NAME_INIT(NLMSG_ERROR),
	NLMSG_NAME_INIT(NLMSG_DONE),
	NLMSG_NAME_INIT(NLMSG_OVERRUN),
	NLMSG_NAME_INIT(RTM_NEWLINK),
	NLMSG_NAME_INIT(RTM_DELLINK),
	NLMSG_NAME_INIT(RTM_GETLINK),
	NLMSG_NAME_INIT(RTM_NEWADDR),
	NLMSG_NAME_INIT(RTM_DELADDR),
	NLMSG_NAME_INIT(RTM_GETADDR),
	NLMSG_NAME_INIT(RTM_NEWROUTE),
	NLMSG_NAME_INIT(RTM_DELROUTE),
	NLMSG_NAME_INIT(RTM_GETROUTE),
	NLMSG_NAME_INIT(RTM_NEWNEIGH),
	NLMSG_NAME_INIT(RTM_DELNEIGH),
	NLMSG_NAME_INIT(RTM_GETNEIGH),
	NLMSG_NAME_INIT(RTM_NEWRULE),
	NLMSG_NAME_INIT(RTM_DELRULE),
	NLMSG_NAME_INIT(RTM_GETRULE),
	NLMSG_NAME_INIT(RTM_NEWQDISC),
	NLMSG_NAME_INIT(RTM_DELQDISC),
	NLMSG_NAME_INIT(RTM_GETQDISC),
	NLMSG_NAME_INIT(RTM_NEWTCLASS),
	NLMSG_NAME_INIT(RTM_DELTCLASS),
	NLMSG_NAME_INIT(RTM_GETTCLASS),
	NLMSG_NAME_INIT(RTM_NEWTFILTER),
	NLMSG_NAME_INIT(RTM_DELTFILTER),
	NLMSG_NAME_INIT(RTM_GETTFILTER),
	NLMSG_NAME_INIT(RTM_MAX),
	{ 0, 0 }	/* end of table marker */
};

char *lookup_nlmsg_type(__u16 nlmsg_type)
{
	int i;

	for (i = 0; nlmsg_type_table[i].name; ++i) {
		if (nlmsg_type_table[i].nlmsg_type == nlmsg_type)
			return nlmsg_type_table[i].name;
	}
	return ("unknown nlmsg_type");
}

typedef struct {
	int nlmsg_flag;
	char *name;
} nlmsg_flags_name;

#define NLMSG_FLAGS_INIT(name) { name, #name }

nlmsg_flags_name nlmsg_flags_table[] = {
	NLMSG_FLAGS_INIT(NLM_F_REQUEST),
	NLMSG_FLAGS_INIT(NLM_F_MULTI),
	NLMSG_FLAGS_INIT(NLM_F_ACK),
	NLMSG_FLAGS_INIT(NLM_F_ECHO),
	NLMSG_FLAGS_INIT(NLM_F_ROOT),
	NLMSG_FLAGS_INIT(NLM_F_MATCH),
	NLMSG_FLAGS_INIT(NLM_F_ATOMIC),
	NLMSG_FLAGS_INIT(NLM_F_REPLACE),
	NLMSG_FLAGS_INIT(NLM_F_EXCL),
	NLMSG_FLAGS_INIT(NLM_F_CREATE),
	NLMSG_FLAGS_INIT(NLM_F_APPEND),
	{ 0, 0 }	/* end of table marker */
};

__u16 print_nlmsg_flags(__u16 nlmsg_flags)
{
	int i;

	/* while some flag bits are still set */
	while (nlmsg_flags) {
		/* search table for a flag where we know what it is */
		for (i = 0; nlmsg_flags_table[i].name; ++i) {
			/* known flag? */
			if (nlmsg_flags_table[i].nlmsg_flag &
nlmsg_flags) {
				/* print its name */
				fprintf(stdout, "%s ",
nlmsg_flags_table[i].name); 
				/* reset the flag */
				nlmsg_flags &=
~nlmsg_flags_table[i].nlmsg_flag;
				break;
			}
		}
		/* if we couldn't find any matching flags, bail */
		if (!nlmsg_flags_table[i].name)
			break;
	}
	/* if any unknown flags left, display them numerically */
	if (nlmsg_flags)
		fprintf(stdout, "mystery flags 0x%x", nlmsg_flags);
	return nlmsg_flags;
}

int readSock(int sockFd, char *bufPtr, int seqNum, int pId)
{
	struct nlmsghdr *nlHdr;
	int readLen = 0, flag = 0, msgLen = 0;

	do{
		/* Recieve response from kernel */
		if ((readLen = recv(sockFd, bufPtr, NL_BUFSIZE - msgLen,
0)) < 0){
			perror("SOCK READ: ");
			return -1;
		}
		nlHdr = (struct nlmsghdr *)bufPtr;

		/* Check if header is valid */
		if (NLMSG_OK(nlHdr, readLen) == 0) {
			perror("Error in recieved packet");
			return -1;
		}

		fprintf(stdout, "nlmsg_type = %d %s\n",
			nlHdr->nlmsg_type,
lookup_nlmsg_type(nlHdr->nlmsg_type));
		fprintf(stdout, "nlmsg_flags = 0x%x ",
nlHdr->nlmsg_flags);
		print_nlmsg_flags(nlHdr->nlmsg_flags);
		fprintf(stdout, "\n");

		/* Move the buffer pointer appropriately */
		bufPtr += readLen;
		msgLen += readLen;

		/* we expect an NLMSG_ERROR in response to these */
		if (nlHdr->nlmsg_type == NLMSG_ERROR) {
			break;
		}

#if 0
	/* jharan, though it seems to work, not clear to me that the
following
		is "correct". I think we should only be looking for the
NLMSG_DONE
		to terminate, like is done above  */
		if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0){
			flag = 1;
			break;
		}
#endif
	} while ((nlHdr->nlmsg_seq != seqNum) ||
		(nlHdr->nlmsg_pid != pId) || (flag == 0));
	return msgLen;
}

void parseResponse(struct nlmsghdr *nlHdr)
{
	struct nlmsgerr *nlErr;

	nlErr = (struct nlmsgerr *)NLMSG_DATA(nlHdr);
	fprintf(stdout, "nlmsgerr:error %d\n", nlErr->error);
}

/* stole this from oss/iproute2/src/lib/libnetlink.c */
/* it builds up the rtattr fields in the outgoing message buffer */

int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int
alen)
{
	int len = RTA_LENGTH(alen);
	struct rtattr *rta;

	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
		return -1;
	rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
	rta->rta_type = type;
	rta->rta_len = len;
	memcpy(RTA_DATA(rta), data, alen);
	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
	return 0;
}

/* we are trying to generate this:

	struct nlmsghdr
	{
		__u32		nlmsg_len;		\x00\x00\x00\x2c
= 44
		__u16		nlmsg_type;		\x00\x18 =
RTM_NEWROUTE
		__u16		nlmsg_flags;	\x06\x05 = NLM_F_REQUEST
| NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE
		__u32		nlmsg_seq;
\x43\x02\x20\xa8\
		__u32		nlmsg_pid;
\x00\x00\x00\x00\
	};
	struct rtmsg
	{
		unsigned char		rtm_family;		\x02\ =
AF_INET
		unsigned char		rtm_dst_len;	\x00\ = 0, as in
0 prefix bits for a default route
		unsigned char		rtm_src_len;	\x00\
		unsigned char		rtm_tos;		\x00\

		unsigned char		rtm_table;		\xfe\ =
RT_TABLE_MAIN
		unsigned char		rtm_protocol;	\x03\ =
RTPROT_BOOT
		unsigned char		rtm_scope;		\x00\ =
RT_SCOPE_UNIVERSE
		unsigned char		rtm_type;		\x01\ =
RTN_UNICAST

		unsigned		rtm_flags;
\x00\x00\x00\x00\
	};
	struct rtattr
	{
		unsigned short	rta_len;		\x00\x08\ = 8
		unsigned short	rta_type;		\x00\x05\ =
RTA_GATEWAY
	};
	\xc0\xa8\x4e\x01\		192.168.78.1 (gateway IP
address)
	struct rtattr
	{
		unsigned short	rta_len;		\x00\x08\ = 8
		unsigned short	rta_type;		\x00\x04\ =
RTA_OIF
	};
	\x00\x00\x00\x02\	2 as in interface index 2, eth0

*/

int buildAddrSetCommand(
char *msgBuf,
unsigned int msgSeq,
unsigned char prefixLen,
unsigned char scope,
int ifa_index,
struct in_addr rta_gateway)
{
	struct nlmsghdr *nlMsg;
	struct rtmsg *rtMsg;

	nlMsg = (struct nlmsghdr *)msgBuf;
	rtMsg = (struct rtmsg *)NLMSG_DATA(nlMsg);

	nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	nlMsg->nlmsg_type = RTM_NEWROUTE;
	nlMsg->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL |
NLM_F_CREATE;
	nlMsg->nlmsg_seq = msgSeq;
	nlMsg->nlmsg_pid = getpid();

	rtMsg->rtm_family = AF_INET;
	rtMsg->rtm_dst_len = prefixLen;
	rtMsg->rtm_src_len = 0;
	rtMsg->rtm_tos = 0;
	rtMsg->rtm_table = RT_TABLE_MAIN;
	rtMsg->rtm_protocol = RTPROT_BOOT;
	rtMsg->rtm_scope = scope;
	rtMsg->rtm_type = RTN_UNICAST;
	rtMsg->rtm_flags = 0;

	if (addattr_l(nlMsg, NL_BUFSIZE, RTA_GATEWAY,
		&rta_gateway.s_addr, sizeof(rta_gateway.s_addr)) < 0) {
		fprintf(stdout, "addattr_l(RTA_GATEWAY) failed\n");
		return -1;
	}

	if (addattr_l(nlMsg, NL_BUFSIZE, RTA_OIF,
		&ifa_index, sizeof(ifa_index)) < 0) {
		fprintf(stdout, "addattr_l(RTA_OIF) failed\n");
		return -1;
	}

	return nlMsg->nlmsg_len;
}

int main(int argc, char *argv[])
{
	struct nlmsghdr *nlMsg;
	char msgBuf[NL_BUFSIZE];
	int sock, len, msgSeq = 0;
	int ifa_index;
	int x;
	unsigned char prefixLen;
	unsigned char scope;
	struct in_addr rta_gateway;

	if (argc < 5) {
		fprintf(stdout,
			"usage: %s ifa_index prefix_len scope
gateway_address\n", argv[0]);
		return -1;
	}

	sscanf(argv[1], "%d", &ifa_index);
	sscanf(argv[2], "%d", &x);
	prefixLen = (unsigned char) x;
	
	sscanf(argv[3], "%d", &x);
	scope = (unsigned char) x;
	
	if (!inet_aton(argv[4], &rta_gateway)) {
		fprintf(stdout, "inet_aton(%s) rta_gateway failed\n",
argv[4]);
		return -1;
	}

	printf("rta_gateway 0x%x\n", rta_gateway.s_addr);

	/* Create Socket */
	if((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
		perror("Socket Creation: ");

	memset(msgBuf, 0, NL_BUFSIZE);

	nlMsg = (struct nlmsghdr *)msgBuf;

	if (buildAddrSetCommand(msgBuf, msgSeq++, prefixLen, scope,
			ifa_index, rta_gateway) < 0) {
		fprintf(stdout,"buildAddrSetCommand() failed\n");
		return -1;
	}

	if(write(sock, nlMsg, nlMsg->nlmsg_len) < 0){
		printf("Write To Socket Failed...\n");
		return -1;
	}

	if((len = readSock(sock, msgBuf, msgSeq, getpid())) < 0){
		printf("Read From Socket Failed...\n");
		return -1;
	}

	for(;NLMSG_OK(nlMsg,len);nlMsg = NLMSG_NEXT(nlMsg,len)){
		/* For getting interface addresses */
		parseResponse(nlMsg);

	}
	close(sock);
  	return 0;
}



-
: send the line "unsubscribe linux-net" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux 802.1Q VLAN]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Git]     [Bugtraq]     [Yosemite News and Information]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux PCI]     [Linux Admin]     [Samba]

  Powered by Linux