Wi-Fi is way more complex than you might think. This post attempts to explain some of that complexity, and how that affects the design of your network apps.
Note I’m not a Wi-Fi expert. All of the following is the result of hard-won experience gained while investigating various oddball Wi-Fi problems. As a result it’s a vast simplification of how things really work. If you actually get to talk to a Wi-Fi expert, they’ll be happy to explain to you how Wi-Fi is even more complex than what I’ve explain below.
Terminology
As this post is going to talk about the fundamentals of Wi-Fi, I’m going to use Wi-Fi technical terms. Specifically:
STA (station) — This is a Wi-Fi ‘client’ device.
AP (access point) — This is the hardware running a single Wi-Fi network. The definition of Wi-Fi network is more complex than you might think, as I’ll explain next.
SSID (Service Set Identifier) — This is what most folks think of as the Wi-Fi network. It’s the user-visible network identifier string that you see throughout the system.
BSSID (Basic Service Set Identifier) — This defines a single Wi-Fi network at the Wi-Fi level. It’s identified by the MAC address - https://en.wikipedia.org/wiki/MAC_address of the AP, something that’s generally not user visible.
In a typical home Wi-Fi network there’s a one-to-one relationship between SSID and BSSID. This is not true in more complex Wi-Fi setups. For example, in my home I have an Ethernet backbone with multiple APs bridged on to that backbone. Each AP has a different BSSID, but they all share the same SSID so that STAs can roam between APs without disrupting their network.
This sort of setup is very common in enterprise environments.
I also use various terms that are less widely accepted but are, nevertheless, important when discussing common scenarios:
Wi-Fi hotspot — This is a Wi-Fi network where the user must interact with the network to gain access to the wider Internet (1).
Wi-Fi accessory — This is an accessory which communicates over Wi-Fi. I use accessory in favour of device because, when working in the Apple ecosystem, device refers to your iOS device.
Finally, I don’t use the term ad-hoc Wi-Fi. In my experience this term is so heavily overloaded as to be meaningless. See the next section for more.
(1) Apple APIs are not as consistent about this as they should be. For example, the hotspot in NEHotspotHelper - https://developer.apple.com/documentation/networkextension/hotspot_helper is correct but the hotspot in NEHotspotConfigurationManager - https://developer.apple.com/documentation/networkextension/wi-fi_configuration is not (the API can be used to configure the device to join any Wi-Fi network, not just a Wi-Fi hotspot).
Ad-Hoc Wi-Fi
I don’t use the term ad-hoc Wi-Fi because, in my experience, this term means different things to different people:
Some folks interpret it to mean IBSS - https://en.wikipedia.org/wiki/Service_set_%28802.11_network%29#Independent.
Some folks interpret it to mean Wi-Fi Direct - https://en.wikipedia.org/wiki/Wi-Fi_Direct.
Some folks interpret it to mean Apple peer-to-peer Wi-Fi (aka AWDL or its predecessor). This is the mechanism used by Network framework when you set the includePeerToPeer - https://developer.apple.com/documentation/network/nwparameters/3020639-includepeertopeer flag, Multipeer Connectivity, and so on.
Some folks interpret it to mean an infrastructure Wi-Fi network that doesn’t lead to the wider Internet, for example, one published by a Wi-Fi accessory.
Given this confusion it’s best to avoid this term in favour something more specific.
Unicasts
Wi-Fi implements a link-level positive acknowledgement mechanism for unicast traffic. This is really important because the physical packet loss on a Wi-Fi network is pretty bad.
In Wi-Fi, all unicast traffic is from STA to AP or vice versa. This makes sense when you think about it. You can’t send from STA to STA because:
The STAs might be located such that each STA can see the AP but the STAs can’t see each other (for example, this might be a home network with the AP located in the middle of the home and the STAs located on the extremities)
The STAs might be talking to different APs (that is, they’re on different BSSIDs)
Wi-Fi unicast traffic is fast because the AP can set the speed of the link to be appropriate for the STA in question.
Some APs refuse to forward STA-to-STA traffic. This is most often seen with Wi-Fi hotspots, where the hotspot isolates each STA as a security measure (this is, IMO, security theatre - https://en.wikipedia.org/wiki/Security_theater but there you go).
Broadcasts
Note In this context, broadcasts also includes multicasts.
Wi-Fi broadcasts work very differently from Wi-Fi unicasts. In a broadcast, the STA sends the packet to the AP and the AP then transmits the broadcast and hopes that all the other STAs pick it up.
The AP does two things to help improve the chances that the STAs will pick up the broadcast:
It sends the broadcast at the lowest supported speed — This makes sense when you think that the AP might have a mix of STAs, some of which support high speed modes and some of which don’t.
It typically ramps up its transmission power.
These measures help, but they don’t guarantee that all the STAs will pick up the broadcast.
If the network has multiple APs, the AP will typically forward the broadcast to the other APs and they will also broadcast the packet. However, this does not always happen. Many organisations have large flat networks, and thus put a limit on Wi-Fi broadcasts to prevent the whole network being flooded with broadcasts. In fact, the AP might not even forward broadcasts from its own STAs (for example, a hotspot that implements STA isolation as I discussed earlier).
IMPORTANT When you’re designing a network protocol that will commonly run over Wi-Fi, you must take into account the peculiarities of Wi-Fi’s broadcast support. For example, if you’re only transmitting to a few peers (less than 10 say), it may be better to send a unicast to each peer rather than send a broadcast; the unicasts may be faster (because Wi-Fi will send each one at the highest speed supported by that peer) and will certainly be more reliable.
Power Managerment
A STA will often turn off its radio in order to save power. When this happens the STA sends the AP a packet telling it how long it’s going to have its radio off, and the AP buffers packets for that STA for the duration. Cool beans!
This feature is also used to support radio and antenna multiplexing. On iOS there are two scenarios where that’s necessary:
iOS devices commonly have a single antenna for Bluetooth and Wi-Fi, so the device must periodically turn off Wi-Fi so it can use the antenna for Bluetooth.
If the device has a single Wi-Fi radio (which is common), it may need to change the channel on that radio in order to deal with peer-to-peer Wi-Fi.
It should go without saying that, if the AP sends a broadcast while the STA isn’t listening, the STA won’t see that broadcast.
Examining Wi-Fi Mechanics
If you’re interested in seeing how Wi-Fi really works, you can take a Wi-Fi level packet trace using the instructions in Recording a Wi-Fi Packet Trace - https://developer.apple.com/documentation/network/recording_a_packet_trace/recording_a_wi-fi_packet_trace. This will show you STA-to-AP traffic, AP-to-STA traffic, link-level positive acknowledgement and retransmission, Wi-Fi power management, and so on.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"
Change history:
18 Apr 2016 — First posted.
1 Mar 2019 — Fix a link to QA1176, which is no more. Minor editorial changes.
11 May 2021 — Added the Ad-Hoc Wi-Fi section. Expanded the Terminology section. Minor editorial changes.
Core WLAN
RSS for tagProvide APIs for querying AirPort interfaces and choosing networks using Core WLAN.
Posts under Core WLAN tag
12 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
This post explains how to investigate network latency problems. It does not necessarily show how to fix the problem, but it describes techniques to find the problem and, from there, contemplate potential fixes.
A latency problem in the general case looks like this:
sending app receiving app
| |
libraries libraries
| |
kernel kernel
| |
network driver network driver
| |
+------ network ------+
The problem is that that the sending app sends a packet of data which is not received by the receiving app in a timely fashion. This discussion assumes that the sending and receiving apps are both running on Apple platforms (macOS, iOS, tvOS). If you’re using another platform, you’ll have to ask that platform vendor about equivalent techniques.
Note Apple platforms have a user-space networking stack that runs in parallel to the networking stack in the kernel. To simplify this discussion, I’m using the term kernel to encompass both stacks.
The first step is to simplify the environment as much as possible. Specifically:
Test with Bluetooth off — On iOS devices specifically, Bluetooth and Wi-Fi present unique coexistence challenges. If you’re primarily interested in Wi-Fi, test with Bluetooth off to see if that affects things.
Eliminate user space libraries — If you’re using a user space library (something like Multipeer Connectivity) it’s possible, albeit unlikely, that your latency problem is related to that library. The library itself might have a bug, or you might be using it incorrectly. To eliminate this possibility, switch to a low-level API, either BSD Sockets or NWConnection.
Disable peer-to-peer networking — Peer-to-peer networking is a common cause of network latency issues on Wi-Fi, so make sure it’s disabled. Peer-to-peer networking is not supported by BSD Sockets, so there’s nothing to do there. If you’re using Network framework, leave the includePeerToPeer property at its default value of false. Also, check other parts of your code to make sure that you haven’t enabled peer-to-peer networking in some other, unrelated place.
Switch to UDP — TCP is a complex protocol and it can have a non-obvious impact on latency. If you’re using TCP, switch to UDP.
IMPORTANT The steps listed above are part of the investigation, not an end in themselves. You may find that, once you understand the real cause of the latency, you go back to using your user space library, or go back to using TCP. However, run your initial investigation with a BSD Sockets or Network framework UDP program.
IMPORTANT Turn off Bluetooth using Settings > Bluetooth. On modern systems turning off Bluetooth in the Control Center does not turn it off completely.
The next step is to simplify your network environment. Ideally you’d want to directly connect the two machines, and thus avoid any possibility that network infrastructure is causing the latency. However, if you’re working with iOS, which while it supports Ethernet is not commonly used with it, it’s likely that you’ll need to use at least a Wi-Fi access point (AP). In that case I recommend that you use an Apple AP: an AirPort base station or Time Capsule. These aren’t necessarily better than third party APs — although there are a lot of broken APs out there! — but, by using an Apple AP, you guarantee that any problems you see are the responsibility of one vendor.
Note While discussing Wi-Fi I tend to slip into the habit of using low-level Wi-Fi terms, like AP. For an explanation of those, see Wi-Fi Fundamentals.
After following the steps above your setup will look something like this.
sending app receiving app
| |
| <-- A | <-- F
| |
kernel kernel
| |
| <-- B | <-- E
| |
Wi-Fi driver Wi-Fi driver
| |
+------ AirPort ------+
^ ^
C D
From there, you can insert probes into the network path to see where the latency is coming from. Specifically:
Add logging to your app to probe points A and F.
Use a standard packet trace to probe points B and E.
Use receive timestamps to probe point E. In BSD Sockets, set the SO_TIMESTAMP option and access the timestamps by looking at the SCM_TIMESTAMP value returned from recvmsg. In Network framework, set the shouldCalculateReceiveTime property and access the timestamps using the receiveTime property.
Use a Wi-Fi level packet trace to probe points C and D.
On the Mac, use DTrace to probe between A and B and between E and F.
IMPORTANT Use tcpdump on your Mac to record a packet trace. If you’re working on iOS, set up an RVI interface. Both of these are explained in Recording a Packet Trace, but you will also want to look at the tcpdump man page. For instructions on how to record a Wi-Fi level packet trace, see Recording a Wi-Fi Packet Trace.
With all of these probes in place you can understand where the packet got delayed. For example:
A delay between A and B would be pretty unusual when using UDP, but could be the result of congestion within the kernel’s TCP/IP stack.
If there’s a delay between B and C, you know that the sending device is having problems sending, either because of a problem within the Wi-Fi driver or because of a Wi-Fi level problem, for example, link-layer retransmissions. To investigate the latter in more depth, use a Wi-Fi level packet trace.
If there’s a delay between C and D, that could be an AP problem, an issue with Wi-Fi QoS, or the receiving Wi-Fi driver entering low-power mode. Again, the Wi-Fi level packet trace will help you understand this.
A delay between D and E is most likely caused by the receiving Wi-Fi driver but there could be other causes as well, like link-layer retransmission.
A delay between E and F could be caused by a bug in the kernel, congestion within the TCP/IP stack, or a thread scheduling problem within your app. In the last case, use the System Trace instrument to investigate thread scheduling delays.
Once you understand the cause of your latency, you can then think about how to reduce it. This might be something you can do yourself. For example, you might uncover a thread scheduling bug in your app. OTOH, the fix might be something that only Apple can do. For example, this might be a bug in the Wi-Fi driver and so all you can do is report that bug.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Revision history:
2022-01-25 — Added a discussion of peer-to-peer Wi-Fi. Mentioned Network framework as an alternative to BSD Sockets. Added a note about the user-space networking stack. Made other editorial changes.
2021-02-27 Fixed the formatting. Made minor editorial changes.
2019-03-01 Fixed some links now that QA1176 has been retired.
2018-09-11 Added a description of how to really turn off Bluetooth, along with some minor editoral changes.
2016-01-19 Made more editorial changes.
2015-10-09 Made minor editoral changes.
2015-04-03 Added a section about turning off Bluetooth.
On iOS beta, monitoring network usage using the getifaddrs API sporadically causes system volume spikes. This happens even though the application does not interact with any audio-related code. The issue persists across different polling intervals (e.g., 0.05s to 1s) and only occurs when invoking getifaddrs. Replacing the API calls with mock data eliminates the problem, suggesting a potential issue with getifaddrs in the beta environment.
The application updates UI elements based on network activity, but the volume spikes occur independently of UI or other observable app behavior.
Steps to Reproduce:
Create an app that monitors network usage using the getifaddrs API.
Fetch network statistics on a timer (e.g., every 0.05 seconds).
Observe system behavior while running the app on iOS beta.
Note sporadic volume spikes during app runtime.
Expected Result:
Polling network usage with getifaddrs should not affect system volume or other unrelated resources.
Actual Result:
System volume spikes occasionally when network statistics are retrieved using getifaddrs.
iOS 18.2 Beta, Tested on physical device ( iPhone 15 Pro )
Hi Team,
Looking for an answer, if it's just us or a widespread issue.
Since Sept, our clients Apple devices can't load a Captive Portal on Apple devices. Client wants the CNA to pop up and I can't get it to happen!
Android and Windows devices all work correctly with their respective popups, but CNA will not work.
No changes done on our side and after multiple tshoots and getting vendors to take multiple PCAPs found, Apple devices are not initiating a HTTP GET request as per Meraki >> https://documentation.meraki.com/MR/MR_Splash_Page/Splash_Page_Traffic_Flow_and_Troubleshooting
The work around is to force a HTTP GET request by manually going into the browser and initiate a http site (we tried 1.1.1.1, also tried other public HTTP sites and it works) and that redirects to our Captive Portal page.
Hi,
I've read a bunch of threads regarding the changes in Sonoma and later requiring Location permission for receiving SSIDs. However, as far as I can see, in Sequoia 15.1 SSIDs and BSSIDs are empty regardless.
In particular, this makes it not possible to use associate(withName:) and associate(withSSID:) because the network object returned by scanForNetwork(withSSID: "...") has its .ssid and .bssid set to nil.
Here is an example:
First we have a wrapper to call the code after the location permission is authorized:
import Foundation
import CoreLocation
class LocationDelegate: NSObject, CLLocationManagerDelegate {
var onAuthorized: (() -> Void)?
var onDenied: (() -> Void)?
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
let authStatus = manager.authorizationStatus
print("Location authorization status changed: \(authStatusToString(authStatus))")
if authStatus == .authorizedAlways {
onAuthorized?()
} else if authStatus == .denied || authStatus == .restricted {
onDenied?()
}
}
}
let locationManager = CLLocationManager()
let locationDelegate = LocationDelegate()
func authorizeLocation(onAuthorized: @escaping () -> Void, onDenied: @escaping () -> Void) {
let authStatus = locationManager.authorizationStatus
print("Location authorization status: \(authStatusToString(authStatus))")
if authStatus == .notDetermined {
print("Waiting for location authorization...")
locationDelegate.onAuthorized = onAuthorized
locationDelegate.onDenied = onDenied
locationManager.delegate = locationDelegate
locationManager.requestAlwaysAuthorization()
} else if authStatus == .authorizedAlways {
onAuthorized()
} else if authStatus == .denied || authStatus == .restricted {
onDenied()
}
RunLoop.main.run()
}
func authStatusToString(_ status: CLAuthorizationStatus) -> String {
switch status {
case .notDetermined:
return "Not Determined"
case .restricted:
return "Restricted"
case .denied:
return "Denied"
case .authorizedAlways:
return "Always Authorized"
case .authorizedWhenInUse:
return "Authorized When In Use"
@unknown default:
return "Unknown"
}
}
Then, a demo program itself:
import Foundation
import CoreWLAN
import Network
let client = CWWiFiClient.shared()
guard let interface = client.interface() else {
print("No wifi interface")
exit(1)
}
authorizeLocation(
onAuthorized: {
do {
print("Scanning for wifi networks...")
let scanResults = try interface.scanForNetworks(withSSID: nil)
let networks = scanResults.compactMap { network -> [String: Any]? in
return [
"ssid": network.ssid ?? "unknown",
"bssid": network.bssid ?? "unknown"
]
}
let jsonData = try JSONSerialization.data(withJSONObject: networks, options: .prettyPrinted)
if let jsonString = String(data: jsonData, encoding: .utf8) {
print(jsonString)
}
exit(0)
} catch {
print("Error: \(error)")
exit(1)
}
},
onDenied: {
print("Location access denied")
exit(1)
}
)
When launched, the program asks for permission, and after that, is shown as enabled in Privacy & Security Settings panel.
Here is the output where it can be seen that the scan is performed after location access was authorized, and regardless of that, all ssids are empty:
Location authorization status: Not Determined
Waiting for location authorization...
Location authorization status changed: Always Authorized
Scanning for wifi networks...
[
{
"ssid" : "unknown",
"bssid" : "unknown"
},
{
"ssid" : "unknown",
"bssid" : "unknown"
},
.... further omitted
Calling scanForNetworks() with explicitly specified network name does this as well, returns a CWNetwork object with .ssid / .bssid = nil.
I just want Mac Catalyst app can look up the SSID of the currently connected WiFI.
Xcode returns I can't use CoreWLan in Mac Catalyst, so I used NEHotspotNetwork, although I do not have convince whether Mac Catalyst allows it.
The same code of destination works fine on iPhone, but not on Mac Catalyst and Mac(Designed for iPad).
What is the proper way to get SSID of WiFI in Mac Catalyst?
Is there another way to do this?
The code I tried is below and I used CoreLocation API before call this function.
func getWiFiSsid() {
NEHotspotNetwork.fetchCurrent { network in
if let network = network {
print(network)
} else {
print("network is nil!")
}
}
}
Below is Entitlement file. Entitlements for app sandbox is removed when I run in Mac(Designed for iPad).
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.networking.HotspotConfiguration</key>
<true/>
<key>com.apple.developer.networking.networkextension</key>
<array/>
<key>com.apple.developer.networking.wifi-info</key>
<true/>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.personal-information.location</key>
<true/>
</dict>
</plist>
Below is Info.plist file.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>NSLocationUsageDescription</key>
<string>Determine whether the ssid of current Wi-Fi connection</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Determine whether the ssid of current Wi-Fi connection</string>
</dict>
</plist>
The console log is below.
NEHotspotNetwork nehelper sent invalid result code [1] for Wi-Fi information request
way to display it is by holding the Option key and clicking the Wi-Fi icon.
In macOS 14.0, wdutil was still usable, but in 14.6.1, the returned information is now . I am unsure if there is an official way to obtain the corresponding BSSID.
I need to process the BSSID in my code, so either a command-line tool or an API would work.
I am working on developing a client to complete 8021.x wireless authentication by python.
According to the CoreWLAN Documentation scanForNetworks(withName:), I'm going to use scanForNetworksWithName_error_ and associateToEnterpriseNetwork_identity_username_password_error_ provided in CoreWLAN. And I wrote a script to have a try.
import os
import pwd
from CoreWLAN import CWWiFiClient
from Foundation import NSString
def get_real_user():
sudo_user = os.environ.get('SUDO_USER')
if sudo_user:
return sudo_user
return os.environ.get('USER', 'root')
def run_as_user(username):
if os.geteuid() == 0:
uid = pwd.getpwnam(username).pw_uid
gid = pwd.getpwnam(username).pw_gid
os.setuid(uid)
def connect_to_enterprise_network(ssid, username, password):
try:
real_user = get_real_user()
if os.geteuid() == 0:
run_as_user(real_user)
client = CWWiFiClient.sharedWiFiClient()
interface = client.interface()
if not interface:
print("no interface")
return False
print("scaning...")
error = None
scan_result, error = interface.scanForNetworksWithName_error_(ssid, None)
if error:
print(f"scan fialed: {error.localizedDescription()}")
return False
target_network = None
for network in scan_result.allObjects():
if network.ssid() == ssid:
target_network = network
break
if not target_network:
print("no target network")
return False
success, error = interface.associateToEnterpriseNetwork_identity_username_password_error_(
target_network,
None,
NSString.stringWithString_(username),
NSString.stringWithString_(password),
None
)
if not success:
print(f"connect failed: {error.localizedDescription() if error else 'unknown error'}")
return False
print("connect successfully")
return True
except Exception as e:
print(f"exception: {str(e)}")
return False
if __name__ == "__main__":
ssid = "ssid"
username = "username"
password = "password"
success = connect_to_enterprise_network(ssid, username, password)
However, I can only execute this script normally under non-root permissions. When I switch to root and execute it, the variable "scan_result.allObjects()" will be an object without any ssid and bssid. Finally the function prints "no target network" and returned.
<CWNetwork: 0x107104080> [ssid=(null), bssid=(null), security=WPA2 Enterprise, rssi=-52, channel=<CWChannel: 0x11e8a1fd0> [channelNumber=44(5GHz), channelWidth={20MHz}], ibss=0]
Compared with the value without sudo:
[<CWNetwork: 0x144650580> [ssid=ssid, bssid=<redacted>, security=WPA2 Enterprise, rssi=-55, channel=<CWChannel: 0x1247040d0> [channelNumber=149(5GHz), channelWidth={20MHz}], ibss=0]]
My python code will be included in an app that must be executed as a root user, so this issue can't be ignored and waiting for your help. THANKS!
On my macOS 15.x device, frequently encountering the error:
Error Domain=com.apple.wifi.apple80211API.error Code=-528342014 "tmpErr"
when connecting to an EAP WiFi network using CWWiFiClient. Restarting the device temporarily resolves the issue, but it reoccurs after some time.
What could be causing this, and how can it be resolved programmatically?
Hello. I'm developing on a cross-platform app to help user connect enterprise network and found it difficult in macOS.
The issue is, I guided user to install profile, but the authentication won't start immediately even the cable is plugged in or the WLAN is connected. There is still some manual operation to be done:
Ethernet: Select the correct profile, and click the Connect button.
Wlan: Click the Connect button. (The profile contains SSID so need't select the correct profile)
Obviously, the operation is still not easy for users to understand and follow. So, is there any method to auto connect 802.1x network using the selected profile in terminal or by code? I mean, the manual operation is not necessary, maybe you can tell me a better solution.
BTW, I found it possible to connect WLAN and auto select the correct profile by using this command
networksetup -setairportnetwork en1 MY_SSID, but it could be very slow since the authentication seemed start 30 sec after connecting the SSID. So I believe it not the best solution.
I use eapolcfg in Apple's open source eap8021x repository to connect to the enterprise network.
1.https://github.com/gfleury/eap8021x-debug
https://opensource.apple.com/source/eap8021x/eap8021x-304.100.1/
Our enterprise network authentication is PEAP. So far, I have created a profile using the following commands and have done the access.
./eapolcfg createProfile --authType PEAP --SSID myssid --securityType WPA2 --userDefinedName MyProfile
./eapolcfg setPasswordItem --password mypassword --name myname --SSID myssid
./eapolcfg startAuthentication --interface en0 --SSID myssid
After I performed this series of operations, I passed
BOOL success = [self.interface associateToEnterpriseNetwork:network identity:nil username:username password:password error:&error];
Connection will pop up the following pop-up window, sometimes associateToEnterpriseNetwork will fail. I don't know what went wrong, is it that I missed some steps through the eapolcfg [tool?]
This function also reports the following error:Error Domain=com.apple.coreWLAN.EAPOL.error Code=1
"(null)"
Please answer my questions. Thank you very much
I don't understand what permissions need to be given for this code to operate. I cannot seem to work out why I'm not able to see a BSSID.
I think I've given sandbox the appropriate permissions AND I've added some to the Target Properties for good measure. Yet, cannot get BSSID.
import SwiftUI
import CoreWLAN
import CoreLocation
struct ContentView: View {
@State private var currentBSSID: String = "Loading..."
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Current BSSID:")
Text(currentBSSID)
}
.padding()
.onAppear(perform: fetchBSSID)
}
func fetchBSSID() {
if let iface2 = CWWiFiClient.shared().interface() {
print("✅ Found Wi-Fi interface: \(iface2.interfaceName ?? "nil")")
} else {
print("❌ No Wi-Fi interface found")
}
if let iface = CWWiFiClient.shared().interface(),
let bssid = iface.bssid() {
currentBSSID = bssid
} else {
currentBSSID = "Not connected"
print("✅ BSSID: \(currentBSSID)")
}
}
}
#Preview {
ContentView()
}
Output - WifI interface is found but BSSID is not found.
Hi! I'm trying to prototype a macOS app related to wifi features. The main hiccup I've encountered is "Connect to a saved network without re-entering the network password".
So far I've been unsuccessful in this without
entering the password manually each time
asking the user for authentication to access the saved network in keychain
I read somewhere on the internet that CWInterface.associate would use saved credentials automatically if you gave a nil password, but my attempts have proven that to be false.
Is this not currently available because it raises security concerns, or it just hasn't been considered? Or am I missing a way to do this? I don't need access to the credentials, just for the system to connect for me.
I have an app that connect to specific wifi but the macos always save password while i do not want user to remember the password. Anyway to stop or work around on it?