| // Copyright 2022 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| @available(added=HEAD) |
| library fuchsia.wlan.fullmac; |
| |
| using fuchsia.wlan.common; |
| using fuchsia.wlan.ieee80211 as ieee80211; |
| using fuchsia.wlan.stats; |
| using zx; |
| |
| type WlanScanType = flexible enum : uint8 { |
| ACTIVE = 1; |
| PASSIVE = 2; |
| }; |
| |
| /// Max length for vendor IEs to be added to the association request. This is currently |
| /// used for WPA. |
| const WLAN_VIE_MAX_LEN uint32 = 514; |
| |
| type WlanAuthType = flexible enum : uint8 { |
| OPEN_SYSTEM = 1; |
| SHARED_KEY = 2; |
| FAST_BSS_TRANSITION = 3; |
| SAE = 4; |
| }; |
| |
| const WLAN_MAX_KEYLIST_SIZE uint32 = 4; |
| |
| type WlanFullmacSetKeysResp = struct { |
| statuslist vector<zx.Status>:WLAN_MAX_KEYLIST_SIZE; |
| }; |
| |
| /// Contains the information of SAE authentication frames. Shared between transmit and receive |
| /// directions, see WlanFullmacImplIfc::SaeFrameRx and WlanFullmacImpl::SaeFrameTx. |
| type SaeFrame = table { |
| /// The peer's MAC address. Required. |
| 1: peer_sta_address ieee80211.MacAddr; |
| /// The status code for this SAE frame. Required. |
| 2: status_code ieee80211.StatusCode; |
| /// The sequence number. Required. |
| 3: seq_num uint16; |
| /// Contains fields in the frame body relevant to SAE. |
| /// See IEEE Std 802.11-2016 table 9-35 and table 9-36 for more details. |
| /// Required. |
| 4: sae_fields vector<uint8>:MAX; |
| }; |
| |
| type WlanScanResult = flexible enum : uint8 { |
| SUCCESS = 0; |
| NOT_SUPPORTED = 1; |
| INVALID_ARGS = 2; |
| INTERNAL_ERROR = 3; |
| SHOULD_WAIT = 4; |
| CANCELED_BY_DRIVER_OR_FIRMWARE = 5; |
| }; |
| |
| type WlanAuthResult = flexible enum : uint8 { |
| SUCCESS = 0; |
| REFUSED = 1; |
| ANTI_CLOGGING_TOKEN_REQUIRED = 2; |
| FINITE_CYCLIC_GROUP_NOT_SUPPORTED = 3; |
| REJECTED = 4; |
| FAILURE_TIMEOUT = 5; |
| }; |
| |
| type WlanAssocResult = flexible enum : uint8 { |
| SUCCESS = 0; |
| REFUSED_REASON_UNSPECIFIED = 1; |
| REFUSED_NOT_AUTHENTICATED = 2; |
| REFUSED_CAPABILITIES_MISMATCH = 3; |
| REFUSED_EXTERNAL_REASON = 4; |
| REFUSED_AP_OUT_OF_MEMORY = 5; |
| REFUSED_BASIC_RATES_MISMATCH = 6; |
| REJECTED_EMERGENCY_SERVICES_NOT_SUPPORTED = 7; |
| REFUSED_TEMPORARILY = 8; |
| }; |
| |
| |
| type StartResult = flexible enum : uint8 { |
| SUCCESS = 0; |
| BSS_ALREADY_STARTED_OR_JOINED = 1; |
| RESET_REQUIRED_BEFORE_START = 2; |
| NOT_SUPPORTED = 3; |
| }; |
| |
| type StopResult = flexible enum : uint8 { |
| SUCCESS = 0; |
| BSS_ALREADY_STOPPED = 1; |
| INTERNAL_ERROR = 2; |
| }; |
| |
| type EapolTxResult = flexible enum : uint8 { |
| SUCCESS = 0; |
| TRANSMISSION_FAILURE = 1; |
| }; |
| |
| type WlanFullmacSignalReportIndication = struct { |
| rssi_dbm int8; |
| snr_db int8; |
| }; |
| |
| /// Describes parameters and capabilities for a single WlanBand. |
| type BandCapability = table { |
| /// The values of this table apply to the band indicated in this field. |
| /// |
| /// Required. |
| 1: band ieee80211.WlanBand; |
| |
| /// Basic rates supported in units of 500 kbit/s (as defined in |
| /// IEEE Std 802.11-2016, 9.4.2.3), e.g., 0x02 represents 1 Mbps. |
| /// The value returned by this type indicates all the non-HT rates |
| /// the device supports transmitting and receiving. |
| /// |
| /// Required. |
| // TODO(https://fxbug.dev/384771238): Determine if this field is needed. |
| 2: basic_rates vector<uint8>:ieee80211.MAX_SUPPORTED_BASIC_RATES; |
| |
| /// HT PHY mode capabilities. |
| /// |
| /// Optional. If this field is not present, then the device does not support HT PHY mode in this |
| /// band. |
| 3: ht_caps ieee80211.HtCapabilities; |
| |
| /// VHT PHY mode capabilities. |
| /// |
| /// Optional. If this field is not present, then the device does not support VHT PHY mode in |
| /// this band. |
| 4: vht_caps ieee80211.VhtCapabilities; |
| |
| /// A list of operating channels considered valid by hardware, in the context of |
| /// regulatory information known to the device driver, at the time of its |
| /// construction during iface creation. In this context, an operating channel |
| /// means a channel which APs may transmit Beacon frames on in the current |
| /// regulatory domain. |
| /// |
| /// This list should be used to determine efficacy of subsequent requests to |
| /// scan a subset of channels using the iface, or to determine which operating |
| /// channel to use when starting an AP. |
| /// |
| /// Required. |
| // TODO(https://fxbug.dev/384771716): Determine if this field is needed. |
| 5: operating_channels vector<uint8>:ieee80211.MAX_UNIQUE_CHANNEL_NUMBERS; |
| }; |
| |
| type WlanFullmacRssiStats = struct { |
| hist vector<uint64>:MAX; |
| }; |
| |
| type WlanFullmacChannelSwitchInfo = struct { |
| new_channel uint8; |
| }; |
| |
| /// Protocol definition for communication from the fullmac vendor driver to the platform. |
| @discoverable |
| closed protocol WlanFullmacImplIfc { |
| // MLME operations |
| strict OnScanResult(table { |
| 1: txn_id uint64; |
| // Time of the scan result relative to when the system was powered on. |
| // See https://fuchsia.dev/fuchsia-src/concepts/time/language_support#monotonic_time |
| 2: timestamp_nanos zx.Time; |
| 3: bss fuchsia.wlan.common.BssDescription; |
| }) -> (); |
| strict OnScanEnd(table { |
| 1: txn_id uint64; |
| 2: code WlanScanResult; |
| }) -> (); |
| strict ConnectConf(table { |
| 1: peer_sta_address ieee80211.MacAddr; |
| 2: result_code ieee80211.StatusCode; |
| |
| // These fields are only valid if the result is success. |
| 3: association_id uint16; |
| 4: association_ies vector<uint8>:MAX; |
| }) -> (); |
| /// Report the result of an MLME-initiated roam attempt. |
| strict RoamConf(table { |
| /// BSSID of the target BSS. Required. |
| 1: selected_bssid ieee80211.MacAddr; |
| /// Result of the roam attempt. Required. |
| 2: status_code ieee80211.StatusCode; |
| /// Whether the original BSS association has been maintained through the roam attempt. Required. |
| /// A successful roam always incurs disassociation from the original BSS, so if `status_code` is |
| /// success then this field must be set to false; a roam failure typically incurs disassociation |
| /// from the original BSS, but may not in some cases (e.g. in some Fast BSS Transition scenarios). |
| 3: original_association_maintained bool; |
| /// Whether the client is authenticated with the target BSS. If `status_code` is success, then |
| /// this field must be set to true; if the roam attempt failed, this field may be true or false. |
| /// This allows higher layers to decide how to clean up connection state after a failed roam |
| /// attempt. |
| 4: target_bss_authenticated bool; |
| /// Association ID for this association with the AP. Required if `status_code` is success. |
| 5: association_id uint16; |
| /// IEs for this association with the AP. Required if `status_code` is success. |
| 6: association_ies vector<uint8>:MAX; |
| }) -> (); |
| /// Report that a fullmac-initiated roam attempt is in progress. |
| /// Fullmac must send this start indication for all roam attempts. |
| strict RoamStartInd(table { |
| /// BSSID of the target BSS. Required. |
| 1: selected_bssid ieee80211.MacAddr; |
| /// Full BSS description of the target BSS. Required. |
| /// If the data in BssDescription is incorrect or incomplete, the roam cannot succeed, |
| /// because higher layers will not be able to complete required actions (e.g. SAE). |
| 2: selected_bss fuchsia.wlan.common.BssDescription; |
| /// Whether the original BSS association has been maintained at the start of a roam attempt. |
| /// Required. 802.11 dictates that a STA can only be associated with a single BSS, so a roam |
| /// attempt typically incurs disassociation at the start of the roam attempt. However, |
| /// 802.11 also provides a mechanism (i.e. Fast BSS Transition) that allows a device to |
| /// maintain association with the original BSS while establishing authentication with the |
| /// target BSS, in order to avoid losing the original association if authentication with the |
| /// target BSS fails. |
| 3: original_association_maintained bool; |
| }) -> (); |
| /// Report the result of a fullmac-initiated roam attempt. |
| strict RoamResultInd(table { |
| /// BSSID of the target BSS. Required. |
| 1: selected_bssid ieee80211.MacAddr; |
| /// Result of the roam attempt. Required. |
| 2: status_code ieee80211.StatusCode; |
| /// Whether the original BSS association has been maintained through the roam attempt. Required. |
| /// A successful roam always incurs disassociation from the original BSS, so if `status_code` is |
| /// success then this field must be set to false; a roam failure typically incurs disassociation |
| /// from the original BSS, but may not in some cases (e.g. in some Fast BSS Transition scenarios). |
| 3: original_association_maintained bool; |
| /// Whether the client is authenticated with the target BSS. If `status_code` is success, then |
| /// this field must be set to true; if the roam attempt failed, this field may be true or false. |
| /// This allows higher layers to decide how to clean up connection state after a failed roam |
| /// attempt. |
| 4: target_bss_authenticated bool; |
| /// Association ID for this association with the AP. Required if `status_code` is success. |
| 5: association_id uint16; |
| /// IEs for this association with the AP. Required if `status_code` is success. |
| 6: association_ies vector<uint8>:MAX; |
| }) -> (); |
| strict AuthInd(table { |
| 1: peer_sta_address ieee80211.MacAddr; |
| 2: auth_type WlanAuthType; |
| }) -> (); |
| strict DeauthConf(table { |
| 1: peer_sta_address ieee80211.MacAddr; |
| }) -> (); |
| /// Report that the driver deauthenticated. |
| strict DeauthInd(table { |
| /// MAC address of the peer. Required. |
| 1: peer_sta_address ieee80211.MacAddr; |
| /// Reason code for deauthentication. Required. |
| 2: reason_code ieee80211.ReasonCode; |
| /// locally_initiated is true if deauth is initiated from the device, |
| /// and is false if it's initiated remotely (e.g. due to deauth frame) |
| 3: locally_initiated bool; |
| }) -> (); |
| strict AssocInd(table { |
| 1: peer_sta_address ieee80211.MacAddr; |
| // Interval specified in time units. |
| 2: listen_interval uint16; |
| 3: ssid ieee80211.Ssid; |
| 4: rsne vector<uint8>:ieee80211.WLAN_IE_MAX_LEN; |
| 5: vendor_ie vector<uint8>:WLAN_VIE_MAX_LEN; |
| }) -> (); |
| /// Report the result of a previously-issued disassociate request. IEEE 802.11-2020 6.3.9.2. |
| strict DisassocConf(table { |
| /// ZX_OK indicates that the disassociate request was serviced and the peer was |
| /// disassociated. Other errors indicate that the request could not be serviced, for these |
| /// or other reasons: |
| /// - ZX_ERR_BAD_STATE: association not possible in current state (e.g. disconnected) |
| /// - ZX_ERR_INVALID_ARGS: no association exists with specified peer |
| /// - ZX_ERR_SHOULD_WAIT: disassociate request could not be serviced because firmware or |
| /// driver was busy |
| 1: status zx.Status; |
| }) -> (); |
| /// Report that disassociation with the specified peer occurred (IEEE 802.11-2020 6.3.9.3). |
| strict DisassocInd(table { |
| /// Address of the peer that was disassociated. Required. |
| 1: peer_sta_address ieee80211.MacAddr; |
| /// Reason for the disassociation. Required. |
| 2: reason_code ieee80211.ReasonCode; |
| /// Whether the disassociation was initiated from the device. Required. |
| /// locally_initiated is true if disassociation was initiated from the device (e.g. firmware |
| /// or vendor driver started the disassociation); false if the disassociation was initiated |
| /// externally (e.g. due to receipt of a disassociate frame from an AP). |
| 3: locally_initiated bool; |
| }) -> (); |
| /// Report the result of a WlanFullmacImpl::StartBss request. |
| strict StartConf(table { |
| /// The result of the StartBss request. Required. |
| 1: result_code StartResult; |
| }) -> (); |
| /// Report the result of a WlanFullmacImpl::StopBss request. |
| strict StopConf(table { |
| /// The result of the StopBss request. Required. |
| 1: result_code StopResult; |
| }) -> (); |
| /// Report the result of a EAPoL frame transmission (IEEE 802.11-2020 6.3.22.2). |
| /// EAPoL frames are transmitted by the platform via WlanFullmacImpl::EapolTx. |
| strict EapolConf(table { |
| /// The result of the transmission. Required. |
| 1: result_code EapolTxResult; |
| /// This value corresponds to the dst_addr in the EapolTxRequest we're confirming. |
| /// IEEE 802.11-2020 does not include this field, but we need it to disambiguate |
| /// if multiple EAPoL handshakes are ongoing. |
| /// Required. |
| 2: dst_addr ieee80211.MacAddr; |
| }) -> (); |
| strict OnChannelSwitch(struct { |
| ind WlanFullmacChannelSwitchInfo; |
| }) -> (); |
| |
| // MLME extensions |
| strict SignalReport(struct { |
| ind WlanFullmacSignalReportIndication; |
| }) -> (); |
| /// Report that an EAPoL frame was received. |
| strict EapolInd(table { |
| /// The address of the sender. Required. |
| 1: src_addr ieee80211.MacAddr; |
| /// The address of the intended destination. Required. |
| 2: dst_addr ieee80211.MacAddr; |
| /// The bytes of the EAPoL frame data. Required. |
| 3: data vector<uint8>:MAX; |
| }) -> (); |
| /// Inform the platform that the PMK is available after a driver-handled SAE handshake. |
| strict OnPmkAvailable(table { |
| /// The pairwise master key bytes. Required. |
| 1: pmk vector<uint8>:MAX; |
| /// The PMK IDs. Required. |
| 2: pmkid vector<uint8>:MAX; |
| }) -> (); |
| strict SaeHandshakeInd(table { |
| 1: peer_sta_address ieee80211.MacAddr; |
| }) -> (); |
| /// Receive an SAE authentication frame. |
| strict SaeFrameRx(struct { |
| frame SaeFrame; |
| }) -> (); |
| strict OnWmmStatusResp(struct { |
| status zx.Status; |
| wmm_params fuchsia.wlan.common.WlanWmmParameters; |
| }) -> (); |
| }; |
| |
| /// Protocol definition for communication from the platform to the fullmac |
| /// vendor driver. |
| @discoverable |
| closed protocol WlanFullmacImpl { |
| |
| /// Initialize the FullMAC driver. This is the first request that the platform will make to the |
| /// FullMAC driver. |
| /// |
| /// On initialization, MLME provides the client end to the WlanFullmacImplIfc protocol. The |
| /// driver must return the SME server end channel, which is used internally by the platform. |
| /// Typically, the SME server end channel is given to the FullMAC driver by |
| /// fuchsia.wlan.phyimpl/WlanPhyImpl.CreateIface. |
| /// |
| /// If `Init` completes successfully, the platform will begin making other WlanFullmacImpl |
| /// requests to the FullMAC driver, and the FullMAC driver is free to make WlanFullmacImplIfc |
| /// requests to the platform. The platform may continue making WlanFullmacImpl requests until |
| /// the WlanFullmacImpl server unbinds. |
| /// |
| /// Common errors include: |
| /// - `ZX_ERR_ALREADY_BOUND`: `Init` was already called on this FullMAC driver. |
| strict Init(resource table { |
| /// The WlanFullmacImplifc client end. |
| /// Required. |
| 1: ifc client_end:WlanFullmacImplIfc; |
| }) -> (resource table { |
| /// The SME server end channel. |
| /// Required. |
| 1: sme_channel zx.Handle:CHANNEL; |
| }) error zx.Status; |
| |
| /// Returns high-level information describing the state of the FullMAC driver. |
| /// This is safe to call even before the call to WlanFullmacImpl::Start. |
| strict Query() -> (table { |
| /// Station address. Required. |
| 1: sta_addr ieee80211.MacAddr; |
| |
| /// MAC role. Required. |
| 2: role fuchsia.wlan.common.WlanMacRole; |
| |
| /// Supported bands. Required. |
| 3: band_caps vector<BandCapability>:fuchsia.wlan.common.MAX_BANDS; |
| }) error zx.Status; |
| |
| strict QuerySecuritySupport() -> (struct { |
| resp fuchsia.wlan.common.SecuritySupport; |
| }) error zx.Status; |
| strict QuerySpectrumManagementSupport() -> (struct { |
| resp fuchsia.wlan.common.SpectrumManagementSupport; |
| }) error zx.Status; |
| strict QueryTelemetrySupport() -> (struct { |
| resp fuchsia.wlan.stats.TelemetrySupport; |
| }) error zx.Status; |
| |
| // MLME operations |
| strict StartScan(table { |
| /// Unique transaction id (will be indicated in corresponding scan results). |
| 1: txn_id uint64; |
| 2: scan_type WlanScanType; |
| /// List of channels to scan on. An empty list of channels will cause a |
| /// scan request to immediately return a OnScanEnd with code INVALID_ARGS. |
| /// |
| /// Invalid channel numbers will be silently ignored. The validity of a channel |
| /// number depends on the current regulatory region, and a FullMAC driver cannot |
| /// always determine the region setting. This is especially the case when |
| /// firmware changes the region setting dynamically. |
| 3: channels vector<uint8>:ieee80211.MAX_UNIQUE_CHANNEL_NUMBERS; |
| /// List of SSIDs to scan for. An empty list of ssids is the same as specifying |
| /// a list containing only the wildcard SSID. |
| /// |
| /// There is no limit on the number of SSIDs specified. A large number of |
| /// SSIDs may result in extended scan times because of hardware limitations on |
| /// the number of SSIDs permitted per scan request and the technical limitation |
| /// in IEEE 802.11-2016 that limits the number of SSIDs in a single Probe Request |
| /// frame to ieee80211.SSID_LIST_MAX SSIDs. |
| 4: ssids vector<ieee80211.Ssid>:MAX; |
| /// Minimum amount of time in msecs spent on a channel during scan. |
| 5: min_channel_time uint32; |
| /// Maximum amount of time in msecs spent on a channel during scan. |
| 6: max_channel_time uint32; |
| }) -> (); |
| strict Connect(table { |
| 1: selected_bss fuchsia.wlan.common.BssDescription; |
| /// Timeout specified in beacon interval. |
| 2: connect_failure_timeout uint32; |
| |
| /// Additional parameters specific to the authentication exchange. |
| 3: auth_type WlanAuthType; |
| /// sae_password is ignored except when SAE_DRIVER_AUTH is enabled and the |
| /// auth_type is SAE. |
| 4: sae_password vector<uint8>:MAX; |
| |
| /// WEP key used in the authentication exchange. |
| /// This is only populated for the WEP security type, otherwise this field is empty. |
| // TODO(https://fxbug.dev/399839691): Will be removed after v/g is updated to use ieee80211.SetKeyDescriptor. |
| 5: wep_key fuchsia.wlan.common.WlanKeyConfig; |
| |
| /// Additional parameters specific to the association exchange. |
| 6: security_ie vector<uint8>:ieee80211.WLAN_IE_MAX_LEN; |
| |
| /// WEP key used in the authentication exchange. |
| /// This is only populated for the WEP security type, otherwise this field is empty. |
| 7: wep_key_desc ieee80211.SetKeyDescriptor; |
| }) -> (); |
| strict Reconnect(table { |
| 1: peer_sta_address ieee80211.MacAddr; |
| }) -> (); |
| /// Initiate a roam attempt, which moves association to a different BSS within the ESS. |
| strict Roam(table { |
| /// Full BSS description of the target BSS. Required. |
| /// If the data in BssDescription is incorrect or incomplete, the roam cannot succeed, |
| /// because higher layers will not be able to complete required actions (e.g. SAE). |
| 1: selected_bss fuchsia.wlan.common.BssDescription; |
| }) -> (); |
| strict AuthResp(table { |
| 1: peer_sta_address ieee80211.MacAddr; |
| 2: result_code WlanAuthResult; |
| }) -> (); |
| strict Deauth(table { |
| 1: peer_sta_address ieee80211.MacAddr; |
| 2: reason_code ieee80211.ReasonCode; |
| }) -> (); |
| strict AssocResp(table { |
| 1: peer_sta_address ieee80211.MacAddr; |
| 2: result_code WlanAssocResult; |
| 3: association_id uint16; |
| }) -> (); |
| strict Disassoc(table { |
| 1: peer_sta_address ieee80211.MacAddr; |
| 2: reason_code ieee80211.ReasonCode; |
| }) -> (); |
| strict StartBss(table { |
| 1: ssid ieee80211.Ssid; |
| 2: bss_type fuchsia.wlan.common.BssType; |
| 3: beacon_period uint32; |
| 4: dtim_period uint32; |
| 5: channel uint8; |
| 6: rsne vector<uint8>:ieee80211.WLAN_IE_MAX_LEN; |
| 7: vendor_ie vector<uint8>:WLAN_VIE_MAX_LEN; |
| }) -> (); |
| strict StopBss(table { |
| 1: ssid ieee80211.Ssid; |
| }) -> (); |
| /// Sets security keys for a connection. This is typically called after a successful key |
| /// exchange. |
| /// |
| /// Note that the platform assumes that the driver will automatically delete keys on a |
| /// disconnect or key rotation. |
| strict SetKeys(table { |
| // TODO(https://fxbug.dev/399839691): keylist will be removed after v/g is updated to use ieee80211.SetKeyDescriptor. |
| 1: keylist vector<fuchsia.wlan.common.WlanKeyConfig>:WLAN_MAX_KEYLIST_SIZE; |
| 2: key_descriptors vector<ieee80211.SetKeyDescriptor>:WLAN_MAX_KEYLIST_SIZE; |
| }) -> (struct { |
| resp WlanFullmacSetKeysResp; |
| }); |
| strict EapolTx(table { |
| 1: src_addr ieee80211.MacAddr; |
| 2: dst_addr ieee80211.MacAddr; |
| 3: data vector<uint8>:MAX; |
| }) -> (); |
| |
| // MLME extensions |
| strict GetIfaceStats() -> (struct { |
| stats fuchsia.wlan.stats.IfaceStats; |
| }) error zx.Status; |
| strict GetIfaceHistogramStats() -> (struct { |
| stats fuchsia.wlan.stats.IfaceHistogramStats; |
| }) error zx.Status; |
| strict GetSignalReport() -> (fuchsia.wlan.stats.SignalReport) error zx.Status; |
| /// Informs the driver of the result of an SAE handshake. |
| strict SaeHandshakeResp(table { |
| /// The peer's MAC address. Required. |
| 1: peer_sta_address ieee80211.MacAddr; |
| /// The status of the SAE handshake. Required. |
| 2: status_code ieee80211.StatusCode; |
| }) -> (); |
| /// Transmit an SAE authentication frame. |
| strict SaeFrameTx(struct { |
| frame SaeFrame; |
| }) -> (); |
| strict WmmStatusReq() -> (); |
| |
| // Notify the interface whether it's online or offline. For client interfaces the online status |
| // changes based on such things as being associated/disassociated with an AP. For encrypted |
| // connections, the interface is considered online after the key exchange completes successfully, |
| // for open connections the interface is considered online as soon as association is confirmed. |
| // |
| // A SoftAP interface is set to online when: |
| // 1) The driver confirms that a request to start a SoftAP succeeded. |
| // A SoftAP interface is set to offline when: |
| // 1) A request to stop a SoftAP is received. |
| // 2) The driver indicates that the SoftAP has stopped (possibly already offline because of 1). |
| // |
| // The call will ONLY be made when the state actually changes. For example in the situation |
| // above where a call to stop an AP has been made there will be a call to OnLinkStateChanged. |
| // However when the driver confirms this there will be no additional call to OnLinkStateChanged |
| // because it was already offline. |
| strict OnLinkStateChanged(table { |
| 1: online bool; |
| }) -> (); |
| }; |
| |
| service Service { |
| wlan_fullmac_impl client_end:WlanFullmacImpl; |
| }; |