A problem about NETLINK

From: xiaoyu Du
Date: Sun Apr 29 2007 - 09:18:38 EST


Does the NETLINK interface have changed a lot from 2.6.17 - 2.6.20.
if not. Why my code which runs fine on 2.6.17 cannot run on my FC 6 with 2.6.20
version kernel(Both official or my compiled).
This is the code (just get the gateway IP address ):

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<sys/types.h>
#include<linux/netlink.h>
#include<linux/rtnetlink.h>

struct req {
struct nlmsghdr nlmsg;
struct rtmsg rtm;
};

static struct rtattr* get_gw_attr(struct nlmsghdr *nlmsghdr);
int print_route(struct rtattr *rtp);

int get_gateway_ip(struct sockaddr *gwp);

int main(void)
{
int n;
struct sockaddr gw;
if (get_gateway_ip(&gw)); {
perror("inet_ntop failed !");
exit (1);
}
}

int get_gateway_ip(struct sockaddr *gwp){
int fd;
int n;
char *c;
char buff[BUFSIZ];
char str[22];
struct req req;
struct rtattr *rtp;
struct nlmsghdr nlmsg, *nlp;
struct rtmsg rtm;
struct sockaddr so;
struct sockaddr_nl nl;
struct in_addr addr;

fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd < 0) {
perror("open error");
exit (1);
}
nl.nl_family = AF_NETLINK;
nl.nl_pad = 0;
nl.nl_pid = getpid();
nl.nl_groups = 0;

n = bind(fd, (struct sockaddr*)&nl, sizeof(nl));
if (n < 0) {
perror(" bind error");
exit (1);
}

memset(&nlmsg, 0, sizeof(struct nlmsghdr));
req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.nlmsg.nlmsg_type = RTM_GETROUTE;

/** In kernel header comments NLM_F_ROOT
"specify tree root", but On somebooks
said this means return the entire table
not just one entry **/
req.nlmsg.nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST;

/** this is not required! **/
// req.nlmsg.nlmsg_pid = nl.pid;

memset(&rtm, 0, sizeof(struct rtmsg));
req.rtm.rtm_family = AF_NETLINK;

/** we need change here **/
req.rtm.rtm_dst_len = 4;
req.rtm.rtm_src_len = 4;

req.rtm.rtm_table = RT_TABLE_MAIN;

/** Route installed during boot **/
req.rtm.rtm_protocol = RTPROT_BOOT;
/** located on directly LAN **/
req.rtm.rtm_scope = RT_SCOPE_LINK;

/** Gateway or direct route **/
req.rtm.rtm_type = RTN_UNICAST;

n = send(fd, &req, sizeof(req), 0);
if (n < 0)
{
perror("send error!");
exit (-1);
}
else
printf("%d bytes send!\n",n);

n = recv(fd, buff, BUFSIZ, 0);
if (n < 0)
perror("received failed!");

printf("%d bytes received!\n", n);
for (nlp = (struct nlmsghdr*)buff; \
(nlp->nlmsg_type != NLMSG_DONE)&& NLMSG_OK(nlp, n);
nlp = NLMSG_NEXT(nlp, n)) {
if ((rtp = get_gw_attr(nlp)) != NULL) {
memcpy((void* )(gwp->sa_data), RTA_DATA(rtp),\
sizeof(struct in_addr));
print_route(rtp);
return 0;
}
}
return -1;
}
static struct rtattr* get_gw_attr(struct nlmsghdr *nlmsghdr)
{
struct rtattr *rta;
int len;
int gw;
char str[16];

len = nlmsghdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));

/** NLMSG_DATA(nlmsghdr) return the rtmsg
pointer following, and RTM_RTA return
the rtattr pointer following the rtmsg. **/
rta = RTM_RTA(NLMSG_DATA(nlmsghdr));
while (RTA_OK(rta, len)) {
if (rta->rta_type >= RTA_MAX)
break;
/** We check if the address is INADDR_ANY.I
don't know whethher this is needed **/
if(rta->rta_type == RTA_GATEWAY &&\
*(int *)RTA_DATA(rta) != INADDR_ANY)
return rta;
rta = RTA_NEXT(rta, len);
}
return NULL;
};
int print_route(struct rtattr *rtp)
{
char str[16];
char *c;
char buff[16];
c = inet_ntop (AF_INET, RTA_DATA(rtp), buff, INET_ADDRSTRLEN);
if (!c) {
perror("inet_ntop failed !");
exit (1);
}
printf("The gateway IP address is %s\n",c);
}
-
To unsubscribe from this list: 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