mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-13 02:42:09 +02:00
Wifi (Linux): adds channel width and device driver detection
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
struct FFWifiInterface {
|
||||
FFstrbuf description;
|
||||
FFstrbuf status;
|
||||
FFstrbuf driver;
|
||||
};
|
||||
|
||||
struct FFWifiConnection {
|
||||
@@ -18,6 +19,7 @@ struct FFWifiConnection {
|
||||
double rxRate;
|
||||
double txRate;
|
||||
uint16_t channel;
|
||||
uint16_t channelWidth; // MHz
|
||||
uint16_t frequency; // MHz
|
||||
};
|
||||
|
||||
|
||||
@@ -212,8 +212,9 @@ static bool ffWifiNlInit(FFWifiNlContext* ctx) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static double ffWifiParseBitrateFromRateInfo(const struct nlattr* rateAttr, FFstrbuf* protocol) {
|
||||
static double ffWifiParseBitrateFromRateInfo(const struct nlattr* rateAttr, FFstrbuf* protocol, uint16_t* channelWidth) {
|
||||
double rate = -DBL_MAX;
|
||||
uint16_t width = 0;
|
||||
size_t remaining = ffWifiNlAttrPayload(rateAttr);
|
||||
|
||||
for (const struct nlattr* info = (const struct nlattr*) ffWifiNlAttrData(rateAttr);
|
||||
@@ -223,6 +224,40 @@ static double ffWifiParseBitrateFromRateInfo(const struct nlattr* rateAttr, FFst
|
||||
size_t payload = ffWifiNlAttrPayload(info);
|
||||
|
||||
switch (type) {
|
||||
case NL80211_RATE_INFO_40_MHZ_WIDTH:
|
||||
width = 40;
|
||||
break;
|
||||
case NL80211_RATE_INFO_80_MHZ_WIDTH:
|
||||
case NL80211_RATE_INFO_80P80_MHZ_WIDTH:
|
||||
width = 80;
|
||||
break;
|
||||
case NL80211_RATE_INFO_160_MHZ_WIDTH:
|
||||
width = 160;
|
||||
break;
|
||||
case 18 /* NL80211_RATE_INFO_320_MHZ_WIDTH */:
|
||||
width = 320;
|
||||
break;
|
||||
case NL80211_RATE_INFO_10_MHZ_WIDTH:
|
||||
width = 10;
|
||||
break;
|
||||
case NL80211_RATE_INFO_5_MHZ_WIDTH:
|
||||
width = 5;
|
||||
break;
|
||||
case 25 /* NL80211_RATE_INFO_1_MHZ_WIDTH */:
|
||||
width = 1;
|
||||
break;
|
||||
case 26 /* NL80211_RATE_INFO_2_MHZ_WIDTH */:
|
||||
width = 2;
|
||||
break;
|
||||
case 27 /* NL80211_RATE_INFO_4_MHZ_WIDTH */:
|
||||
width = 4;
|
||||
break;
|
||||
case 28 /* NL80211_RATE_INFO_8_MHZ_WIDTH */:
|
||||
width = 8;
|
||||
break;
|
||||
case 29 /* NL80211_RATE_INFO_16_MHZ_WIDTH */:
|
||||
width = 16;
|
||||
break;
|
||||
case 30 /* NL80211_RATE_INFO_UHR_MCS */:
|
||||
ffStrbufSetStatic(protocol, "802.11bn (Wi-Fi 8)");
|
||||
break;
|
||||
@@ -254,9 +289,126 @@ static double ffWifiParseBitrateFromRateInfo(const struct nlattr* rateAttr, FFst
|
||||
}
|
||||
}
|
||||
|
||||
if (rate != -DBL_MAX && *channelWidth == 0) {
|
||||
*channelWidth = width;
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static uint16_t ffWifiChannelWidthToMhz(uint32_t width) {
|
||||
switch (width) {
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
return 20;
|
||||
case NL80211_CHAN_WIDTH_40:
|
||||
return 40;
|
||||
case NL80211_CHAN_WIDTH_80:
|
||||
case NL80211_CHAN_WIDTH_80P80:
|
||||
return 80;
|
||||
case NL80211_CHAN_WIDTH_160:
|
||||
return 160;
|
||||
case NL80211_CHAN_WIDTH_5:
|
||||
return 5;
|
||||
case NL80211_CHAN_WIDTH_10:
|
||||
return 10;
|
||||
case NL80211_CHAN_WIDTH_1:
|
||||
return 1;
|
||||
case NL80211_CHAN_WIDTH_2:
|
||||
return 2;
|
||||
case NL80211_CHAN_WIDTH_4:
|
||||
return 4;
|
||||
case NL80211_CHAN_WIDTH_8:
|
||||
return 8;
|
||||
case NL80211_CHAN_WIDTH_16:
|
||||
return 16;
|
||||
case 13 /* NL80211_CHAN_WIDTH_320 */:
|
||||
return 320;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ffWifiFetchInterfaceInfo(FFWifiNlContext* ctx, FFWifiResult* item, uint32_t ifIndex) {
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct genlmsghdr genl;
|
||||
char attrs[32];
|
||||
} req = {
|
||||
.nlh = {
|
||||
.nlmsg_len = NLMSG_LENGTH(sizeof(struct genlmsghdr)),
|
||||
.nlmsg_type = ctx->nl80211FamilyId,
|
||||
.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
|
||||
.nlmsg_seq = ++ctx->seq,
|
||||
.nlmsg_pid = ctx->portId,
|
||||
},
|
||||
.genl = {
|
||||
.cmd = NL80211_CMD_GET_INTERFACE,
|
||||
.version = 0,
|
||||
},
|
||||
};
|
||||
|
||||
if (!ffWifiNlAppendAttr(&req.nlh, sizeof(req), NL80211_ATTR_IFINDEX, &ifIndex, sizeof(ifIndex))) {
|
||||
FF_DEBUG("Failed to build nl80211 interface request");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_nl addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
};
|
||||
|
||||
ssize_t sent = sendto(ctx->sockFd, &req, req.nlh.nlmsg_len, 0, (struct sockaddr*) &addr, sizeof(addr));
|
||||
if (sent != (ssize_t) req.nlh.nlmsg_len) {
|
||||
FF_DEBUG("Failed to send nl80211 interface request");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t buffer[8192];
|
||||
while (true) {
|
||||
ssize_t received = recvfrom(ctx->sockFd, buffer, sizeof(buffer), 0, nullptr, nullptr);
|
||||
if (received < 0) {
|
||||
FF_DEBUG("Failed to receive nl80211 interface reply: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const struct nlmsghdr* nlh = (const struct nlmsghdr*) buffer;
|
||||
NLMSG_OK(nlh, received);
|
||||
nlh = NLMSG_NEXT(nlh, received)) {
|
||||
if (nlh->nlmsg_seq != req.nlh.nlmsg_seq) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nlh->nlmsg_type == NLMSG_ERROR) {
|
||||
const struct nlmsgerr* err = (const struct nlmsgerr*) NLMSG_DATA(nlh);
|
||||
if (err->error != 0) {
|
||||
FF_DEBUG("nl80211 interface request failed: %s", strerror(-err->error));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nlh->nlmsg_type != ctx->nl80211FamilyId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const struct genlmsghdr* genl = (const struct genlmsghdr*) NLMSG_DATA(nlh);
|
||||
size_t attrRemaining = nlh->nlmsg_len - NLMSG_HDRLEN - GENL_HDRLEN;
|
||||
for (const struct nlattr* attr = (const struct nlattr*) ((const char*) genl + GENL_HDRLEN);
|
||||
ffWifiNlAttrOk(attr, attrRemaining);
|
||||
attr = ffWifiNlAttrNext(attr, &attrRemaining)) {
|
||||
if ((attr->nla_type & NLA_TYPE_MASK) != NL80211_ATTR_CHANNEL_WIDTH ||
|
||||
ffWifiNlAttrPayload(attr) < sizeof(uint32_t)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
item->conn.channelWidth = ffWifiChannelWidthToMhz(*(const uint32_t*) ffWifiNlAttrData(attr));
|
||||
return item->conn.channelWidth != 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ffWifiApplySecurityFlags(FFWifiResult* item, const FFWifiSecurityFlags* sec) {
|
||||
ffStrbufClear(&item->conn.security);
|
||||
|
||||
@@ -566,13 +718,13 @@ static void ffWifiParseStationInfo(const struct nlattr* staInfoAttr, FFWifiResul
|
||||
if (type == NL80211_STA_INFO_SIGNAL && payload >= sizeof(uint8_t) && item->conn.signalQuality == -DBL_MAX) {
|
||||
int rssi = (int8_t) *(const uint8_t*) ffWifiNlAttrData(attr);
|
||||
item->conn.signalQuality = rssiToSignalQuality(rssi);
|
||||
} else if (type == NL80211_STA_INFO_TX_BITRATE && item->conn.txRate == -DBL_MAX) {
|
||||
double tx = ffWifiParseBitrateFromRateInfo(attr, &item->conn.protocol);
|
||||
} else if (type == NL80211_STA_INFO_TX_BITRATE && (item->conn.txRate == -DBL_MAX || item->conn.channelWidth == 0)) {
|
||||
double tx = ffWifiParseBitrateFromRateInfo(attr, &item->conn.protocol, &item->conn.channelWidth);
|
||||
if (tx != -DBL_MAX) {
|
||||
item->conn.txRate = tx;
|
||||
}
|
||||
} else if (type == NL80211_STA_INFO_RX_BITRATE && item->conn.rxRate == -DBL_MAX) {
|
||||
double rx = ffWifiParseBitrateFromRateInfo(attr, &item->conn.protocol);
|
||||
} else if (type == NL80211_STA_INFO_RX_BITRATE && (item->conn.rxRate == -DBL_MAX || item->conn.channelWidth == 0)) {
|
||||
double rx = ffWifiParseBitrateFromRateInfo(attr, &item->conn.protocol, &item->conn.channelWidth);
|
||||
if (rx != -DBL_MAX) {
|
||||
item->conn.rxRate = rx;
|
||||
}
|
||||
@@ -680,6 +832,7 @@ static const char* detectWithNetlink(FFWifiNlContext* ctx, FFWifiResult* item, u
|
||||
if (ffWifiFetchScanInfo(ctx, item, ifIndex)) {
|
||||
FF_DEBUG("found associated BSS: %s", item->conn.ssid.chars);
|
||||
ffStrbufSetStatic(&item->conn.status, "connected");
|
||||
ffWifiFetchInterfaceInfo(ctx, item, ifIndex);
|
||||
ffWifiFetchStationInfo(ctx, item, ifIndex);
|
||||
if (!item->conn.protocol.length && item->conn.txRate != -DBL_MAX) {
|
||||
FF_DEBUG("nl80211 station info did not include MCS family fields");
|
||||
@@ -914,6 +1067,7 @@ const char* ffDetectWifi(FFlist* result) {
|
||||
FFWifiResult* item = FF_LIST_ADD(FFWifiResult, *result);
|
||||
ffStrbufInitS(&item->inf.description, i->if_name);
|
||||
ffStrbufInit(&item->inf.status);
|
||||
ffStrbufInit(&item->inf.driver);
|
||||
ffStrbufInit(&item->conn.status);
|
||||
ffStrbufInit(&item->conn.ssid);
|
||||
ffStrbufInit(&item->conn.bssid);
|
||||
@@ -923,8 +1077,23 @@ const char* ffDetectWifi(FFlist* result) {
|
||||
item->conn.rxRate = -DBL_MAX;
|
||||
item->conn.txRate = -DBL_MAX;
|
||||
item->conn.channel = 0;
|
||||
item->conn.channelWidth = 0;
|
||||
item->conn.frequency = 0;
|
||||
|
||||
{
|
||||
ffStrbufSetF(&buffer, "/sys/class/net/%s/device/driver", i->if_name);
|
||||
char pathBuf[PATH_MAX];
|
||||
ssize_t resultLength = readlink(buffer.chars, pathBuf, ARRAY_SIZE(pathBuf));
|
||||
if (resultLength > 0) {
|
||||
const char* p = memrchr(pathBuf, '/', (size_t) resultLength);
|
||||
if (p) {
|
||||
++p;
|
||||
ffStrbufSetNS(&item->inf.driver, (uint32_t) (resultLength - (p - pathBuf)), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char operstate;
|
||||
ffStrbufSetF(&buffer, "/sys/class/net/%s/operstate", i->if_name);
|
||||
if (!ffReadFileData(buffer.chars, 1, &operstate)) {
|
||||
|
||||
@@ -98,6 +98,7 @@ bool ffPrintWifi(FFWifiOptions* options) {
|
||||
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Wifi), moduleIndex, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
|
||||
FF_ARG(item->inf.description, "inf-desc"),
|
||||
FF_ARG(item->inf.status, "inf-status"),
|
||||
FF_ARG(item->inf.driver, "inf-driver"),
|
||||
FF_ARG(item->conn.status, "status"),
|
||||
FF_ARG(item->conn.ssid, "ssid"),
|
||||
FF_ARG(item->conn.bssid, "bssid"),
|
||||
@@ -108,6 +109,7 @@ bool ffPrintWifi(FFWifiOptions* options) {
|
||||
FF_ARG(item->conn.security, "security"),
|
||||
FF_ARG(percentBar, "signal-quality-bar"),
|
||||
FF_ARG(item->conn.channel, "channel"),
|
||||
FF_ARG(item->conn.channelWidth, "channel-width"),
|
||||
FF_ARG(bandStr, "band"),
|
||||
}));
|
||||
}
|
||||
@@ -116,6 +118,7 @@ bool ffPrintWifi(FFWifiOptions* options) {
|
||||
FF_LIST_FOR_EACH (FFWifiResult, item, result) {
|
||||
ffStrbufDestroy(&item->inf.description);
|
||||
ffStrbufDestroy(&item->inf.status);
|
||||
ffStrbufDestroy(&item->inf.driver);
|
||||
ffStrbufDestroy(&item->conn.status);
|
||||
ffStrbufDestroy(&item->conn.ssid);
|
||||
ffStrbufDestroy(&item->conn.bssid);
|
||||
@@ -163,6 +166,7 @@ bool ffGenerateWifiJsonResult([[maybe_unused]] FFWifiOptions* options, yyjson_mu
|
||||
yyjson_mut_val* inf = yyjson_mut_obj_add_obj(doc, obj, "inf");
|
||||
yyjson_mut_obj_add_strbuf(doc, inf, "description", &wifi->inf.description);
|
||||
yyjson_mut_obj_add_strbuf(doc, inf, "status", &wifi->inf.status);
|
||||
yyjson_mut_obj_add_strbuf(doc, inf, "driver", &wifi->inf.driver);
|
||||
|
||||
yyjson_mut_val* conn = yyjson_mut_obj_add_obj(doc, obj, "conn");
|
||||
yyjson_mut_obj_add_strbuf(doc, conn, "status", &wifi->conn.status);
|
||||
@@ -186,12 +190,14 @@ bool ffGenerateWifiJsonResult([[maybe_unused]] FFWifiOptions* options, yyjson_mu
|
||||
yyjson_mut_obj_add_null(doc, conn, "txRate");
|
||||
}
|
||||
yyjson_mut_obj_add_uint(doc, conn, "channel", wifi->conn.channel);
|
||||
yyjson_mut_obj_add_uint(doc, conn, "channelWidth", wifi->conn.channelWidth);
|
||||
yyjson_mut_obj_add_uint(doc, conn, "frequency", wifi->conn.frequency);
|
||||
}
|
||||
|
||||
FF_LIST_FOR_EACH (FFWifiResult, item, result) {
|
||||
ffStrbufDestroy(&item->inf.description);
|
||||
ffStrbufDestroy(&item->inf.status);
|
||||
ffStrbufDestroy(&item->inf.driver);
|
||||
ffStrbufDestroy(&item->conn.status);
|
||||
ffStrbufDestroy(&item->conn.ssid);
|
||||
ffStrbufDestroy(&item->conn.bssid);
|
||||
@@ -240,6 +246,7 @@ FFModuleBaseInfo ffWifiModuleInfo = {
|
||||
.formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
|
||||
{ "Interface description", "inf-desc" },
|
||||
{ "Interface status", "inf-status" },
|
||||
{ "Interface driver", "inf-driver" },
|
||||
{ "Connection status", "status" },
|
||||
{ "Connection SSID", "ssid" },
|
||||
{ "Connection BSSID", "bssid" },
|
||||
@@ -250,6 +257,7 @@ FFModuleBaseInfo ffWifiModuleInfo = {
|
||||
{ "Connection Security algorithm", "security" },
|
||||
{ "Connection signal quality (percentage bar)", "signal-quality-bar" },
|
||||
{ "Connection channel number", "channel" },
|
||||
{ "Connection channel width in MHz", "channel-width" },
|
||||
{ "Connection channel band in GHz", "band" },
|
||||
})),
|
||||
.defaultOrder = 51,
|
||||
|
||||
Reference in New Issue
Block a user