177 lines
3.8 KiB
C++
177 lines
3.8 KiB
C++
#include "apgetconnected.h"
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
|
|
#include <linux/nl80211.h>
|
|
#include <net/if.h>
|
|
|
|
#include <netlink/genl/genl.h>
|
|
#include <netlink/genl/ctrl.h>
|
|
#include <netlink/msg.h>
|
|
|
|
|
|
namespace ap
|
|
{
|
|
|
|
static int nl80211Init(struct nl_sock* nl_sock, int* nl80211_id)
|
|
{
|
|
int err;
|
|
|
|
if (!nl_sock)
|
|
{
|
|
std::cerr<<"Failed to allocate netlink socket.\n";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (genl_connect(nl_sock))
|
|
{
|
|
std::cerr<<"Failed to connect to generic netlink.\n";
|
|
err = -ENOLINK;
|
|
nl_socket_free(nl_sock);
|
|
return err;
|
|
}
|
|
|
|
nl_socket_set_buffer_size(nl_sock, 8192, 8192);
|
|
|
|
/* try to set NETLINK_EXT_ACK to 1, ignoring errors */
|
|
err = 1;
|
|
setsockopt(nl_socket_get_fd(nl_sock), SOL_NETLINK, NETLINK_EXT_ACK, &err, sizeof(err));
|
|
|
|
*nl80211_id = genl_ctrl_resolve(nl_sock, "nl80211");
|
|
if (*nl80211_id < 0)
|
|
{
|
|
std::cerr<<"nl80211 not found.\n";
|
|
err = -ENOENT;
|
|
nl_socket_free(nl_sock);
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int errorHandler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
|
|
{
|
|
(void)nla;
|
|
(void)err;
|
|
printf("netlink error\n");
|
|
*reinterpret_cast<int*>(arg) = 0;
|
|
return NL_STOP;
|
|
}
|
|
|
|
static int finishHandler(struct nl_msg *msg, void *arg)
|
|
{
|
|
(void)msg;
|
|
*reinterpret_cast<int*>(arg) = 0;
|
|
return NL_SKIP;
|
|
}
|
|
|
|
static int ackHandler(struct nl_msg *msg, void *arg)
|
|
{
|
|
(void)msg;
|
|
*reinterpret_cast<int*>(arg) = 0;
|
|
return NL_STOP;
|
|
}
|
|
|
|
|
|
static int extractDeviceMac(struct nl_msg *msg, void *arg)
|
|
{
|
|
struct nlattr* tb[NL80211_ATTR_MAX + 1];
|
|
struct genlmsghdr* gnlh = (struct genlmsghdr*)nlmsg_data(nlmsg_hdr(msg));
|
|
|
|
std::vector<uint64_t>* deviceMacAddrs = reinterpret_cast<std::vector<uint64_t>*>(arg);
|
|
|
|
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
|
|
if (!tb[NL80211_ATTR_STA_INFO])
|
|
{
|
|
std::cerr<<"sta stats missing!\n";
|
|
return -1;
|
|
}
|
|
|
|
const unsigned char* macChar = reinterpret_cast<const unsigned char*>(nla_data(tb[NL80211_ATTR_MAC]));
|
|
uint64_t macAddr = 0;
|
|
memcpy(&macAddr, macChar, 6);
|
|
deviceMacAddrs->push_back(macAddr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
std::vector<uint64_t> connectedDevices(const std::string& ifDevice, int& error)
|
|
{
|
|
struct nl_sock* nl_sock = nl_socket_alloc();
|
|
int nl80211_id = 0;
|
|
error = 0;
|
|
|
|
if(nl80211Init(nl_sock, &nl80211_id))
|
|
{
|
|
std::cerr<<"Can not init nl80211\n";
|
|
error = ERR_INIT;
|
|
}
|
|
|
|
signed long long devidx = if_nametoindex(ifDevice.c_str());
|
|
if(!devidx)
|
|
{
|
|
std::cerr<<ifDevice<<" is not a valid if device\n";
|
|
error = ERR_NO_DEV;
|
|
}
|
|
|
|
struct nl_msg *msg;
|
|
msg = nlmsg_alloc();
|
|
if(!msg) error = ERR_ALLOC;
|
|
|
|
struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
|
|
struct nl_cb *s_cb = nl_cb_alloc(NL_CB_DEFAULT);
|
|
if (!cb || !s_cb) error = ERR_ALLOC;
|
|
|
|
std::vector<uint64_t> deviceMacAddrs;
|
|
|
|
if(error == 0)
|
|
{
|
|
if(!genlmsg_put(msg, 0, 0, nl80211_id, 0, NLM_F_DUMP, NL80211_CMD_GET_STATION, 0))
|
|
{
|
|
std::cerr<<"genlmsg_put() failed\n";
|
|
error = ERR_GENERAL;
|
|
}
|
|
|
|
if(error == 0)
|
|
{
|
|
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
|
|
|
|
nl_socket_set_cb(nl_sock, s_cb);
|
|
nl_send_auto_complete(nl_sock, msg);
|
|
|
|
{
|
|
int ret = 1;
|
|
|
|
nl_cb_err(cb, NL_CB_CUSTOM, errorHandler, &ret);
|
|
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finishHandler, &ret);
|
|
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ackHandler, &ret);
|
|
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, extractDeviceMac, &deviceMacAddrs);
|
|
|
|
while (ret > 0) nl_recvmsgs(nl_sock, cb);
|
|
}
|
|
}
|
|
}
|
|
|
|
nla_put_failure:
|
|
nl_cb_put(cb);
|
|
nl_cb_put(s_cb);
|
|
nlmsg_free(msg);
|
|
nl_socket_free(nl_sock);
|
|
return deviceMacAddrs;
|
|
}
|
|
|
|
std::string macAddrToString(uint64_t macAddr)
|
|
{
|
|
unsigned char* macAddrPtr = reinterpret_cast<unsigned char*>(&macAddr);
|
|
std::stringstream ss;
|
|
ss<<std::uppercase<<std::setfill('0')<<std::setw(2)<<std::hex;
|
|
for(unsigned int i = 0; i < 6; ++i) ss<<+macAddrPtr[i]<<':';
|
|
std::string macString = ss.str();
|
|
macString.pop_back();
|
|
return macString;
|
|
}
|
|
|
|
}
|