Question

I'm starting wifi related project and i've completed one with linux ioctl calls. Now i must do the same with help of libnl as ioctl is now deprecated, i've already read all the core documentation but still don't understand how to send command on specific interface. How can i send command to network interface? say i want send NL80211_CMD_TRIGGER_SCAN, how can i do this? any example code is greatly appreciated as it will be the start of my journey. As i understand for now i must create libnl socket, something like:

struct nl_sock *socket;
sock = nl_socket_alloc();

and then compose nl_msg message with my command and send it, but how?

P.S. suppose with nl_send(), but i hope you understand that i stuck at point of no-understanding the idea of how this lib works

Was it helpful?

Solution

I am also working on something that involves netlink. I pieced together a program that seems to work on my system (debian 3.2.0.4). It is a simple program that sends a msg first and starts listening updates coming from kernel. I believe you would have to change the send part and set necessary flags etc.

One rather important difference: I don't call nl_socket_alloc, instead, I create a regular socket. I am sure I have some mistake in there, you can be straightforward. I hope it helps:

#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/cache.h>
#include <netlink/route/link.h>
//#include <>

#define NETLINK_USER 31

#define MAX_PAYLOAD 1024

using std::cout;
using std::endl;

int sequence_number = 0;

void sendNetLinkMsg(int fd) {
    struct nlmsghdr *nh = 0;
    struct sockaddr_nl sa;
    struct iovec iov = { nh, nh->nlmsg_len };
    struct msghdr msg;

    msg = {&sa, sizeof(sa), &iov, 1, NULL, 0, 0};
    memset(&sa, 0, sizeof(sa));
    sa.nl_family = AF_NETLINK;
    nh->nlmsg_pid = getpid();
    nh->nlmsg_seq = ++sequence_number;
    nh->nlmsg_flags |= NLM_F_ACK;

    sendmsg(fd, &msg, 0);
}

void recvNetLinkMsg(int fd, struct msghdr* msg, char* buf) {
    int len;
    struct nlmsghdr *nh;
    len = recvmsg(fd, msg, 0);
    for (nh = (struct nlmsghdr *) buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
        if (nh->nlmsg_type == NLMSG_DONE)
            break;

        if (nh->nlmsg_type == NLMSG_ERROR) {
            cout << "Error" << endl;
        }
        if (nh->nlmsg_type == RTM_DELROUTE)
            cout << "Delete route" << endl;
        else if (nh->nlmsg_type == RTM_NEWROUTE)
            cout << "New route" << endl;
        else {
            cout << "Unknown msg: " << nh->nlmsg_type << endl;
        }
    }
}

int main() {
    struct sockaddr_nl sockAddr;
    memset(&sockAddr, 0, sizeof(sockAddr));
    sockAddr.nl_family = AF_NETLINK;
    sockAddr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;

    int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    bind(fd, (struct sockaddr *) &sockAddr, sizeof(sockAddr));

    char buf[4096];
    struct iovec iov = { buf, sizeof(buf) };
    struct msghdr msg;

    msg = {&sockAddr, sizeof(sockAddr), &iov, 1, NULL, 0, 0};

    sendNetLinkMsg(fd);

    while (true) {
        recvNetLinkMsg(fd, &msg, buf);
    }
    return 0;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top