How to bundle requests?
Tilman Baumann
tilman.baumann at grandeye.com
Tue Oct 25 05:50:52 EDT 2011
Hi,
I need IP address information and link mac addresses in my programme.
I thought I can combine requests with nlmsg_flags = NLM_F_MULTI but it
seems like this does not really work at all.
Or I'm doing it wrong.
I'm not constantly listening on the socket. I just send a request and do
one recv(). I could imagine that this is bad practice. If you tell me
how it is better done I would appreciate this very much.
Sorry about the line breaks. I did not take care of max line length.
I will attach the file as well, to make it more readable.
Below code works if I just send one RTM_GETADDR or RTM_GETLINK packet.
But the combined request like below does only return GETADDR data.
Am I doing the NLM_F_MULTI request right? Should it work and how should
I use it do make it work.
Any help appreciated. Thanks
Tilman Baumann
#include <errno.h>
#include <error.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <inttypes.h>
#include <net/ethernet.h>
#include <netinet/ether.h>
#define IF_NAME "br0"
#define LL_NET_ADDRESS "169.254.0.0"
#define LL_NET_MASK "255.255.0.0"
#define HWADDR_LEN 17
int parse_netlink_response(char * buf, int buf_size, uint32_t *
linklocal_address_p, uint32_t * ipaddr_p, struct ether_addr * hwaddr);
int get_ipdata(uint32_t * linklocal_address_p, uint32_t * ipaddr_p,
struct ether_addr * hwaddr)
{
int status, ifaddr_nlmsg_len, ifinfo_nlmsg_len, packet_length;
char buf[16384]; /* arbitrary size */
int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
struct nlmsghdr *ifaddr_hdr = NULL;
struct nlmsghdr *ifinfo_hdr = NULL;
struct ifaddrmsg *ifaddr_msg = NULL;
struct ifinfomsg *ifinfo_msg = NULL;
ifaddr_nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
ifinfo_nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
packet_length = ifaddr_nlmsg_len + ifinfo_nlmsg_len;
ifaddr_hdr = (struct nlmsghdr *) malloc(packet_length);
memset(ifaddr_hdr, 0, packet_length);
// Set NL message header
ifaddr_hdr->nlmsg_len = ifaddr_nlmsg_len;
ifaddr_hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MULTI;
ifaddr_hdr->nlmsg_type = RTM_GETADDR;
// set payload sruct
ifaddr_msg = (struct ifaddrmsg *) NLMSG_DATA(ifaddr_hdr);
ifaddr_msg->ifa_family = AF_INET;
// Set NL message header
ifinfo_hdr = (struct nlmsghdr *) NLMSG_NEXT(ifaddr_hdr,
packet_length);
ifinfo_hdr->nlmsg_len = ifaddr_nlmsg_len;
ifinfo_hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT | NLMSG_DONE;
ifinfo_hdr->nlmsg_type = RTM_GETLINK;
// set payload sruct
ifinfo_msg = (struct ifinfomsg *) NLMSG_DATA(ifinfo_hdr);
ifinfo_msg->ifi_family = AF_UNSPEC;
status = send(fd, ifaddr_hdr, packet_length, 0);
if (status < 0) {
perror("send");
return 1;
}
status = recv(fd, buf, sizeof(buf), 0);
if (status < 0) {
perror("recv");
return 1;
}
if(status == 0){
printf("EOF\n");
return 1;
}
return parse_netlink_response(buf, status, linklocal_address_p,
ipaddr_p, hwaddr);
}
int parse_netlink_response(char * buf, int buf_size, uint32_t *
linklocal_address_p, uint32_t * ipaddr_p, struct ether_addr * hwaddr){
struct nlmsghdr *nlh;
uint32_t linklocal_netmask, linklocal_network_address;
struct in_addr *inp;
/* Prepare netlink netmask and network address for later
validation of address with mask */
inet_pton(AF_INET, LL_NET_ADDRESS, &linklocal_network_address);
inet_pton(AF_INET, LL_NET_MASK, &linklocal_netmask);
/* Get first netlink message header */
nlh = (struct nlmsghdr *) buf;
/* While valid imessage herader is available */
while ((NLMSG_OK(nlh, buf_size)) && (nlh->nlmsg_type !=
NLMSG_DONE)) {
if (nlh->nlmsg_type == RTM_NEWADDR) { /* if this is a
IP Addr response */
struct ifaddrmsg *ifa = (struct ifaddrmsg *)
NLMSG_DATA(nlh); /* Read ifaddrmsg */
struct rtattr *rth = IFA_RTA(ifa);
int rtl = IFA_PAYLOAD(nlh);
char name[IFNAMSIZ];
/* Only stuff about interface IF_NAME is
relevant */
if_indextoname(ifa->ifa_index, name);
if(ifa->ifa_family == AF_INET && strncmp (
name, IF_NAME, IFNAMSIZ) == 0 ){
/* Read first rtattr attribute header */
while (rtl && RTA_OK(rth, rtl)) {
if(rth->rta_type == IFA_ADDRESS){
inp = (struct in_addr
*)RTA_DATA(rth); /* Read IP in in_addr */
if(ifa->ifa_prefixlen
== 16 && linklocal_network_address == (inp->s_addr & linklocal_netmask)){
*linklocal_address_p = inp->s_addr; /* This is a addfress in link local
scope */
}else{
*ipaddr_p =
inp->s_addr; /* This is a regular address */
}
}
rth = RTA_NEXT(rth, rtl);
/* Advance to next rtattr attribute header */
}
}
}else if(nlh->nlmsg_type == RTM_NEWLINK ||
nlh->nlmsg_type == RTM_DELLINK || nlh->nlmsg_type == RTM_GETLINK){
/*Only link respnses */
struct ifinfomsg *ifinfo = (struct ifinfomsg *)
NLMSG_DATA(nlh); /* Read ifinfomsg */
int rtl = IFA_PAYLOAD(nlh);
struct rtattr *rth = IFLA_RTA(ifinfo);
char name[IFNAMSIZ];
/* Only stuff about interface IF_NAME is
relevant */
if_indextoname(ifinfo->ifi_index, name);
if(strncmp ( name, IF_NAME, IFNAMSIZ) == 0 ){
/* Read first rtattr attribute header */
while (rtl && RTA_OK(rth, rtl)) {
if(rth->rta_type == IFLA_ADDRESS){
/* Copy ether_addr
struct to prepared destination */
memcpy (hwaddr, (struct
ether_addr *)RTA_DATA(rth), sizeof (hwaddr));
}
rth = RTA_NEXT(rth, rtl);
/* Advance to next rtattr attribute header */
}
}
}
nlh = NLMSG_NEXT(nlh, buf_size); /* Advance to
next netlink message header */
}
return 0;
}
int main()
{
uint32_t linklocal_address, ipaddr;
char linklocal_address_s[INET_ADDRSTRLEN];
char ipaddr_s[INET_ADDRSTRLEN];
struct ether_addr *hwaddr;
linklocal_address = 0;
ipaddr = 0;
hwaddr = (struct ether_addr *) malloc(sizeof(struct ether_addr));
get_ipdata(&linklocal_address, &ipaddr, hwaddr);
inet_ntop(AF_INET, &ipaddr, ipaddr_s, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &linklocal_address, linklocal_address_s,
INET_ADDRSTRLEN);
printf("Address: %s\n", ipaddr_s);
printf("Linklocal Address: %s\n", linklocal_address_s);
printf("HW Address: %s\n", ether_ntoa(hwaddr));
return 0;
}
--
Tilman Baumann
Grandeye Limited
6 Huxley Road, Surrey Research Park
Guildford, GU2 7RE, United Kingdom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: netlinktest.c
Type: text/x-csrc
Size: 6607 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20111025/b578c6c4/attachment.bin>
More information about the libnl
mailing list