Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support to check if SSID is connected #37

Merged
merged 1 commit into from
Jul 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
}
}
}