Skip to content

Commit

Permalink
Added support to detect if the wifi is connected to a given network.
Browse files Browse the repository at this point in the history
Added Wi-Fi details when pressing Options and Wi-Fi icon.
- still missing getting ip address, router, internet reachability, security and country code on the connected network
- added disconnect ssid however it does nothing as of now.

Fixed issue with local IP address and router IP address not showing properly
- moved code in Api.c

Added support for reachability to detect if a wireless connection can connect
- added placeholder for wifi channel width
- fixed a typo for Tx Rate

Replaced custom bandwidth to itlwm's api
- Added disassociate button from itlwm's api

Improvements on local address

Improvements getting router ip address
- using scutil instead of netstat and ipconfig, reduces parsing strings

removed unused function runCommand

Removed unnecessary negative sign from rssi and noise due to fixes in itlwm. OpenIntelWireless/itlwm@dd4bec0

Updated rssi and noise values to match itlwm.kext api OpenIntelWireless/itlwm@dd4bec0
- Hidden Security and country code items since they have not been implemented so this pull request can be merged.
  • Loading branch information
ErrorErrorError committed Jul 5, 2020
1 parent 19c0386 commit f5db547
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 7 deletions.
9 changes: 9 additions & 0 deletions ClientKit/Api.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,19 @@ bool get_network_list(network_info_list_t *list) {
struct ioctl_scan scan;
struct ioctl_network_info network_info_ret;
io_connect_t con;
struct ioctl_sta_info sta_info;
char *current_ssid = (char *)"";
uint32_t state;
scan.version = IOCTL_VERSION;
if (ioctl_set(IOCTL_80211_SCAN, &scan, sizeof(struct ioctl_scan)) != KERN_SUCCESS) {
goto error;
}
sleep(3);
if (get_80211_state(&state) && state == ITL80211_S_RUN) {
if (get_station_info(&sta_info) == KERN_SUCCESS) {
current_ssid = (char *)sta_info.ssid;
}
}
if (!open_adapter(&con)) {
goto error;
}
Expand All @@ -88,6 +96,7 @@ bool get_network_list(network_info_list_t *list) {
// TODO: set security
// info->auth.security = network_info_ret.ni_rsncipher;
info->auth.security = ITL80211_CIPHER_CCMP;
info->is_connected = strcmp(current_ssid, (char *) &network_info_ret.ssid) == 0;
}
close_adapter(con);
return true;
Expand Down
4 changes: 2 additions & 2 deletions Common/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ struct ioctl_sta_info {
int cur_mcs;
uint channel;
uint16_t band_width;//20 40 80 160
uint rssi;
uint noise;
int16_t rssi;
int16_t noise;
uint rate;
unsigned char ssid[NWID_LEN];
uint8_t bssid[ETHER_ADDR_LEN];
Expand Down
119 changes: 114 additions & 5 deletions HeliPort/Appearance/StatusMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ final class StatusMenu: NSMenu, NSMenuDelegate {
for idx in 1...2 {
items[items.count - idx].isHidden = !visible
}
for idx in 11...23 {
// Hide security and country code since those have not been implemented in io_station_info
if idx == 15 || idx == 18 {
items[idx].isHidden = true
continue
}
items[idx].isHidden = !(visible && status == ITL80211_S_RUN)
}
}
}

Expand Down Expand Up @@ -109,15 +117,32 @@ final class StatusMenu: NSMenu, NSMenuDelegate {
private let macItem = NSMenuItem(title: NSLocalizedString("Address: ", comment: "") + "(null)")
private let itlwmVerItem = NSMenuItem(title: NSLocalizedString("Version: ", comment: "") + "(null)")

// MARK: - WiFi connected items
let disconnectItem = NSMenuItem(
title: NSLocalizedString("Disconnect from: ", comment: "") + "(null)",
action: #selector(disassociateSSID(_:)))
private let ipAddresssItem = NSMenuItem(title: NSLocalizedString(" IP Address: ", comment: "") + "(null)")
private let routerItem = NSMenuItem(title: NSLocalizedString(" Router: ", comment: "") + "(null)")
private let internetItem = NSMenuItem(title: NSLocalizedString(" Internet: ", comment: "") + "(null)")
private let securityItem = NSMenuItem(title: NSLocalizedString(" Security: ", comment: "") + "(null)")
private let bssidItem = NSMenuItem(title: NSLocalizedString(" BSSID: ", comment: "") + "(null)")
private let channelItem = NSMenuItem(title: NSLocalizedString(" Channel: ", comment: "") + "(null)")
private let countryCodeItem = NSMenuItem(title: NSLocalizedString(" Country Code: ", comment: "") + "(null)")
private let rssiItem = NSMenuItem(title: NSLocalizedString(" RSSI: ", comment: "") + "(null)")
private let noiseItem = NSMenuItem(title: NSLocalizedString(" Noise: ", comment: "") + "(null)")
private let txRateItem = NSMenuItem(title: NSLocalizedString(" Tx Rate: ", comment: "") + "(null)")
private let phyModeItem = NSMenuItem(title: NSLocalizedString(" PHY Mode: ", comment: "") + "(null)")
private let mcsIndexItem = NSMenuItem(title: NSLocalizedString(" MCS Index: ", comment: "") + "(null)")

// - MARK: Init

init() {
super.init(title: "")
minimumWidth = CGFloat(285.0)
delegate = self
setupMenuHeaderAndFooter()
updateNetworkList()
getDeviceInfo()
updateNetworkList()

DispatchQueue.global(qos: .default).async {
self.statusUpdateTimer = Timer.scheduledTimer(
Expand Down Expand Up @@ -157,10 +182,25 @@ final class StatusMenu: NSMenu, NSMenuDelegate {

headerLength = items.count

for _ in 1...maxNetworkListLength {
for _ in 0..<maxNetworkListLength {
networkItemList.append(addNetworkItemPlaceholder())
}

insertItem(disconnectItem, at: headerLength + 1)
disconnectItem.target = self
insertItem(ipAddresssItem, at: headerLength + 2)
insertItem(routerItem, at: headerLength + 3)
insertItem(internetItem, at: headerLength + 4)
insertItem(securityItem, at: headerLength + 5)
insertItem(bssidItem, at: headerLength + 6)
insertItem(channelItem, at: headerLength + 7)
insertItem(countryCodeItem, at: headerLength + 8)
insertItem(rssiItem, at: headerLength + 9)
insertItem(noiseItem, at: headerLength + 10)
insertItem(txRateItem, at: headerLength + 11)
insertItem(phyModeItem, at: headerLength + 12)
insertItem(mcsIndexItem, at: headerLength + 13)

addItem(networkItemListSeparator)

addClickItem(title: NSLocalizedString("Join Other Network...", comment: ""))
Expand Down Expand Up @@ -326,9 +366,68 @@ final class StatusMenu: NSMenu, NSMenuDelegate {
}

DispatchQueue.global(qos: .background).async {
var info = station_info_t()
get_station_info(&info)
Log.debug(String(format: "current rate=%03d", info.rate))
var disconnectName = NSLocalizedString("Unavailable", comment: "")
var ipAddr = NSLocalizedString("Unavailable", comment: "")
var routerAddr = NSLocalizedString("Unavailable", comment: "")
var internet = NSLocalizedString("Unavailable", comment: "")
var security = NSLocalizedString("Unavailable", comment: "")
var bssid = NSLocalizedString("Unavailable", comment: "")
var channel = NSLocalizedString("Unavailable", comment: "")
var countryCode = NSLocalizedString("Unavailable", comment: "")
var rssi = NSLocalizedString("Unavailable", comment: "")
var noise = NSLocalizedString("Unavailable", comment: "")
var txRate = NSLocalizedString("Unavailable", comment: "")
var phyMode = NSLocalizedString("Unavailable", comment: "")
var mcsIndex = NSLocalizedString("Unavailable", comment: "")
var staInfo = station_info_t()
if self.status == ITL80211_S_RUN && get_station_info(&staInfo) == KERN_SUCCESS {
let bsd = String(self.bsdItem.title)
.replacingOccurrences(of: NSLocalizedString("Interface Name: ", comment: ""),
with: "",
options: .regularExpression,
range: nil)
let ipAddress = NetworkManager.getLocalAddress(bsd: bsd)
let routerAddress = NetworkManager.getRouterAddress(bsd: bsd)
let isReachable = NetworkManager.checkConnectionReachability(station: staInfo)
Log.debug(String(format: "current rate=%03d", staInfo.rate))
disconnectName = String(cString: &staInfo.ssid.0)
ipAddr = ipAddress ?? NSLocalizedString("Unknown", comment: "")
routerAddr = routerAddress ?? NSLocalizedString("Unknown", comment: "")
internet = NSLocalizedString(isReachable ? "Reachable" : "Unreachable", comment: "")
security = NSLocalizedString("Unknown", comment: "")
bssid = String(format: "%02x:%02x:%02x:%02x:%02x:%02x",
staInfo.bssid.0,
staInfo.bssid.1,
staInfo.bssid.2,
staInfo.bssid.3,
staInfo.bssid.4,
staInfo.bssid.5
)
channel = String(staInfo.channel) + " (" +
(staInfo.channel <= 14 ? "2.4 GHz" : "5 GHz") + ", " +
"\(staInfo.band_width) MHz)"
countryCode = "Unknown"
rssi = String(staInfo.rssi) + " dBm"
noise = String(staInfo.noise) + " dBm"
txRate = String(staInfo.rate) + " Mbps"
phyMode = staInfo.op_mode.description
mcsIndex = String(staInfo.cur_mcs)
}
DispatchQueue.main.async {
self.disconnectItem.title = NSLocalizedString("Disconnect from: ", comment: "") + disconnectName
self.ipAddresssItem.title = NSLocalizedString(" IP Address: ", comment: "") + ipAddr
self.routerItem.title = NSLocalizedString(" Router: ", comment: "") + routerAddr
self.internetItem.title = NSLocalizedString(" Internet: ", comment: "") + internet
self.securityItem.title = NSLocalizedString(" Security: ", comment: "") + security
self.bssidItem.title = NSLocalizedString(" BSSID: ", comment: "") + bssid
self.channelItem.title = NSLocalizedString(" Channel: ", comment: "") + channel
self.countryCodeItem.title = NSLocalizedString(" Country Code: ", comment: "") + countryCode
self.rssiItem.title = NSLocalizedString(" RSSI: ", comment: "") + rssi
self.noiseItem.title = NSLocalizedString(" Noise: ", comment: "") + noise
self.txRateItem.title = NSLocalizedString(" Tx Rate: ", comment: "") + txRate
self.phyModeItem.title = NSLocalizedString(" PHY Mode: ", comment: "") + phyMode
self.mcsIndexItem.title = NSLocalizedString(" MCS Index: ", comment: "") + mcsIndex
}
}
}

Expand All @@ -348,4 +447,14 @@ final class StatusMenu: NSMenu, NSMenuDelegate {
}
}
}

@objc func disassociateSSID(_ sender: NSMenuItem) {
let ssid = String(sender.title)
.replacingOccurrences(of: NSLocalizedString("Disconnect from: ", comment: ""), with: "",
options: .regularExpression,
range: nil
)
dis_associate_ssid(ssid)
print("disconnected from \(ssid)")
}
}
105 changes: 105 additions & 0 deletions HeliPort/NetworkInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import Foundation
import Cocoa
import SystemConfiguration

class NetworkInfo {
var ssid: String = ""
Expand Down Expand Up @@ -206,6 +207,89 @@ class NetworkManager {
let addressBytes = macAddressData.map { String(format: "%02x", $0) }
return addressBytes.joined(separator: separator)
}

class func checkConnectionReachability(station: station_info_t) -> Bool {
guard let reachability = SCNetworkReachabilityCreateWithName(nil, "www.apple.com") else {
return false
}
var address = sockaddr_in()
address.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
address.sin_family = sa_family_t(AF_INET)

var flags = SCNetworkReachabilityFlags()
SCNetworkReachabilityGetFlags(reachability, &flags)

let isReachable: Bool = flags.contains(.reachable)
let needsConnection = flags.contains(.connectionRequired)
let canConnectAutomatically = flags.contains(.connectionOnDemand) || flags.contains(.connectionOnTraffic)
let canConnectWithoutUserInteraction = canConnectAutomatically && !flags.contains(.interventionRequired)
return isReachable && (!needsConnection || canConnectWithoutUserInteraction)
}

class func getRouterAddress(bsd: String) -> String? {
let dynamicCreate = SCDynamicStoreCreate(kCFAllocatorDefault, "router-ip" as CFString, nil, nil)
let keyIPv4 = "State:/Network/Global/IPv4" as CFString
let keyIPv6 = "State:/Network/Global/IPv6" as CFString
var dictionary: CFPropertyList?
if let ipV4Info = SCDynamicStoreCopyValue(dynamicCreate, keyIPv4) {
dictionary = ipV4Info
} else if let ipV6Info = SCDynamicStoreCopyValue(dynamicCreate, keyIPv6) {
dictionary = ipV6Info
}
if let interface = dictionary?[kSCDynamicStorePropNetPrimaryInterface] as? String {
if interface == bsd {
print("Interface found: \(interface == bsd)")
if let ipRouterAddr = dictionary?["Router"] as? String {
return ipRouterAddr
} else {
print("Could not find router ip")
}
} else {
print("Could not find interface")
}
}
return nil
}

// from https://stackoverflow.com/questions/30748480/swift-get-devices-wifi-ip-address/30754194#30754194
class func getLocalAddress(bsd: String) -> String? {
// Get list of all interfaces on the local machine:
var ifaddr: UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return nil }
guard let firstAddr = ifaddr else { return nil }
var ipV4: String?
var ipV6: String?
// For each interface ...
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee
// Check for IPv4 or IPv6 interface:
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
// Check interface name:
let name = String(cString: interface.ifa_name)
if name == bsd {
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST)
if addrFamily == UInt8(AF_INET) {
ipV4 = String(cString: hostname)
} else if addrFamily == UInt8(AF_INET6) {
ipV6 = String(cString: hostname)
}
}
}
}
freeifaddrs(ifaddr)
if ipV4 != nil {
return ipV4
} else if ipV6 != nil {
return ipV6
} else {
return nil
}
}
}

extension NetworkInfo: Hashable {
Expand All @@ -217,3 +301,24 @@ extension NetworkInfo: Hashable {
hasher.combine(ssid)
}
}

extension itl_phy_mode: CustomStringConvertible {
public var description: String {
switch self {
case ITL80211_MODE_11A:
return "802.11a"
case ITL80211_MODE_11B:
return "802.11b"
case ITL80211_MODE_11G:
return "802.11g"
case ITL80211_MODE_11N :
return "802.11n"
case ITL80211_MODE_11AC:
return "802.11ac"
case ITL80211_MODE_11AX:
return "802.11ax"
default:
return "Unknown"
}
}
}

0 comments on commit f5db547

Please sign in to comment.