master ohmu/fastfetch-openbsd / src / detection / wifi / wifi_sunos.c
ohmu  ·  2026-10-15
  1#include "wifi.h"
  2#include "common/debug.h"
  3#include "common/io.h"
  4#include "common/mallocHelper.h"
  5
  6#include <dirent.h>
  7#include <fcntl.h>
  8#include <stropts.h>
  9#include <sys/ioctl.h>
 10#include <unistd.h>
 11
 12#include <inet/wifi_ioctl.h>
 13
 14static bool getWifiValue(int fd, uint32_t id, void* value, size_t valueSize, wldp_t* buffer) {
 15    memset(buffer, 0, MAX_BUF_LEN);
 16    buffer->wldp_type = NET_802_11;
 17    buffer->wldp_id = id;
 18
 19    struct strioctl request = {
 20        .ic_cmd = WLAN_GET_PARAM,
 21        .ic_timout = 0,
 22        .ic_len = MAX_BUF_LEN,
 23        .ic_dp = (char*) buffer,
 24    };
 25
 26    if (ioctl(fd, I_STR, &request) != 0 || buffer->wldp_result != WL_SUCCESS || buffer->wldp_length < WIFI_BUF_OFFSET + valueSize || buffer->wldp_length > MAX_BUF_LEN) {
 27        return false;
 28    }
 29
 30    memcpy(value, buffer->wldp_buf, valueSize);
 31    return true;
 32}
 33
 34static void setWifiProtocol(FFstrbuf* protocol, uint32_t subtype, bool htEnabled) {
 35    switch (subtype) {
 36        case WL_FHSS:
 37            ffStrbufSetStatic(protocol, "802.11 (FHSS)");
 38            break;
 39        case WL_DSSS:
 40            ffStrbufSetStatic(protocol, "802.11 (DSSS)");
 41            break;
 42        case WL_IRBASE:
 43            ffStrbufSetStatic(protocol, "802.11 (IR)");
 44            break;
 45        case WL_OFDM:
 46            ffStrbufSetStatic(protocol, htEnabled ? "802.11n (Wi-Fi 4)" : "802.11a");
 47            break;
 48        case WL_HRDS:
 49            ffStrbufSetStatic(protocol, "802.11b");
 50            break;
 51        case WL_ERP:
 52            ffStrbufSetStatic(protocol, htEnabled ? "802.11n (Wi-Fi 4)" : "802.11g");
 53            break;
 54        default:
 55            break;
 56    }
 57}
 58
 59static void setWifiSecurity(FFstrbuf* security, uint32_t encryption, bool haveAuthMode, uint32_t authMode) {
 60    switch (encryption) {
 61        case WL_NOENCRYPTION:
 62            ffStrbufSetStatic(security, "Insecure");
 63            break;
 64        case WL_ENC_WEP:
 65            ffStrbufSetStatic(security, "WEP");
 66            break;
 67        case WL_ENC_WPA:
 68            ffStrbufSetStatic(security, haveAuthMode && authMode == WL_SHAREDKEY ? "WPA Shared Key" : "WPA");
 69            break;
 70        default:
 71            ffStrbufSetStatic(security, "Unknown");
 72            break;
 73    }
 74}
 75
 76const char* ffDetectWifi(FFlist* result) {
 77    // https://github.com/illumos/illumos-gate/blob/master/usr/src/cmd/cmd-inet/usr.sbin/wificonfig/wificonfig.c
 78
 79    FF_AUTO_CLOSE_DIR DIR* directory = opendir("/dev/wifi");
 80    if (!directory) {
 81        return nullptr;
 82    }
 83
 84    FF_AUTO_FREE void* bufferMemory = malloc(MAX_BUF_LEN);
 85    if (!bufferMemory) {
 86        FF_DEBUG("malloc(MAX_BUF_LEN) failed");
 87        return "malloc() failed";
 88    }
 89    wldp_t* buffer = (wldp_t*) bufferMemory;
 90
 91    struct dirent* entry;
 92    while ((entry = readdir(directory)) != nullptr) {
 93        size_t nameLength = strlen(entry->d_name);
 94        if (nameLength == 0 || entry->d_name[nameLength - 1] < '0' || entry->d_name[nameLength - 1] > '9') {
 95            continue;
 96        }
 97
 98        char devicePath[PATH_MAX];
 99        int pathLength = snprintf(devicePath, sizeof(devicePath), "/dev/wifi/%s", entry->d_name);
100        if (pathLength < 0 || (size_t) pathLength >= sizeof(devicePath)) {
101            continue;
102        }
103
104        FF_AUTO_CLOSE_FD int fd = open(devicePath, O_RDWR | O_CLOEXEC);
105        if (fd < 0) {
106            continue;
107        }
108        if (!isastream(fd)) {
109            continue;
110        }
111
112        FFWifiResult* item = FF_LIST_ADD(FFWifiResult, *result);
113        ffStrbufInitS(&item->inf.description, entry->d_name);
114        ffStrbufInit(&item->inf.status);
115        ffStrbufInit(&item->conn.status);
116        ffStrbufInit(&item->conn.ssid);
117        ffStrbufInit(&item->conn.bssid);
118        ffStrbufInit(&item->conn.protocol);
119        ffStrbufInit(&item->conn.security);
120        item->conn.signalQuality = -DBL_MAX;
121        item->conn.rxRate = -DBL_MAX;
122        item->conn.txRate = -DBL_MAX;
123        item->conn.channel = 0;
124        item->conn.channelWidth = 0;
125        item->conn.frequency = 0;
126
127        wl_radio_t radio;
128        if (getWifiValue(fd, WL_RADIO, &radio, sizeof(radio), buffer)) {
129            ffStrbufSetStatic(&item->inf.status, radio ? "Up" : "Down");
130        } else {
131            ffStrbufSetStatic(&item->inf.status, "Unknown");
132        }
133
134        wl_linkstatus_t linkStatus;
135        if (!getWifiValue(fd, WL_LINKSTATUS, &linkStatus, sizeof(linkStatus), buffer)) {
136            ffStrbufSetStatic(&item->conn.status, "Unknown");
137            continue;
138        }
139        if (linkStatus != WL_CONNECTED) {
140            ffStrbufSetStatic(&item->conn.status, "Not connected");
141            continue;
142        }
143        ffStrbufSetStatic(&item->conn.status, "Connected");
144
145        wl_essid_t essid;
146        if (getWifiValue(fd, WL_ESSID, &essid, sizeof(essid), buffer) && essid.wl_essid_length > 0 && essid.wl_essid_length < sizeof(essid.wl_essid_essid) && essid.wl_essid_length <= MAX_ESSID_LENGTH - 1) {
147            ffStrbufSetNS(&item->conn.ssid, essid.wl_essid_length, essid.wl_essid_essid);
148        }
149
150        wl_bssid_t bssid;
151        if (getWifiValue(fd, WL_BSSID, bssid, sizeof(bssid), buffer)) {
152            ffStrbufSetF(&item->conn.bssid, "%02X:%02X:%02X:%02X:%02X:%02X", (uint8_t) bssid[0], (uint8_t) bssid[1], (uint8_t) bssid[2], (uint8_t) bssid[3], (uint8_t) bssid[4], (uint8_t) bssid[5]);
153        }
154
155        wl_rssi_t rssi;
156        if (getWifiValue(fd, WL_RSSI, &rssi, sizeof(rssi), buffer)) {
157            item->conn.signalQuality = rssi >= MAX_RSSI ? 100.0 : ((double) rssi / MAX_RSSI) * 100.0;
158        }
159
160        wl_phy_conf_t phy;
161        if (getWifiValue(fd, WL_PHY_CONFIG, &phy, sizeof(phy), buffer)) {
162            uint32_t subtype = phy.wl_phy_dsss_conf.wl_dsss_subtype;
163            switch (subtype) {
164                case WL_FHSS:
165                    item->conn.channel = (uint16_t) phy.wl_phy_fhss_conf.wl_fhss_channel;
166                    setWifiProtocol(&item->conn.protocol, subtype, false);
167                    break;
168                case WL_DSSS:
169                    item->conn.channel = (uint16_t) phy.wl_phy_dsss_conf.wl_dsss_channel;
170                    setWifiProtocol(&item->conn.protocol, subtype, false);
171                    break;
172                case WL_OFDM:
173                    item->conn.frequency = (uint16_t) phy.wl_phy_ofdm_conf.wl_ofdm_frequency;
174                    item->conn.channel = ffWifiFreqToChannel(item->conn.frequency);
175                    setWifiProtocol(&item->conn.protocol, subtype, phy.wl_phy_ofdm_conf.wl_ofdm_ht_enabled);
176                    break;
177                case WL_ERP:
178                    item->conn.channel = (uint16_t) phy.wl_phy_erp_conf.wl_erp_channel;
179                    setWifiProtocol(&item->conn.protocol, subtype, phy.wl_phy_erp_conf.wl_erp_ht_enabled);
180                    break;
181                default:
182                    setWifiProtocol(&item->conn.protocol, subtype, false);
183                    break;
184            }
185        }
186
187        wl_encryption_t encryption = 0;
188        wl_authmode_t authMode = 0;
189        bool haveEncryption = getWifiValue(fd, WL_ENCRYPTION, &encryption, sizeof(encryption), buffer);
190        bool haveAuthMode = getWifiValue(fd, WL_AUTH_MODE, &authMode, sizeof(authMode), buffer);
191        if (haveEncryption) {
192            setWifiSecurity(&item->conn.security, encryption, haveAuthMode, authMode);
193        }
194    }
195
196    return nullptr;
197}