Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions drivers/net/wireless/mediatek/mt7932/link.c
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,20 @@ static int mt_connect_attempt(struct mt7932 *m, bool *submitted,
return ret ?: READ_ONCE(m->connect_error);
}

/*
* Once the request has gone to the AP, a timeout, a refusal or a reset while
* the firmware is still healthy is how the AP answered, not a driver or
* firmware fault. cfg80211 hands it to the supplicant, which retries, and
* mac80211 reports the same outcomes at info level. Keep the error level for
* failures that need recovery or point at the firmware.
*/
static bool mt_connect_failed_at_peer(struct mt7932 *m, bool auth_submitted,
int ret)
{
return auth_submitted && !READ_ONCE(m->link_failed) &&
(ret == -ETIMEDOUT || ret == -ECONNREFUSED || ret == -ECONNRESET);
}

void mt_connect_work(struct work_struct *work)
{
struct mt7932 *m = container_of(work, struct mt7932, connect_work);
Expand Down Expand Up @@ -760,6 +774,9 @@ void mt_connect_work(struct work_struct *work)
READ_ONCE(m->data_ready));
else if (cancelled)
dev_dbg(&m->pdev->dev, "CONNECT_CANCELLED: %d\n", ret);
else if (mt_connect_failed_at_peer(m, auth_submitted, ret))
dev_info(&m->pdev->dev, "CONNECT_FAILED: %d; recovery-required=0\n",
ret);
else
dev_err(&m->pdev->dev, "CONNECT_FAILED: %d; recovery-required=%u\n",
ret, READ_ONCE(m->link_failed));
Expand Down
54 changes: 39 additions & 15 deletions tools/asahi/mt7932-connect-result-tests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-only
"""Compile the connect worker's report path and the complete nl80211 encoder."""
"""Compile the connect worker's report path, its log-level helper and the
complete nl80211 encoder."""
from pathlib import Path
import argparse
import hashlib
Expand Down Expand Up @@ -41,9 +42,9 @@
#define spin_unlock(l) ((void)(l))
#define mutex_lock(l) ((void)(l))
#define mutex_unlock(l) ((void)(l))
#define dev_info(...) ((void)0)
#define dev_info(...) ((void)info_logs++)
#define dev_dbg(...) ((void)0)
#define dev_err(...) ((void)0)
#define dev_err(...) ((void)err_logs++)
#define for_each_valid_link(cr,l) for((l)=0;(l)<1;(l)++)
struct sk_buff { unsigned values[32]; bool seen[32]; };
struct nlattr { int n; };
Expand Down Expand Up @@ -75,11 +76,11 @@
static int wiphy_net(int*w){return 0;}
static void genlmsg_multicast_netns(int*f,int n,struct sk_buff*m,int p,int g,gfp_t t){}
ENCODER
struct mt7932 {bool stopping,connect_open,assoc_request_seen,connecting,connected,disconnecting,connect_cancelled,connect_publishing,connect_lost,rf_ready,connect_pmk_valid;
struct mt7932 {bool link_failed,stopping,connect_open,assoc_request_seen,connecting,connected,disconnecting,connect_cancelled,connect_publishing,connect_lost,rf_ready,connect_pmk_valid;
int connect_error,response_lock,command_mutex,data_lock,wiphy,power_work;u16 disconnect_reason;struct net_device *netdev;struct cfg80211_bss *connect_bss;u8 connect_bssid[6],connect_pmk[32],connect_sae_pwd[63],connect_sae_pwd_length,assoc_request_ies[512];unsigned assoc_request_ie_len;
struct {struct {bool ht_supported;}ht_cap;}band2;bool power_tim,data_ready,station_signal_valid,station_rx_rate_valid,station_tx_rate_valid;unsigned long station_tx_bytes,station_rx_bytes,station_tx_packets,station_rx_packets,station_connected;};
static unsigned long jiffies=1;
static unsigned notifications,disconnections,retirements,releases,authorizations,carrier,work_count;
static unsigned info_logs,err_logs,notifications,disconnections,retirements,releases,authorizations,carrier,work_count;
static struct cfg80211_connect_resp_params saved;
static bool mt_rf_allowed(struct mt7932*m){return m->rf_ready;}
static void mt_transport_snapshot(struct mt7932*m){}
Expand All @@ -96,16 +97,22 @@
static void netif_carrier_on(struct net_device*n){carrier++;}
static void netif_wake_queue(struct net_device*n){}
static void cfg80211_port_authorized(struct net_device*n,const u8*b,const u8*p,size_t l,gfp_t f){authorizations++;}
static void report_worker(struct mt7932 *m,int ret,bool retirement_attempted){
HELPER
static void report_worker(struct mt7932 *m,int ret,bool retirement_attempted,bool auth_submitted){
struct cfg80211_connect_resp_params response={};unsigned long flags;bool submitted=true,peer_owned=true,cancelled;u16 reason;
REPORT
int main(void){struct net_device n={1};struct cfg80211_bss b={};
int errors[]={0,-ETIMEDOUT,-ECONNREFUSED,-EPROTO,-ECANCELED,-ECONNRESET,-EIO};
for(unsigned i=0;i<sizeof(errors)/sizeof(*errors);i++){
struct mt7932 m={.connecting=true,.rf_ready=true,.netdev=&n,.connect_bss=&b,.data_ready=true};
notifications=disconnections=retirements=authorizations=carrier=work_count=0;
for(unsigned i=0;i<sizeof(errors)/sizeof(*errors);i++)for(unsigned k=0;k<4;k++){
bool auth=k&1,failed=k&2;
struct mt7932 m={.connecting=true,.rf_ready=true,.netdev=&n,.connect_bss=&b,.data_ready=true,.link_failed=failed};
info_logs=err_logs=notifications=disconnections=retirements=authorizations=carrier=work_count=0;
memset(m.connect_pmk,0x5a,sizeof(m.connect_pmk));memset(m.connect_sae_pwd,0x5a,sizeof(m.connect_sae_pwd));m.connect_sae_pwd_length=63;m.connect_pmk_valid=true;
report_worker(&m,errors[i],false);
report_worker(&m,errors[i],false,auth);
// Only an AP-side outcome (timeout, refusal, reset) of a request that
// reached the AP, with the firmware healthy, is logged at info level.
bool peer=auth&&!failed&&(errors[i]==-ETIMEDOUT||errors[i]==-ECONNREFUSED||errors[i]==-ECONNRESET);
assert(info_logs==(errors[i]&&peer)&&err_logs==(errors[i]&&!peer));
for(unsigned j=0;j<sizeof(m.connect_pmk);j++)assert(!m.connect_pmk[j]);
for(unsigned j=0;j<sizeof(m.connect_sae_pwd);j++)assert(!m.connect_sae_pwd[j]);
assert(!m.connect_sae_pwd_length&&!m.connect_pmk_valid);assert(notifications==1&&disconnections==0);
Expand All @@ -120,24 +127,37 @@
// Cancellation consumes the BSS and reports disconnect, not a connect result.
struct mt7932 m={.connecting=true,.rf_ready=true,.netdev=&n,.connect_bss=&b,.connect_cancelled=true,.connect_error=-ECANCELED};
notifications=disconnections=retirements=authorizations=carrier=0;
report_worker(&m,0,false);assert(notifications==0&&disconnections==1&&retirements==1&&!m.connected);assert(authorizations==0&&carrier==0);
info_logs=err_logs=0;
report_worker(&m,0,false,true);assert(!info_logs&&!err_logs);assert(notifications==0&&disconnections==1&&retirements==1&&!m.connected);assert(authorizations==0&&carrier==0);
// A stale success cannot publish carrier after a terminal error.
m=(struct mt7932){.connecting=true,.rf_ready=true,.netdev=&n,.connect_bss=&b,.connect_error=-ECONNRESET};
notifications=disconnections=retirements=authorizations=carrier=0;
report_worker(&m,0,false);assert(saved.status==1&&notifications==1&&retirements==1&&!m.connected&&!encoded.seen[NL80211_ATTR_TIMED_OUT]);assert(authorizations==0&&carrier==0);
info_logs=err_logs=0;
report_worker(&m,0,false,true);assert(info_logs==1&&!err_logs);assert(saved.status==1&&notifications==1&&retirements==1&&!m.connected&&!encoded.seen[NL80211_ATTR_TIMED_OUT]);assert(authorizations==0&&carrier==0);
// Failed retry retirement retains ownership and is not attempted again.
m=(struct mt7932){.connecting=true,.rf_ready=true,.netdev=&n,.connect_bss=&b};
notifications=disconnections=retirements=releases=authorizations=carrier=0;
report_worker(&m,-EIO,true);
info_logs=err_logs=0;
report_worker(&m,-EIO,true,true);assert(!info_logs&&err_logs==1);
assert(saved.status==1&&notifications==1&&!retirements&&!releases&&!m.connected);
assert(!authorizations&&!carrier);
// Already-known IEEE AP status is preserved by the complete netlink encoder.
struct cfg80211_registered_device r={};struct cfg80211_connect_resp_params ap={.status=17};
nl80211_send_connect_result(&r,&n,&ap,0);assert(encoded.values[NL80211_ATTR_STATUS_CODE]==17&&!encoded.seen[NL80211_ATTR_TIMED_OUT]);
puts("PASS 11 connect report and nl80211 timeout/rejection/cancellation controls");}
puts("PASS 12 connect report, info-vs-error log level and nl80211 timeout/rejection/cancellation controls");}
'''


def peer_helper(source):
"""mt_connect_failed_at_peer(), which picks the report's log level; empty
for an older driver that has none."""
marker = 'static bool mt_connect_failed_at_peer('
if marker not in source:
return ''
start = source.index(marker)
return source[start:source.index('\n}\n', start) + 3]


def main():
parser = argparse.ArgumentParser()
parser.add_argument('--source-root', type=Path, default=ROOT)
Expand All @@ -149,6 +169,7 @@ def main():
start = source.index('report:\n', source.index('void mt_connect_work('))
end = source.index('\n/* Narrow ordinary OPEN', start)
report = source[start:end]
helper = peer_helper(source)
net = (root/'net/wireless/nl80211.c').read_text()
start = net.index('void nl80211_send_connect_result(')
end = net.index('\nvoid nl80211_send_roamed(', start)
Expand All @@ -157,15 +178,18 @@ def main():
out = args.output or Path(temporary)
out.mkdir(parents=True, exist_ok=True)
cases = {'fixed': report}
helpers = {'fixed': helper}
if args.old_source:
old = args.old_source.read_text()
start = old.index('report:\n', old.index('void mt_connect_work('))
end = old.index('\n/* Narrow ordinary OPEN', start)
cases['old'] = old[start:end]
helpers['old'] = peer_helper(old)
results = {}
for name, body in cases.items():
c = out/(name+'.c')
c.write_text(PREFIX.replace('ENCODER', encoder).replace('REPORT', body))
c.write_text(PREFIX.replace('ENCODER', encoder).replace('HELPER', helpers[name])
.replace('REPORT', body))
binary = out/name
subprocess.run(['cc','-std=gnu11','-Wall','-Werror','-Wno-unused-parameter',
'-Wno-unused-function','-I/usr/include',str(c),'-o',str(binary)], check=True)
Expand Down
Loading