111 lines
No EOL
3.3 KiB
C++
111 lines
No EOL
3.3 KiB
C++
#include "netlinkmonitor.h"
|
|
#include <QDebug>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
#include <linux/netlink.h>
|
|
|
|
#define NETLINK_MYPROTO NETLINK_USERSOCK // Matches your kernel module, or use NETLINK_USERSOCK
|
|
#define MY_NETLINK_GROUP 27 // Multicast group your kernel module broadcasts on
|
|
#define MAX_PAYLOAD 1024
|
|
|
|
NetlinkMonitor::NetlinkMonitor(QObject *parent)
|
|
: QObject(parent)
|
|
, m_sockFd(-1)
|
|
, m_socketNotifier(nullptr)
|
|
{
|
|
}
|
|
|
|
NetlinkMonitor::~NetlinkMonitor()
|
|
{
|
|
if (m_socketNotifier) {
|
|
delete m_socketNotifier;
|
|
m_socketNotifier = nullptr;
|
|
}
|
|
if (m_sockFd != -1) {
|
|
close(m_sockFd);
|
|
m_sockFd = -1;
|
|
}
|
|
}
|
|
|
|
bool NetlinkMonitor::setupNetlink()
|
|
{
|
|
// 1. Create netlink socket
|
|
m_sockFd = socket(AF_NETLINK, SOCK_RAW, NETLINK_MYPROTO);
|
|
if (m_sockFd < 0) {
|
|
qWarning() << "Failed to create netlink socket:" << strerror(errno);
|
|
return false;
|
|
}
|
|
|
|
// 2. Bind to a local address with the desired groups
|
|
struct sockaddr_nl addr;
|
|
memset(&addr, 0, sizeof(addr));
|
|
addr.nl_family = AF_NETLINK;
|
|
addr.nl_pid = getpid(); // our user-space PID
|
|
// Subscribe to the group (bitmask). For group #1, you set bit (1-1).
|
|
addr.nl_groups = 1 << (MY_NETLINK_GROUP - 1);
|
|
|
|
if (bind(m_sockFd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0) {
|
|
qWarning() << "Failed to bind netlink socket:" << strerror(errno);
|
|
close(m_sockFd);
|
|
m_sockFd = -1;
|
|
return false;
|
|
}
|
|
|
|
// 3. Create a QSocketNotifier to watch for incoming data
|
|
m_socketNotifier = new QSocketNotifier(m_sockFd, QSocketNotifier::Read, this);
|
|
connect(m_socketNotifier, &QSocketNotifier::activated,
|
|
this, &NetlinkMonitor::handleReadyRead);
|
|
|
|
qDebug() << "NetlinkMonitor: socket setup complete, fd =" << m_sockFd;
|
|
return true;
|
|
}
|
|
|
|
void NetlinkMonitor::handleReadyRead()
|
|
{
|
|
// This slot is triggered whenever the netlink socket has data to read.
|
|
char buffer[MAX_PAYLOAD];
|
|
struct iovec iov = {
|
|
.iov_base = buffer,
|
|
.iov_len = sizeof(buffer)
|
|
};
|
|
struct sockaddr_nl srcAddr;
|
|
struct msghdr msg;
|
|
struct nlmsghdr *nlh;
|
|
|
|
memset(&srcAddr, 0, sizeof(srcAddr));
|
|
memset(&msg, 0, sizeof(msg));
|
|
|
|
msg.msg_name = &srcAddr;
|
|
msg.msg_namelen = sizeof(srcAddr);
|
|
msg.msg_iov = &iov;
|
|
msg.msg_iovlen = 1;
|
|
|
|
ssize_t ret = recvmsg(m_sockFd, &msg, 0);
|
|
if (ret < 0) {
|
|
qWarning() << "recvmsg() failed:" << strerror(errno);
|
|
return;
|
|
}
|
|
|
|
// The netlink message is in the buffer as one or more nlmsghdr blocks.
|
|
for (nlh = (struct nlmsghdr *)buffer; NLMSG_OK(nlh, ret);
|
|
nlh = NLMSG_NEXT(nlh, ret)) {
|
|
|
|
if (nlh->nlmsg_type == NLMSG_DONE) {
|
|
// The actual payload is after the nlmsghdr
|
|
char *payload = (char *)NLMSG_DATA(nlh);
|
|
// Convert to QString, then emit a signal
|
|
QString msgStr = QString::fromLatin1(payload);
|
|
messageReceived(msgStr);
|
|
printf("%s\n", msgStr.toStdString().c_str());
|
|
}
|
|
else if (nlh->nlmsg_type == NLMSG_ERROR) {
|
|
qWarning() << "Received netlink error message";
|
|
}
|
|
else {
|
|
// In a real app, handle other message types as needed
|
|
qDebug() << "Received netlink type:" << nlh->nlmsg_type;
|
|
}
|
|
}
|
|
} |