Skip to content

Instantly share code, notes, and snippets.

@cnlohr
Created May 27, 2022 22:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cnlohr/d2192d03fcbd749837b8b41bcbc5f17d to your computer and use it in GitHub Desktop.
Save cnlohr/d2192d03fcbd749837b8b41bcbc5f17d to your computer and use it in GitHub Desktop.
Really basic libnl test for getting wifi properties.
// Based on (but modified from)
/*************************************************************
* Description: We get some wifi info using nl80211 *
* Licence : Public Domain. *
* Author : Antonios Tsolis (2016) *
*************************************************************/
//
// Modifications by C. Lohr (still under public domain)
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netlink/netlink.h> //lots of netlink functions
#include <netlink/genl/genl.h> //genl_connect, genlmsg_put
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h> //genl_ctrl_resolve
#include <linux/nl80211.h> //NL80211 definitions
static volatile int keepRunning = 1;
const char * attrnames[] = {
"NL80211_ATTR_UNSPEC",
"NL80211_ATTR_WIPHY",
"NL80211_ATTR_WIPHY_NAME",
"NL80211_ATTR_IFINDEX",
"NL80211_ATTR_IFNAME",
"NL80211_ATTR_IFTYPE",
"NL80211_ATTR_MAC",
"NL80211_ATTR_KEY_DATA",
"NL80211_ATTR_KEY_IDX",
"NL80211_ATTR_KEY_CIPHER",
"NL80211_ATTR_KEY_SEQ",
"NL80211_ATTR_KEY_DEFAULT",
"NL80211_ATTR_BEACON_INTERVAL",
"NL80211_ATTR_DTIM_PERIOD",
"NL80211_ATTR_BEACON_HEAD",
"NL80211_ATTR_BEACON_TAIL",
"NL80211_ATTR_STA_AID",
"NL80211_ATTR_STA_FLAGS",
"NL80211_ATTR_STA_LISTEN_INTERVAL",
"NL80211_ATTR_STA_SUPPORTED_RATES",
"NL80211_ATTR_STA_VLAN",
"NL80211_ATTR_STA_INFO",
"NL80211_ATTR_WIPHY_BANDS",
"NL80211_ATTR_MNTR_FLAGS",
"NL80211_ATTR_MESH_ID",
"NL80211_ATTR_STA_PLINK_ACTION",
"NL80211_ATTR_MPATH_NEXT_HOP",
"NL80211_ATTR_MPATH_INFO",
"NL80211_ATTR_BSS_CTS_PROT",
"NL80211_ATTR_BSS_SHORT_PREAMBLE",
"NL80211_ATTR_BSS_SHORT_SLOT_TIME",
"NL80211_ATTR_HT_CAPABILITY",
"NL80211_ATTR_SUPPORTED_IFTYPES",
"NL80211_ATTR_REG_ALPHA2",
"NL80211_ATTR_REG_RULES",
"NL80211_ATTR_MESH_CONFIG",
"NL80211_ATTR_BSS_BASIC_RATES",
"NL80211_ATTR_WIPHY_TXQ_PARAMS",
"NL80211_ATTR_WIPHY_FREQ",
"NL80211_ATTR_WIPHY_CHANNEL_TYPE",
"NL80211_ATTR_KEY_DEFAULT_MGMT",
"NL80211_ATTR_MGMT_SUBTYPE",
"NL80211_ATTR_IE",
"NL80211_ATTR_MAX_NUM_SCAN_SSIDS",
"NL80211_ATTR_SCAN_FREQUENCIES",
"NL80211_ATTR_SCAN_SSIDS",
"NL80211_ATTR_GENERATION",
"NL80211_ATTR_BSS",
"NL80211_ATTR_REG_INITIATOR",
"NL80211_ATTR_REG_TYPE",
"NL80211_ATTR_SUPPORTED_COMMANDS",
"NL80211_ATTR_FRAME",
"NL80211_ATTR_SSID",
"NL80211_ATTR_AUTH_TYPE",
"NL80211_ATTR_REASON_CODE",
"NL80211_ATTR_KEY_TYPE",
"NL80211_ATTR_MAX_SCAN_IE_LEN",
"NL80211_ATTR_CIPHER_SUITES",
"NL80211_ATTR_FREQ_BEFORE",
"NL80211_ATTR_FREQ_AFTER",
"NL80211_ATTR_FREQ_FIXED",
"NL80211_ATTR_WIPHY_RETRY_SHORT",
"NL80211_ATTR_WIPHY_RETRY_LONG",
"NL80211_ATTR_WIPHY_FRAG_THRESHOLD",
"NL80211_ATTR_WIPHY_RTS_THRESHOLD",
"NL80211_ATTR_TIMED_OUT",
"NL80211_ATTR_USE_MFP",
"NL80211_ATTR_STA_FLAGS2",
"NL80211_ATTR_CONTROL_PORT",
"NL80211_ATTR_TESTDATA",
"NL80211_ATTR_PRIVACY",
"NL80211_ATTR_DISCONNECTED_BY_AP",
"NL80211_ATTR_STATUS_CODE",
"NL80211_ATTR_CIPHER_SUITES_PAIRWISE",
"NL80211_ATTR_CIPHER_SUITE_GROUP",
"NL80211_ATTR_WPA_VERSIONS",
"NL80211_ATTR_AKM_SUITES",
"NL80211_ATTR_REQ_IE",
"NL80211_ATTR_RESP_IE",
"NL80211_ATTR_PREV_BSSID",
"NL80211_ATTR_KEY",
"NL80211_ATTR_KEYS",
"NL80211_ATTR_PID",
"NL80211_ATTR_4ADDR",
"NL80211_ATTR_SURVEY_INFO",
"NL80211_ATTR_PMKID",
"NL80211_ATTR_MAX_NUM_PMKIDS",
"NL80211_ATTR_DURATION",
"NL80211_ATTR_COOKIE",
"NL80211_ATTR_WIPHY_COVERAGE_CLASS",
"NL80211_ATTR_TX_RATES",
"NL80211_ATTR_FRAME_MATCH",
"NL80211_ATTR_ACK",
"NL80211_ATTR_PS_STATE",
"NL80211_ATTR_CQM",
"NL80211_ATTR_LOCAL_STATE_CHANGE",
"NL80211_ATTR_AP_ISOLATE",
"NL80211_ATTR_WIPHY_TX_POWER_SETTING",
"NL80211_ATTR_WIPHY_TX_POWER_LEVEL",
"NL80211_ATTR_TX_FRAME_TYPES",
"NL80211_ATTR_RX_FRAME_TYPES",
"NL80211_ATTR_FRAME_TYPE",
"NL80211_ATTR_CONTROL_PORT_ETHERTYPE",
"NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT",
"NL80211_ATTR_SUPPORT_IBSS_RSN",
"NL80211_ATTR_WIPHY_ANTENNA_TX",
"NL80211_ATTR_WIPHY_ANTENNA_RX",
"NL80211_ATTR_MCAST_RATE",
"NL80211_ATTR_OFFCHANNEL_TX_OK",
"NL80211_ATTR_BSS_HT_OPMODE",
"NL80211_ATTR_KEY_DEFAULT_TYPES",
"NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION",
"NL80211_ATTR_MESH_SETUP",
"NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX",
"NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX",
"NL80211_ATTR_SUPPORT_MESH_AUTH",
"NL80211_ATTR_STA_PLINK_STATE",
"NL80211_ATTR_WOWLAN_TRIGGERS",
"NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED",
"NL80211_ATTR_SCHED_SCAN_INTERVAL",
"NL80211_ATTR_INTERFACE_COMBINATIONS",
"NL80211_ATTR_SOFTWARE_IFTYPES",
"NL80211_ATTR_REKEY_DATA",
"NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS",
"NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN",
"NL80211_ATTR_SCAN_SUPP_RATES",
"NL80211_ATTR_HIDDEN_SSID",
"NL80211_ATTR_IE_PROBE_RESP",
"NL80211_ATTR_IE_ASSOC_RESP",
"NL80211_ATTR_STA_WME",
"NL80211_ATTR_SUPPORT_AP_UAPSD",
"NL80211_ATTR_ROAM_SUPPORT",
"NL80211_ATTR_SCHED_SCAN_MATCH",
"NL80211_ATTR_MAX_MATCH_SETS",
"NL80211_ATTR_PMKSA_CANDIDATE",
"NL80211_ATTR_TX_NO_CCK_RATE",
"NL80211_ATTR_TDLS_ACTION",
"NL80211_ATTR_TDLS_DIALOG_TOKEN",
"NL80211_ATTR_TDLS_OPERATION",
"NL80211_ATTR_TDLS_SUPPORT",
"NL80211_ATTR_TDLS_EXTERNAL_SETUP",
"NL80211_ATTR_DEVICE_AP_SME",
"NL80211_ATTR_DONT_WAIT_FOR_ACK",
"NL80211_ATTR_FEATURE_FLAGS",
"NL80211_ATTR_PROBE_RESP_OFFLOAD",
"NL80211_ATTR_PROBE_RESP",
"NL80211_ATTR_DFS_REGION",
"NL80211_ATTR_DISABLE_HT",
"NL80211_ATTR_HT_CAPABILITY_MASK",
"NL80211_ATTR_NOACK_MAP",
"NL80211_ATTR_INACTIVITY_TIMEOUT",
"NL80211_ATTR_RX_SIGNAL_DBM",
"NL80211_ATTR_BG_SCAN_PERIOD",
"NL80211_ATTR_WDEV",
"NL80211_ATTR_USER_REG_HINT_TYPE",
"NL80211_ATTR_CONN_FAILED_REASON",
"NL80211_ATTR_SAE_DATA",
"NL80211_ATTR_VHT_CAPABILITY",
"NL80211_ATTR_SCAN_FLAGS",
"NL80211_ATTR_CHANNEL_WIDTH",
"NL80211_ATTR_CENTER_FREQ1",
"NL80211_ATTR_CENTER_FREQ2",
"NL80211_ATTR_P2P_CTWINDOW",
"NL80211_ATTR_P2P_OPPPS",
"NL80211_ATTR_LOCAL_MESH_POWER_MODE",
"NL80211_ATTR_ACL_POLICY",
"NL80211_ATTR_MAC_ADDRS",
"NL80211_ATTR_MAC_ACL_MAX",
"NL80211_ATTR_RADAR_EVENT",
"NL80211_ATTR_EXT_CAPA",
"NL80211_ATTR_EXT_CAPA_MASK",
"NL80211_ATTR_STA_CAPABILITY",
"NL80211_ATTR_STA_EXT_CAPABILITY",
"NL80211_ATTR_PROTOCOL_FEATURES",
"NL80211_ATTR_SPLIT_WIPHY_DUMP",
"NL80211_ATTR_DISABLE_VHT",
"NL80211_ATTR_VHT_CAPABILITY_MASK",
"NL80211_ATTR_MDID",
"NL80211_ATTR_IE_RIC",
"NL80211_ATTR_CRIT_PROT_ID",
"NL80211_ATTR_MAX_CRIT_PROT_DURATION",
"NL80211_ATTR_PEER_AID",
"NL80211_ATTR_COALESCE_RULE",
"NL80211_ATTR_CH_SWITCH_COUNT",
"NL80211_ATTR_CH_SWITCH_BLOCK_TX",
"NL80211_ATTR_CSA_IES",
"NL80211_ATTR_CSA_C_OFF_BEACON",
"NL80211_ATTR_CSA_C_OFF_PRESP",
"NL80211_ATTR_RXMGMT_FLAGS",
"NL80211_ATTR_STA_SUPPORTED_CHANNELS",
"NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES",
"NL80211_ATTR_HANDLE_DFS",
"NL80211_ATTR_SUPPORT_5_MHZ",
"NL80211_ATTR_SUPPORT_10_MHZ",
"NL80211_ATTR_OPMODE_NOTIF",
"NL80211_ATTR_VENDOR_ID",
"NL80211_ATTR_VENDOR_SUBCMD",
"NL80211_ATTR_VENDOR_DATA",
"NL80211_ATTR_VENDOR_EVENTS",
"NL80211_ATTR_QOS_MAP",
"NL80211_ATTR_MAC_HINT",
"NL80211_ATTR_WIPHY_FREQ_HINT",
"NL80211_ATTR_MAX_AP_ASSOC_STA",
"NL80211_ATTR_TDLS_PEER_CAPABILITY",
"NL80211_ATTR_SOCKET_OWNER",
"NL80211_ATTR_CSA_C_OFFSETS_TX",
"NL80211_ATTR_MAX_CSA_COUNTERS",
"NL80211_ATTR_TDLS_INITIATOR",
"NL80211_ATTR_USE_RRM",
"NL80211_ATTR_WIPHY_DYN_ACK",
"NL80211_ATTR_TSID",
"NL80211_ATTR_USER_PRIO",
"NL80211_ATTR_ADMITTED_TIME",
"NL80211_ATTR_SMPS_MODE",
"NL80211_ATTR_OPER_CLASS",
"NL80211_ATTR_MAC_MASK",
"NL80211_ATTR_WIPHY_SELF_MANAGED_REG",
"NL80211_ATTR_EXT_FEATURES",
"NL80211_ATTR_SURVEY_RADIO_STATS",
"NL80211_ATTR_NETNS_FD",
"NL80211_ATTR_SCHED_SCAN_DELAY",
"NL80211_ATTR_REG_INDOOR",
"NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS",
"NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL",
"NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS",
"NL80211_ATTR_SCHED_SCAN_PLANS",
"__NL80211_ATTR_AFTER_LAST",
};
typedef struct {
int id;
struct nl_sock *socket;
struct nl_cb *cb3;
int result3;
} Netlink;
typedef struct {
char ifname[30];
int ifindex;
int signal;
uint64_t txrate;
} Wifi;
static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
[NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
[NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
[NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
[NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
[NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
[NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
[NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
[NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
[NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
};
static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
};
static int initNl80211(Netlink *nl, Wifi *w);
static int finish_handler(struct nl_msg *msg, void *arg);
static int getWifiName_callback(struct nl_msg *msg, void *arg);
static int getWifiInfo_callback(struct nl_msg *msg, void *arg);
static int getWifiInfo_callback2(struct nl_msg *msg, void *arg);
static int getWifiStatus(Netlink *nl, Wifi *w);
static int initNl80211(Netlink *nl, Wifi *w)
{
nl->socket = nl_socket_alloc();
if (!nl->socket) {
fprintf(stderr, "Failed to allocate netlink socket.\n");
return -ENOMEM;
}
nl_socket_set_buffer_size(nl->socket, 8192, 8192);
if (genl_connect(nl->socket)) {
fprintf(stderr, "Failed to connect to netlink socket.\n");
nl_close(nl->socket);
nl_socket_free(nl->socket);
return -ENOLINK;
}
nl->id = genl_ctrl_resolve(nl->socket, "nl80211");
if (nl->id < 0) {
fprintf(stderr, "Nl80211 interface not found.\n");
nl_close(nl->socket);
nl_socket_free(nl->socket);
return -ENOENT;
}
nl->cb3 = nl_cb_alloc(NL_CB_DEFAULT);
nl_cb_set(nl->cb3, NL_CB_VALID, NL_CB_CUSTOM, getWifiInfo_callback2, w);
nl_cb_set(nl->cb3, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &(nl->result3));
return nl->id;
}
static int finish_handler(struct nl_msg *msg, void *arg)
{
int *ret = arg;
*ret = 0;
return NL_SKIP;
}
static int getWifiInfo_callback2(struct nl_msg *msg, void *arg)
{
struct nlattr * tb[NL80211_ATTR_MAX + 1];
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct nlattr * sinfo[NL80211_STA_INFO_MAX + 1];
struct nlattr * rinfo[NL80211_FREQUENCY_ATTR_MAX + 1];
//nl_msg_dump(msg, stdout);
nla_parse(tb,
NL80211_ATTR_MAX,
genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0),
NULL);
if (tb[NL80211_ATTR_IFNAME]) {
printf( "IfName: %s\n", nla_get_string(tb[NL80211_ATTR_IFNAME]));
}
int i;
for( i = 0; i < /*NL80211_ATTR_MAX*/sizeof(attrnames)/sizeof(attrnames[0]); i++ )
{
if( tb[i] )
{
int type = nla_len( tb[i] );
printf( "%d = %p (%s) (%d) %d\n", i, tb[i], attrnames[i], type, nla_get_u32( tb[i] ) );
}
}
return NL_SKIP;
}
static int getWifiStatus(Netlink *nl, Wifi *w)
{
nl->result3 = 1;
struct nl_msg *msg3 = nlmsg_alloc();
if (!msg3) {
fprintf(stderr, "Failed to allocate netlink message.\n");
return -2;
}
printf( "%d\n", nl->id );
genlmsg_put(msg3,
NL_AUTO_PORT,
NL_AUTO_SEQ,
nl->id,
0,
NLM_F_DUMP,
NL80211_CMD_GET_INTERFACE,
0);
nl_send_auto(nl->socket, msg3);
while (nl->result3 > 0) {
nl_recvmsgs(nl->socket, nl->cb3);
}
nlmsg_free(msg3);
return 0;
}
int main(int argc, char **argv)
{
Netlink nl;
Wifi w;
nl.id = initNl80211(&nl, &w);
if (nl.id < 0) {
fprintf(stderr, "Error initializing netlink 802.11\n");
return -1;
}
getWifiStatus(&nl, &w);
printf("Exiting gracefully... ");
nl_cb_put(nl.cb3);
nl_close(nl.socket);
nl_socket_free(nl.socket);
printf("OK\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment