Core WLAN

RSS for tag

Provide APIs for querying AirPort interfaces and choosing networks using Core WLAN.

Posts under Core WLAN tag

9 Posts

Post

Replies

Boosts

Views

Activity

Wi-Fi Fundamentals
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.
0
0
8.4k
Jun ’22
Investigating Network Latency Problems
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.
0
0
8.2k
Jan ’23
Monitor mode capture broken with Wi-Fi 7 (M5 Pro MacBook Pro) on macOS 26 - worked previously on same OS with older hardware
Platform: macOS 26.3.1, M5 Pro MacBook Pro Framework: CoreWLAN Affected applications: NetViews, Air Tool 2, and our own tooling — appears to be specific to the new Wi-Fi 7 hardware Hardware Card Type: chip id: 0x11 api 1.2 firmware [Rev 72.11.260 N1B1 devFused=0] phy [17.1.17.0], core80211 [324.10.260 N1_silicon_b] Firmware: Jan 27 2026 21:18:32 version XBS_BUILD_TAG GIT_DESCRIBE FWID chip id: 0x11 api 1.2 firmware [Rev 72.11.260 N1B1 devFused=0] phy [17.1.17.0], core80211 [324.10.260 N1_silicon_b] Driver: IO80211_driverkit-1540.16 "IO80211_driverkit-1540.16" Jan 27 2026 Background Both issues described below were working correctly on macOS 26 with previous-generation hardware. The regression is specific to the Wi-Fi 7 card shipping in the M5 Pro MacBook Pro. This is not an OS regression — it is a hardware/driver/firmware compatibility issue with the new card under macOS 26. Issue 1: disassociate() + tcpdump/Wireshark -I no longer enters monitor mode Previously, the standard approach of calling disassociate() and then launching tcpdump -i en0 -I or Wireshark -i en0 -I -k would successfully put the interface into monitor mode. On the M5 Pro Wi-Fi 7 card, this no longer works. The capture tool launches but the interface either stays in station mode or enters mode 0 - where there is no connection, but still not able to be a monitor radio. This is the primary regression affecting third-party wireless tools. Issue 2: setWLANChannel reports success but the radio only retunes once As a workaround for Issue 1, we use the built-in Wireless Diagnostics → Sniffer tool to establish monitor mode (which works fairly reliably on this hardware). Once the interface is in monitor mode via that path, we attempt to change the channel using setWLANChannel: let iface = CWWiFiClient.shared().interface(withName: "en0")! let target = iface.supportedWLANChannels()! .first { $0.channelNumber == 6 && $0.channelWidth == .width20MHz }! try iface.setWLANChannel(target) The first call succeeds (eg: channel 48 -> 6) the radio actually tunes to the requested channel and Wireshark captures frames there. Any subsequent call (eg: channel 48 -> 6 -> 1) shows the same apparent success - no error thrown, wlanChannel() updates to reflect the new channel - but the radio does not retune. Wireshark continues capturing on the first changed channel. We have tested with disassociate() and interface power cycling between attempts — neither resets the ability to retune the radio. What we have ruled out Timing: delays between calls make no difference Competing processes holding the interface wlanChannel() returning a stale cache value — it updates correctly, but diverges from actual hardware state after the first channel change Key data point: Wireless Diagnostics Sniffer works The built-in Wireless Diagnostics → Sniffer tool successfully puts the interface into monitor mode on this hardware. This confirms the card and driver are capable - the issue is that the capability is no longer reachable via CoreWLAN or via tcpdump/Wireshark's -I flag. Wireless Diagnostics Sniffer does not support live channel changes, so it cannot serve as a full workaround. The questions Is there a supported path for third-party apps to enter monitor mode on the new Wi-Fi 7 hardware on macOS 26? What is the correct mechanism for changing channels while in monitor mode - is setWLANChannel expected to retune the radio on subsequent calls, or is there a different API intended for this? The fact that Wireless Diagnostics accomplishes both (albeit, not live) confirms the hardware and driver are fully capable - we are looking for the sanctioned equivalent for third-party tools.
4
1
187
5d
Cannot get WiFi SSID inside launchctl agent
I am developing a macOS application that depends on noticing when the user's computer switches WiFi association, and the SSID determines specific actions. I am currently testing on Tahoe and found that using CoreWLAN can even get notifications and discover the actual SSID inside an app, as long as the app is signed with a real certificate and a corresponding profile is installed on my development machine. The app, however, installs and launches a launchctl agent, which will always be running and hence the component to discover changes and act upon them. Although app and agent both have their own bundle identifier, both configured in the portal, the agent always received a redacted SSID (nil), while the app does not. The only app entitlement currently is "com.apple.security.get-task-allow = true", which I don't think has anything to do with this. The agent has: com.apple.application-identifier com.apple.developer.team-identifier com.apple.security.get-task-allow com.apple.security.personal-information.location Both have asked for permission, and both have location services enabled in system settings. The agent runs as an LSUIElement=1, headless/background configuration. So, am I missing something, a step, or is there a fundamental restriction on an agent that makes this an impossible task? (Right now, it runs a shortcut to discover the name, but requires the user to create it, and it has side effects I'd rather not see, like the flashing indicator in the menu bar)
4
0
144
Feb ’26
iPhones/iPads unable to connect to ClearPass Captive portals - Issue affecting only Meraki APs with FortiGates
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.
1
0
274
Feb ’26
Title: Accessing Wi-Fi SSID for custom On-Demand logic in PacketTunnelProvider on macOS
We are developing a macOS VPN application using NEPacketTunnelProvider with a custom encryption protocol. We are using standard On-Demand VPN rules with Wi-Fi SSID matching but we want to add some additional feature to the native behaviour.  We want to control the 'conenect/disconnect' button status and allow the user to interact with the tunnel even when the on demand rule conditions are satisfied, is there a native way to do it? In case we need to implement our custom on-demand behaviour we need to access to this information: connected interface type ssid name and being informed when it changes so to trigger our logic, how to do it from the app side? we try to use CWWiFiClient along with ssidDidChangeForWiFiInterface monitoring, it returns just the interface name en0 and not the wifi ssid name. Is location access mandatory to access wifi SSID on macOS even if we have a NEPacketTunnelProvider? Please note that we bundle our Network Extension as an App Extension (not SystemExtension).
9
2
380
Jan ’26
How to Determine the Actual Wi-Fi Band (2.4GHz / 5GHz / 6GHz) on macOS Programmatically
I’m trying to determine the actual Wi-Fi band (e.g. 2.4GHz, 5GHz, or 6GHz) of the network that is currently connected on macOS. I’m not looking for a heuristic based on the Wi-Fi name (SSID), such as checking whether it contains “5G” or “6G”. Instead, I want a reliable and accurate method that reflects the real connection parameters reported by the system. Specifically, I’m interested in: Whether macOS exposes the current Wi-Fi band or channel information through public APIs (e.g. CoreWLAN) Or if there is any supported system-level way to retrieve this information programmatically If this information is not directly accessible, I’d also like to understand: Why macOS does not expose it And whether there is a recommended alternative approach Any insights or examples would be greatly appreciated.
2
0
145
Jan ’26
System Information in macOS 26.2 RC no longer shows Wi-Fi SSIDs
System Information in macOS from 26.0 to 26.2 RC no longer provides Wi-Fi SSIDs; instead, it displays "< redacted> " for every SSID on my two MacBooks. This issue has been fixed in macOS 26.1 beta and macOS 26.2 beta, but it returns in the RC and the Final Release versions. Is it an expected behaviour or a bug in the Release Candidate? MacBook Air 2025: MacBook Pro 2021:
1
0
198
Dec ’25
Connect to saved wifi network without user auth
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.
2
0
157
Sep ’25
Access BSSID MacOS
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.
2
0
219
Apr ’25
Wi-Fi Fundamentals
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.
Replies
0
Boosts
0
Views
8.4k
Activity
Jun ’22
Investigating Network Latency Problems
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.
Replies
0
Boosts
0
Views
8.2k
Activity
Jan ’23
Monitor mode capture broken with Wi-Fi 7 (M5 Pro MacBook Pro) on macOS 26 - worked previously on same OS with older hardware
Platform: macOS 26.3.1, M5 Pro MacBook Pro Framework: CoreWLAN Affected applications: NetViews, Air Tool 2, and our own tooling — appears to be specific to the new Wi-Fi 7 hardware Hardware Card Type: chip id: 0x11 api 1.2 firmware [Rev 72.11.260 N1B1 devFused=0] phy [17.1.17.0], core80211 [324.10.260 N1_silicon_b] Firmware: Jan 27 2026 21:18:32 version XBS_BUILD_TAG GIT_DESCRIBE FWID chip id: 0x11 api 1.2 firmware [Rev 72.11.260 N1B1 devFused=0] phy [17.1.17.0], core80211 [324.10.260 N1_silicon_b] Driver: IO80211_driverkit-1540.16 "IO80211_driverkit-1540.16" Jan 27 2026 Background Both issues described below were working correctly on macOS 26 with previous-generation hardware. The regression is specific to the Wi-Fi 7 card shipping in the M5 Pro MacBook Pro. This is not an OS regression — it is a hardware/driver/firmware compatibility issue with the new card under macOS 26. Issue 1: disassociate() + tcpdump/Wireshark -I no longer enters monitor mode Previously, the standard approach of calling disassociate() and then launching tcpdump -i en0 -I or Wireshark -i en0 -I -k would successfully put the interface into monitor mode. On the M5 Pro Wi-Fi 7 card, this no longer works. The capture tool launches but the interface either stays in station mode or enters mode 0 - where there is no connection, but still not able to be a monitor radio. This is the primary regression affecting third-party wireless tools. Issue 2: setWLANChannel reports success but the radio only retunes once As a workaround for Issue 1, we use the built-in Wireless Diagnostics → Sniffer tool to establish monitor mode (which works fairly reliably on this hardware). Once the interface is in monitor mode via that path, we attempt to change the channel using setWLANChannel: let iface = CWWiFiClient.shared().interface(withName: "en0")! let target = iface.supportedWLANChannels()! .first { $0.channelNumber == 6 && $0.channelWidth == .width20MHz }! try iface.setWLANChannel(target) The first call succeeds (eg: channel 48 -> 6) the radio actually tunes to the requested channel and Wireshark captures frames there. Any subsequent call (eg: channel 48 -> 6 -> 1) shows the same apparent success - no error thrown, wlanChannel() updates to reflect the new channel - but the radio does not retune. Wireshark continues capturing on the first changed channel. We have tested with disassociate() and interface power cycling between attempts — neither resets the ability to retune the radio. What we have ruled out Timing: delays between calls make no difference Competing processes holding the interface wlanChannel() returning a stale cache value — it updates correctly, but diverges from actual hardware state after the first channel change Key data point: Wireless Diagnostics Sniffer works The built-in Wireless Diagnostics → Sniffer tool successfully puts the interface into monitor mode on this hardware. This confirms the card and driver are capable - the issue is that the capability is no longer reachable via CoreWLAN or via tcpdump/Wireshark's -I flag. Wireless Diagnostics Sniffer does not support live channel changes, so it cannot serve as a full workaround. The questions Is there a supported path for third-party apps to enter monitor mode on the new Wi-Fi 7 hardware on macOS 26? What is the correct mechanism for changing channels while in monitor mode - is setWLANChannel expected to retune the radio on subsequent calls, or is there a different API intended for this? The fact that Wireless Diagnostics accomplishes both (albeit, not live) confirms the hardware and driver are fully capable - we are looking for the sanctioned equivalent for third-party tools.
Replies
4
Boosts
1
Views
187
Activity
5d
Cannot get WiFi SSID inside launchctl agent
I am developing a macOS application that depends on noticing when the user's computer switches WiFi association, and the SSID determines specific actions. I am currently testing on Tahoe and found that using CoreWLAN can even get notifications and discover the actual SSID inside an app, as long as the app is signed with a real certificate and a corresponding profile is installed on my development machine. The app, however, installs and launches a launchctl agent, which will always be running and hence the component to discover changes and act upon them. Although app and agent both have their own bundle identifier, both configured in the portal, the agent always received a redacted SSID (nil), while the app does not. The only app entitlement currently is "com.apple.security.get-task-allow = true", which I don't think has anything to do with this. The agent has: com.apple.application-identifier com.apple.developer.team-identifier com.apple.security.get-task-allow com.apple.security.personal-information.location Both have asked for permission, and both have location services enabled in system settings. The agent runs as an LSUIElement=1, headless/background configuration. So, am I missing something, a step, or is there a fundamental restriction on an agent that makes this an impossible task? (Right now, it runs a shortcut to discover the name, but requires the user to create it, and it has side effects I'd rather not see, like the flashing indicator in the menu bar)
Replies
4
Boosts
0
Views
144
Activity
Feb ’26
iPhones/iPads unable to connect to ClearPass Captive portals - Issue affecting only Meraki APs with FortiGates
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.
Replies
1
Boosts
0
Views
274
Activity
Feb ’26
Title: Accessing Wi-Fi SSID for custom On-Demand logic in PacketTunnelProvider on macOS
We are developing a macOS VPN application using NEPacketTunnelProvider with a custom encryption protocol. We are using standard On-Demand VPN rules with Wi-Fi SSID matching but we want to add some additional feature to the native behaviour.  We want to control the 'conenect/disconnect' button status and allow the user to interact with the tunnel even when the on demand rule conditions are satisfied, is there a native way to do it? In case we need to implement our custom on-demand behaviour we need to access to this information: connected interface type ssid name and being informed when it changes so to trigger our logic, how to do it from the app side? we try to use CWWiFiClient along with ssidDidChangeForWiFiInterface monitoring, it returns just the interface name en0 and not the wifi ssid name. Is location access mandatory to access wifi SSID on macOS even if we have a NEPacketTunnelProvider? Please note that we bundle our Network Extension as an App Extension (not SystemExtension).
Replies
9
Boosts
2
Views
380
Activity
Jan ’26
How to Determine the Actual Wi-Fi Band (2.4GHz / 5GHz / 6GHz) on macOS Programmatically
I’m trying to determine the actual Wi-Fi band (e.g. 2.4GHz, 5GHz, or 6GHz) of the network that is currently connected on macOS. I’m not looking for a heuristic based on the Wi-Fi name (SSID), such as checking whether it contains “5G” or “6G”. Instead, I want a reliable and accurate method that reflects the real connection parameters reported by the system. Specifically, I’m interested in: Whether macOS exposes the current Wi-Fi band or channel information through public APIs (e.g. CoreWLAN) Or if there is any supported system-level way to retrieve this information programmatically If this information is not directly accessible, I’d also like to understand: Why macOS does not expose it And whether there is a recommended alternative approach Any insights or examples would be greatly appreciated.
Replies
2
Boosts
0
Views
145
Activity
Jan ’26
System Information in macOS 26.2 RC no longer shows Wi-Fi SSIDs
System Information in macOS from 26.0 to 26.2 RC no longer provides Wi-Fi SSIDs; instead, it displays "< redacted> " for every SSID on my two MacBooks. This issue has been fixed in macOS 26.1 beta and macOS 26.2 beta, but it returns in the RC and the Final Release versions. Is it an expected behaviour or a bug in the Release Candidate? MacBook Air 2025: MacBook Pro 2021:
Replies
1
Boosts
0
Views
198
Activity
Dec ’25
Remove wifi password
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?
Replies
5
Boosts
0
Views
161
Activity
Oct ’25
Connect to saved wifi network without user auth
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.
Replies
2
Boosts
0
Views
157
Activity
Sep ’25
Access BSSID MacOS
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.
Replies
2
Boosts
0
Views
219
Activity
Apr ’25