|  | 
| 1 | 1 | #include "wifi.h" | 
| 2 |  | -#include "common/processing.h" | 
| 3 |  | -#include "common/properties.h" | 
|  | 2 | +#include "common/io/io.h" | 
| 4 | 3 | #include "util/stringUtils.h" | 
| 5 | 4 | 
 | 
| 6 |  | -#include <net/if.h> | 
| 7 | 5 | #include <stdio.h> | 
| 8 | 6 | #include <string.h> | 
|  | 7 | +#include <stdlib.h> | 
|  | 8 | +#include <sys/ioctl.h> | 
|  | 9 | +#include <sys/socket.h> | 
|  | 10 | +#include <net/if.h> | 
|  | 11 | +#include <net/if_media.h> | 
|  | 12 | +#include <net80211/ieee80211_ioctl.h> | 
|  | 13 | +#include <unistd.h> | 
| 9 | 14 | 
 | 
| 10 | 15 | const char* ffDetectWifi(FFlist* result) | 
| 11 | 16 | { | 
| 12 | 17 |     struct if_nameindex* infs = if_nameindex(); | 
| 13 |  | -    if(!infs) | 
|  | 18 | +    if(!infs) { | 
| 14 | 19 |         return "if_nameindex() failed"; | 
|  | 20 | +    } | 
|  | 21 | + | 
|  | 22 | +    FF_AUTO_CLOSE_FD int sock = socket(AF_INET, SOCK_DGRAM, 0); | 
|  | 23 | +    if(sock < 0) { | 
|  | 24 | +        return "socket() failed"; | 
|  | 25 | +    } | 
| 15 | 26 | 
 | 
| 16 | 27 |     for(struct if_nameindex* i = infs; !(i->if_index == 0 && i->if_name == NULL); ++i) | 
| 17 | 28 |     { | 
| 18 |  | -        if (!ffStrStartsWith(i->if_name, "wlan")) continue; | 
| 19 |  | -        FF_STRBUF_AUTO_DESTROY ifconfig = ffStrbufCreate(); | 
| 20 |  | -        if (ffProcessAppendStdOut(&ifconfig, (char* const[]) { | 
| 21 |  | -            "ifconfig", | 
| 22 |  | -            i->if_name, | 
| 23 |  | -            NULL | 
| 24 |  | -        }) == NULL) | 
| 25 |  | -        { | 
| 26 |  | -            FFWifiResult* item = (FFWifiResult*) ffListAdd(result); | 
| 27 |  | -            ffStrbufInitS(&item->inf.description, i->if_name); | 
| 28 |  | -            ffStrbufInit(&item->inf.status); | 
| 29 |  | -            ffStrbufInit(&item->conn.status); | 
| 30 |  | -            ffStrbufInit(&item->conn.ssid); | 
| 31 |  | -            ffStrbufInit(&item->conn.bssid); | 
| 32 |  | -            ffStrbufInit(&item->conn.protocol); | 
| 33 |  | -            ffStrbufInit(&item->conn.security); | 
| 34 |  | -            item->conn.signalQuality = 0.0/0.0; | 
| 35 |  | -            item->conn.rxRate = 0.0/0.0; | 
| 36 |  | -            item->conn.txRate = 0.0/0.0; | 
| 37 |  | -            item->conn.channel = 0; | 
| 38 |  | -            item->conn.frequency = 0; | 
| 39 |  | - | 
| 40 |  | -            ffParsePropLines(ifconfig.chars, "status: ", &item->conn.status); | 
| 41 |  | -            if (!ffStrbufEqualS(&item->conn.status, "associated")) | 
| 42 |  | -                continue; | 
| 43 |  | - | 
| 44 |  | -            ffParsePropLines(ifconfig.chars, "ssid ", &item->conn.ssid); | 
| 45 |  | -            if (item->conn.ssid.length) | 
| 46 |  | -            { | 
| 47 |  | -                // This doesn't work for quoted SSID values | 
| 48 |  | -                uint32_t idx = ffStrbufFirstIndexS(&item->conn.ssid, " bssid "); | 
| 49 |  | -                if (idx < item->conn.ssid.length) | 
| 50 |  | -                { | 
| 51 |  | -                    ffStrbufSetS(&item->conn.bssid, item->conn.ssid.chars + idx + (uint32_t) strlen(" bssid ")); | 
| 52 |  | -                    ffStrbufSubstrBefore(&item->conn.ssid, idx); | 
| 53 |  | -                } | 
| 54 |  | - | 
| 55 |  | -                idx = ffStrbufFirstIndexS(&item->conn.ssid, " channel "); | 
| 56 |  | -                if (idx < item->conn.ssid.length) | 
| 57 |  | -                { | 
| 58 |  | -                    const char* pchannel = item->conn.ssid.chars + idx + strlen(" channel "); | 
| 59 |  | -                    sscanf(pchannel, "%hu (%hu MHz %*s)", &item->conn.channel, &item->conn.frequency); | 
| 60 |  | -                } | 
| 61 |  | - | 
| 62 |  | -                ffStrbufSubstrBefore(&item->conn.ssid, idx); | 
|  | 29 | +        if (!ffStrStartsWith(i->if_name, "wlan")) { | 
|  | 30 | +            continue; | 
|  | 31 | +        } | 
|  | 32 | + | 
|  | 33 | +        FFWifiResult* item = (FFWifiResult*) ffListAdd(result); | 
|  | 34 | +        ffStrbufInitS(&item->inf.description, i->if_name); | 
|  | 35 | +        ffStrbufInit(&item->inf.status); | 
|  | 36 | +        ffStrbufInit(&item->conn.status); | 
|  | 37 | +        ffStrbufInit(&item->conn.ssid); | 
|  | 38 | +        ffStrbufInit(&item->conn.bssid); | 
|  | 39 | +        ffStrbufInit(&item->conn.protocol); | 
|  | 40 | +        ffStrbufInit(&item->conn.security); | 
|  | 41 | +        item->conn.signalQuality = 0.0/0.0; | 
|  | 42 | +        item->conn.rxRate = 0.0/0.0; | 
|  | 43 | +        item->conn.txRate = 0.0/0.0; | 
|  | 44 | +        item->conn.channel = 0; | 
|  | 45 | +        item->conn.frequency = 0; | 
|  | 46 | + | 
|  | 47 | +        char ssid[IEEE80211_NWID_LEN + 1] = {}; | 
|  | 48 | +        struct ieee80211req ireq = {}; | 
|  | 49 | +        strlcpy(ireq.i_name, i->if_name, sizeof(ireq.i_name)); | 
|  | 50 | +        ireq.i_type = IEEE80211_IOC_SSID; | 
|  | 51 | +        ireq.i_data = ssid; | 
|  | 52 | +        ireq.i_len = sizeof(ssid) - 1; | 
|  | 53 | + | 
|  | 54 | +        if (ioctl(sock, SIOCG80211, &ireq) < 0 || ireq.i_len == 0) { | 
|  | 55 | +            struct ifreq ifr; | 
|  | 56 | +            strlcpy(ifr.ifr_name, i->if_name, sizeof(ifr.ifr_name)); | 
|  | 57 | +            if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) { | 
|  | 58 | +                ffStrbufSetStatic(&item->inf.status, "Unknown"); | 
|  | 59 | +            } else { | 
|  | 60 | +                ffStrbufSetStatic(&item->inf.status, ifr.ifr_flags & IFF_UP ? "Up" : "Down"); | 
|  | 61 | +            } | 
|  | 62 | +            ffStrbufAppendS(&item->conn.status, "Not associated"); | 
|  | 63 | +            continue; | 
|  | 64 | +        } | 
|  | 65 | + | 
|  | 66 | +        ffStrbufSetStatic(&item->inf.status, "Up"); | 
|  | 67 | +        ffStrbufSetStatic(&item->conn.status, "Associated"); | 
|  | 68 | +        ffStrbufAppendNS(&item->conn.ssid, ireq.i_len, ssid); | 
|  | 69 | + | 
|  | 70 | +        uint8_t bssid[IEEE80211_ADDR_LEN] = {}; | 
|  | 71 | +        ireq.i_type = IEEE80211_IOC_BSSID; | 
|  | 72 | +        ireq.i_data = bssid; | 
|  | 73 | +        ireq.i_len = sizeof(bssid); | 
|  | 74 | + | 
|  | 75 | +        if (ioctl(sock, SIOCG80211, &ireq) >= 0) { | 
|  | 76 | +            ffStrbufSetF(&item->conn.bssid, "%02X:%02X:%02X:%02X:%02X:%02X", | 
|  | 77 | +                         bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); | 
|  | 78 | +        } | 
|  | 79 | + | 
|  | 80 | +        struct ieee80211_channel curchan = {}; | 
|  | 81 | +        ireq.i_type = IEEE80211_IOC_CURCHAN; | 
|  | 82 | +        ireq.i_data = &curchan; | 
|  | 83 | +        ireq.i_len = sizeof(curchan); | 
|  | 84 | + | 
|  | 85 | +        if (ioctl(sock, SIOCG80211, &ireq) >= 0) { | 
|  | 86 | +            item->conn.channel = curchan.ic_ieee; | 
|  | 87 | +            item->conn.frequency = curchan.ic_freq; | 
|  | 88 | + | 
|  | 89 | +            if (IEEE80211_IS_CHAN_FHSS(&curchan)) | 
|  | 90 | +                ffStrbufSetStatic(&item->conn.protocol, "802.11 (FHSS)"); | 
|  | 91 | +            if (IEEE80211_IS_CHAN_A(&curchan)) | 
|  | 92 | +                ffStrbufSetStatic(&item->conn.protocol, "802.11a"); | 
|  | 93 | +            if (IEEE80211_IS_CHAN_B(&curchan)) | 
|  | 94 | +                ffStrbufSetStatic(&item->conn.protocol, "802.11b"); | 
|  | 95 | +            if (IEEE80211_IS_CHAN_ANYG(&curchan)) | 
|  | 96 | +                ffStrbufSetStatic(&item->conn.protocol, "802.11g"); | 
|  | 97 | +            if (IEEE80211_IS_CHAN_HT(&curchan)) | 
|  | 98 | +                ffStrbufSetStatic(&item->conn.protocol, "802.11n (Wi-Fi 4)"); | 
|  | 99 | +            if (IEEE80211_IS_CHAN_VHT(&curchan)) | 
|  | 100 | +                ffStrbufSetStatic(&item->conn.protocol, "802.11ac (Wi-Fi 5)"); | 
|  | 101 | +        } | 
|  | 102 | + | 
|  | 103 | +        union { | 
|  | 104 | +            struct ieee80211req_sta_req req; | 
|  | 105 | +            uint8_t buf[1024]; | 
|  | 106 | +        } stareq = {}; | 
|  | 107 | +        memcpy(stareq.req.is_u.macaddr, bssid, sizeof(bssid)); | 
|  | 108 | +        ireq.i_type = IEEE80211_IOC_STA_INFO; | 
|  | 109 | +        ireq.i_data = &stareq; | 
|  | 110 | +        ireq.i_len = sizeof(stareq); | 
|  | 111 | + | 
|  | 112 | +        if (ioctl(sock, SIOCG80211, &ireq) >= 0) { | 
|  | 113 | +            struct ieee80211req_sta_info* sta = stareq.req.info; | 
|  | 114 | +            if (sta->isi_len != 0) { | 
|  | 115 | +                item->conn.signalQuality = (sta->isi_rssi >= -50 ? 100 : sta->isi_rssi <= -100 ? 0 : (sta->isi_rssi + 100) * 2); | 
|  | 116 | +                item->conn.rxRate = sta->isi_txmbps * 0.5; | 
| 63 | 117 |             } | 
|  | 118 | +        } | 
| 64 | 119 | 
 | 
| 65 |  | -            ffParsePropLines(ifconfig.chars, "media: ", &item->conn.protocol); | 
| 66 |  | -            if (item->conn.protocol.length) | 
| 67 |  | -            { | 
| 68 |  | -                uint32_t index = ffStrbufFirstIndexS(&item->conn.protocol, " mode "); | 
| 69 |  | -                if (index == item->conn.protocol.length) | 
| 70 |  | -                    ffStrbufClear(&item->conn.protocol); | 
| 71 |  | -                else | 
| 72 |  | -                { | 
| 73 |  | -                    ffStrbufSubstrAfter(&item->conn.protocol, index + strlen(" mode ") - 1); | 
| 74 |  | -                    ffStrbufPrependS(&item->conn.protocol, "802."); | 
| 75 |  | -                } | 
|  | 120 | +        ireq.i_type = IEEE80211_IOC_AUTHMODE; | 
|  | 121 | +        ireq.i_data = NULL; | 
|  | 122 | +        ireq.i_len = 0; | 
|  | 123 | +        if (ioctl(sock, SIOCG80211, &ireq) >= 0) { | 
|  | 124 | +            switch (ireq.i_val) { | 
|  | 125 | +            case IEEE80211_AUTH_NONE: | 
|  | 126 | +                ffStrbufSetStatic(&item->conn.security, "Insecure"); | 
|  | 127 | +                break; | 
|  | 128 | +            case IEEE80211_AUTH_OPEN: | 
|  | 129 | +                ffStrbufSetStatic(&item->conn.security, "Open"); | 
|  | 130 | +                break; | 
|  | 131 | +            case IEEE80211_AUTH_SHARED: | 
|  | 132 | +                ffStrbufSetStatic(&item->conn.security, "Shared"); | 
|  | 133 | +                break; | 
|  | 134 | +            case IEEE80211_AUTH_8021X: | 
|  | 135 | +                ffStrbufSetStatic(&item->conn.security, "8021X"); | 
|  | 136 | +                break; | 
|  | 137 | +            case IEEE80211_AUTH_AUTO: | 
|  | 138 | +                ffStrbufSetStatic(&item->conn.security, "Auto"); | 
|  | 139 | +                break; | 
|  | 140 | +            case IEEE80211_AUTH_WPA: | 
|  | 141 | +                ffStrbufSetStatic(&item->conn.security, "WPA"); | 
|  | 142 | +                break; | 
|  | 143 | +            default: | 
|  | 144 | +                ffStrbufSetF(&item->conn.security, "Unknown (%d)", ireq.i_val); | 
|  | 145 | +                break; | 
| 76 | 146 |             } | 
| 77 | 147 |         } | 
| 78 | 148 |     } | 
| 79 | 149 | 
 | 
|  | 150 | +    if_freenameindex(infs); | 
| 80 | 151 |     return NULL; | 
| 81 | 152 | } | 
0 commit comments