{"id":2219011,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2219011/?format=json","web_url":"http://patchwork.ozlabs.org/project/hostap/patch/20260402095356.1401176-8-allen.ye@mediatek.com/","project":{"id":22,"url":"http://patchwork.ozlabs.org/api/1.1/projects/22/?format=json","name":"HostAP Development","link_name":"hostap","list_id":"hostap.lists.infradead.org","list_email":"hostap@lists.infradead.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260402095356.1401176-8-allen.ye@mediatek.com>","date":"2026-04-02T09:53:56","name":"[v11,7/7] tests: Add AFC hwsim tests","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"60bea1c9cb2dd7d425ce5aa02d1e6a3384d4e0d1","submitter":{"id":86975,"url":"http://patchwork.ozlabs.org/api/1.1/people/86975/?format=json","name":"Allen Ye","email":"Allen.Ye@mediatek.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/hostap/patch/20260402095356.1401176-8-allen.ye@mediatek.com/mbox/","series":[{"id":498460,"url":"http://patchwork.ozlabs.org/api/1.1/series/498460/?format=json","web_url":"http://patchwork.ozlabs.org/project/hostap/list/?series=498460","date":"2026-04-02T09:53:56","name":"Introduce Automated Frequency Coordination (AFC) support","version":11,"mbox":"http://patchwork.ozlabs.org/series/498460/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2219011/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2219011/checks/","tags":{},"headers":{"Return-Path":"\n <hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n secure) header.d=lists.infradead.org header.i=@lists.infradead.org\n header.a=rsa-sha256 header.s=bombadil.20210309 header.b=yykuZgMd;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n secure) header.d=infradead.org header.i=@infradead.org header.a=rsa-sha256\n header.s=desiato.20200630 header.b=eFjc5H5t;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.d=mediatek.com header.i=@mediatek.com header.a=rsa-sha256\n header.s=dk header.b=b5PfXXmf;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=none (no SPF record) smtp.mailfrom=lists.infradead.org\n (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org;\n envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org;\n receiver=patchwork.ozlabs.org)"],"Received":["from bombadil.infradead.org (bombadil.infradead.org\n [IPv6:2607:7c80:54:3::133])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fmcfV2283z1yGJ\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 02 Apr 2026 20:55:10 +1100 (AEDT)","from localhost ([::1] helo=bombadil.infradead.org)\n\tby bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux))\n\tid 1w8El7-0000000HK22-24wA;\n\tThu, 02 Apr 2026 09:54:41 +0000","from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05])\n\tby bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux))\n\tid 1w8El6-0000000HK1K-0Y0V\n\tfor hostap@bombadil.infradead.org;\n\tThu, 02 Apr 2026 09:54:40 +0000","from mailgw01.mediatek.com ([216.200.240.184])\n\tby desiato.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux))\n\tid 1w8El2-00000002Ayi-2yZf\n\tfor hostap@lists.infradead.org;\n\tThu, 02 Apr 2026 09:54:38 +0000","from mtkmbs11n1.mediatek.inc [(172.21.101.185)] by\n mailgw01.mediatek.com\n\t(envelope-from <allen.ye@mediatek.com>)\n\t(musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384\n 256/256)\n\twith ESMTP id 848755624; Thu, 02 Apr 2026 02:54:25 -0700","from mtkmbs13n2.mediatek.inc (172.21.101.108) by\n mtkmbs11n2.mediatek.inc (172.21.101.187) with Microsoft SMTP Server\n (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n 15.2.2562.29; Thu, 2 Apr 2026 17:54:22 +0800","from mtksitap99.mediatek.inc (10.233.130.16) by\n mtkmbs13n2.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id\n 15.2.2562.29 via Frontend Transport; Thu, 2 Apr 2026 17:54:22 +0800"],"DKIM-Signature":["v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;\n\td=lists.infradead.org; s=bombadil.20210309; h=Sender:\n\tContent-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post:\n\tList-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:\n\tMessage-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description:\n\tResent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:\n\tList-Owner; bh=7xjAg2PU4rGqr6V5eYrseMYg+X1pAVni9JFRQwpALvg=; b=yykuZgMdHJ9ixf\n\tOUQ0AxVaawirHxEk4R+cMpph2kBjPiIo25ntAThEiP7xai9cBKUtLS7MKaaGwXLzAr6LtbB13S7iR\n\tCYNOPiNZVbxrihteShL9dXzRF8ah7lkV8d5mB1SNHpuv7U5cYv3Ktovw/VfqQxXTN23xIot4iZMG2\n\tChrEOMCz06anvJiwuA8++Ph1MHWOAEzUDXKyuTRaW5jnSbJnbLMKuBnReKcsHK1WRESyXAa8JJlwM\n\tfrtt0pUxo1tfk0kSxodIiIc0atf/x1zNmFo9Uwkae7SqwSRmB7phxO63odW+kF/1ebxl63C4DFmHP\n\t47jMDKlcO3x4ZEeHXK8w==;","v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;\n\td=infradead.org; s=desiato.20200630; h=Content-Type:Content-Transfer-Encoding\n\t:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From:\n\tSender:Reply-To:Content-ID:Content-Description;\n\tbh=c35WxkVOJ3FaN6UMPUkmxK5nJv030WmsnhZpRyKJZ4g=; b=eFjc5H5teeqysn2ZOfy9XTGCAo\n\tUhagTlc6h34c9TBcIH0pnT4J7TLgL7cWjhnLyAM/zZ06ERKBBsklgUjgZZDsQekHqsGHpVl6UvHJC\n\tab3VeL4Lw6RFDzKYeJTmYx7VSqy9BnQ0KuAO1Cw1i3Z45IXuizJXp55lWMDpEKxzkN/WVkGExhTlE\n\t24+Hyj4aDyZjnlHDYU+f5muA38F+h9UVJPc7kDB5n0lkZrC/QBgu0pLMO3XUmOrPMAhEGlPuOeZoO\n\ts1d1+JnSxzZCMdvV9gfbXuK6eozyozzFwc6yhTn0IiSAXl7pZ1nWKb1HPIQDQdSkhZ+wTadl5hFDm\n\tnrFD9EPA==;","v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;\n d=mediatek.com; s=dk;\n\th=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From;\n bh=c35WxkVOJ3FaN6UMPUkmxK5nJv030WmsnhZpRyKJZ4g=;\n\tb=b5PfXXmfwiOPo8bE1CEudaonuQhH+Rh3R8dRx3udGb1XZ9GT+nDiO9FkrDo3on0/oTeynMNmSrCJALKG3+ZMIwCTR6ok5B3zIbDdUwOtY3aPhsgHWZ2W6yz2QRQXhsRz9q/tsW8jaeHG0c0mSCKgey8B8zeH1ZfiQU+qTc24/Jg=;"],"X-UUID":["ee66df6c2e7911f19e7563141e833ce8-20260402","ee66df6c2e7911f19e7563141e833ce8-20260402"],"X-CID-P-RULE":"Release_Ham","X-CID-O-INFO":"VERSION:1.3.12,REQID:bd291ba5-cb0f-4ab6-9f39-2f683a609b1e,IP:0,U\n\tRL:0,TC:0,Content:33,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION\n\t:release,TS:33","X-CID-META":"VersionHash:e7bac3a,CLOUDID:26fafd8e-6df4-4a3d-a7a4-fbdc42d669ce,B\n\tulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102|836|865|888|898,TC:-5,Cont\n\tent:4|15|50,EDM:-3,IP:nil,URL:0,File:130,RT:0,Bulk:nil,QS:nil,BEC:-1,COL:0\n\t,OSI:0,OSA:0,AV:0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0","X-CID-BVR":"2,SSN|SDN","X-CID-BAS":"2,SSN|SDN,0,_","X-CID-FACTOR":"TF_CID_SPAM_SNR","X-CID-RHF":"D41D8CD98F00B204E9800998ECF8427E","From":"Allen Ye <allen.ye@mediatek.com>","To":"Jouni Malinen <j@w1.fi>","CC":"<hostap@lists.infradead.org>, Felix Fietkau <nbd@nbd.name>, Evelyn Tsai\n\t<evelyn.tsai@mediatek.com>, \"Mark-MC . Lee\" <mark-mc.lee@mediatek.com>, Tarun\n Radhakrishnan <tarun.r@tataelxsi.co.in>, Allen Ye <allen.ye@mediatek.com>","Subject":"[PATCH v11 7/7] tests: Add AFC hwsim tests","Date":"Thu, 2 Apr 2026 17:53:56 +0800","Message-ID":"<20260402095356.1401176-8-allen.ye@mediatek.com>","X-Mailer":"git-send-email 2.45.2","In-Reply-To":"<20260402095356.1401176-1-allen.ye@mediatek.com>","References":"<20260402095356.1401176-1-allen.ye@mediatek.com>","MIME-Version":"1.0","X-MTK":"N","X-CRM114-Version":"20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 ","X-CRM114-CacheID":"sfid-20260402_105437_323023_B56DDA8C ","X-CRM114-Status":"GOOD (  17.55  )","X-Spam-Score":"2.8 (++)","X-Spam-Report":"Spam detection software,\n running on the system \"desiato.infradead.org\",\n has NOT identified this incoming email as spam.  The original\n message has been attached to this so you can view it or label\n similar future email.  If you have any questions, see\n the administrator of that system for details.\n Content preview:  Add hwsim test with a mock AFCD and AFC response to verify\n    the Automated Frequency Coordination (AFC) feature. Signed-off-by: Allen\n   Ye <allen.ye@mediatek.com> --- tests/hwsim/example-hostapd.config | 1 +\n tests/hwsim/test_afc.py\n    | 335 +++++++++++++++++++++++++++++ 2 files changed,\n 336 insertions(+) create\n    mode [...]\n Content analysis details:   (2.8 points, 5.0 required)\n  pts rule name              description\n ---- ----------------------\n --------------------------------------------------\n  1.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to\n                              Validity was blocked.  See\n                             https://knowledge.validity.com/hc/en-us/articles/20961730681243\n                              for more information.\n                           [216.200.240.184 listed in\n bl.score.senderscore.com]\n  1.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to\n                              Validity was blocked.  See\n                             https://knowledge.validity.com/hc/en-us/articles/20961730681243\n                              for more information.\n                             [216.200.240.184 listed in\n sa-accredit.habeas.com]\n  1.0 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED RBL: ADMINISTRATOR NOTICE: The\n                             query to Validity was blocked.  See\n                             https://knowledge.validity.com/hc/en-us/articles/20961730681243\n                              for more information.\n                        [216.200.240.184 listed in\n sa-trusted.bondedsender.org]\n -0.0 SPF_PASS               SPF: sender matches SPF record\n -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record\n  0.1 DKIM_SIGNED            Message has a DKIM or DK signature,\n not necessarily valid\n -0.1 DKIM_VALID_EF          Message has a valid DKIM or DK signature from\n                             envelope-from domain\n -0.1 DKIM_VALID_AU          Message has a valid DKIM or DK signature from\n author's\n                             domain\n -0.1 DKIM_VALID             Message has at least one valid DKIM or DK\n signature\n  0.0 UNPARSEABLE_RELAY      Informational: message has unparseable relay\n lines","X-BeenThere":"hostap@lists.infradead.org","X-Mailman-Version":"2.1.34","Precedence":"list","List-Id":"<hostap.lists.infradead.org>","List-Unsubscribe":"<http://lists.infradead.org/mailman/options/hostap>,\n <mailto:hostap-request@lists.infradead.org?subject=unsubscribe>","List-Archive":"<http://lists.infradead.org/pipermail/hostap/>","List-Post":"<mailto:hostap@lists.infradead.org>","List-Help":"<mailto:hostap-request@lists.infradead.org?subject=help>","List-Subscribe":"<http://lists.infradead.org/mailman/listinfo/hostap>,\n <mailto:hostap-request@lists.infradead.org?subject=subscribe>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Sender":"\"Hostap\" <hostap-bounces@lists.infradead.org>","Errors-To":"hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org"},"content":"Add hwsim test with a mock AFCD and AFC response to verify the\nAutomated Frequency Coordination (AFC) feature.\n\nSigned-off-by: Allen Ye <allen.ye@mediatek.com>\n---\n tests/hwsim/example-hostapd.config |   1 +\n tests/hwsim/test_afc.py            | 335 +++++++++++++++++++++++++++++\n 2 files changed, 336 insertions(+)\n create mode 100644 tests/hwsim/test_afc.py","diff":"diff --git a/tests/hwsim/example-hostapd.config b/tests/hwsim/example-hostapd.config\nindex 41611b0f2..982508ec0 100644\n--- a/tests/hwsim/example-hostapd.config\n+++ b/tests/hwsim/example-hostapd.config\n@@ -128,3 +128,4 @@ CONFIG_PROCESS_COORDINATION=y\n CONFIG_ENC_ASSOC=y\n CONFIG_PMKSA_PRIVACY=y\n CONFIG_IEEE8021X_AUTH=y\n+CONFIG_AFC=y\ndiff --git a/tests/hwsim/test_afc.py b/tests/hwsim/test_afc.py\nnew file mode 100644\nindex 000000000..110556517\n--- /dev/null\n+++ b/tests/hwsim/test_afc.py\n@@ -0,0 +1,335 @@\n+# AFC tests\n+# Copyright (c) 2025, MediaTek Corporation\n+#\n+# This software may be distributed under the terms of the BSD license.\n+# See README for more details.\n+\n+import logging\n+logger = logging.getLogger()\n+import os\n+import threading\n+from datetime import datetime, timedelta\n+import socket\n+import json\n+\n+import hwsim_utils\n+import hostapd\n+from utils import *\n+\n+class AFCDServer:\n+    def __init__(self):\n+        self.path = '/tmp/afcd.sock'\n+        if os.path.exists(self.path):\n+            os.remove(self.path)\n+        self.s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)\n+        self.s.bind(self.path)\n+        self.s.listen(1)\n+\n+    def listen_reply(self, freq_info, chan_info):\n+        if freq_info is None:\n+            freq_info = []\n+        if chan_info is None:\n+            chan_info = []\n+\n+        try:\n+            self.s.settimeout(1)\n+            self.conn, _ = self.s.accept()\n+        except Exception as e:\n+            logger.info(\"hostapd failed to connect to afcd\")\n+            self.close()\n+            if os.path.exists(self.path):\n+                os.unlink(self.path)\n+            return\n+\n+        try:\n+            req_raw = self.conn.recv(8192).decode()\n+        except socket.timeout:\n+            logger.info(\"AFCD failed to get request\")\n+            req_raw = None\n+        if req_raw:\n+            logger.info(f\"Received: {req_raw}\")\n+            if 'availableSpectrumInquiryRequests' in req_raw:\n+                try:\n+                    req_json = json.loads(req_raw)\n+                    requestId = req_json[\"availableSpectrumInquiryRequests\"][0][\"requestId\"]\n+                except Exception as e:\n+                    logger.info(f\"Failed to parse requestId: {e}\")\n+                    self.close()\n+\n+                expire_time = (datetime.now() + timedelta(hours=24)).strftime(\"%Y-%m-%dT%H:%M:%SZ\")\n+\n+                resp = {\n+                    \"availableSpectrumInquiryResponses\": [\n+                        {\n+                            \"response\": {\n+                                \"responseCode\": 0,\n+                                \"shortDescription\": \"SUCCESS\"\n+                            },\n+                            \"availableFrequencyInfo\": freq_info,\n+                            \"availableChannelInfo\": chan_info,\n+                            \"requestId\": requestId,\n+                            \"availabilityExpireTime\": expire_time,\n+                            \"rulesetId\": \"US_47_CFR_PART_15_SUBPART_E\"\n+                        }\n+                    ],\n+                    \"version\": \"1.4\"\n+                }\n+                reply = json.dumps(resp)\n+                self.conn.sendall(reply.encode())\n+                logger.info(f\"response Sent: {reply}\")\n+\n+    def __del__(self):\n+        self.close()\n+\n+    def close(self):\n+        self.s.close()\n+\n+def run_afcd_server(freq_info=None, chan_info=None):\n+    server = AFCDServer()\n+    server.listen_reply(freq_info, chan_info)\n+    server.close()\n+\n+def init_afc_dut_params():\n+    params = {\"country_code\": \"CA\",\n+              \"hw_mode\": \"a\",\n+              \"ssid\": \"AFC\",\n+              \"ieee80211ax\": \"1\",\n+              \"wpa\": \"2\",\n+              \"rsn_pairwise\": \"CCMP\",\n+              \"wpa_key_mgmt\": \"SAE\",\n+              \"sae_pwe\": \"1\",\n+              \"sae_password\": \"password\",\n+              \"ieee80211w\": \"2\",\n+              \"afcd_sock\": \"/tmp/afcd.sock\",\n+              \"afc_request_version\": \"1.4\",\n+              \"afc_serial_number\": \"SN000\",\n+              \"afc_cert_ids\": \"US_47_CFR_PART_15_SUBPART_E:CID000\",\n+              \"afc_location_type\": \"0\",\n+              \"afc_linear_polygon\": \"-121.98586998164663:37.38193354300452\",\n+              \"afc_radial_polygon\": \"118.8:92.76,76.44:87.456,98.56:123.33\",\n+              \"afc_major_axis\": \"150\",\n+              \"afc_minor_axis\": \"150\",\n+              \"afc_orientation\": \"0\",\n+              \"afc_height\": \"15\",\n+              \"afc_height_type\": \"AGL\",\n+              \"afc_vertical_tolerance\": \"2\",\n+              \"afc_freq_range\": \"5925:6425,6525:6875\",\n+              \"afc_op_class\": \"131,132,133,134,136,137\"\n+              }\n+    return params\n+\n+def test_afc_empty(dev, apdev):\n+    \"\"\"AFC server with no usable channel\"\"\"\n+\n+    dev[0].cmd_execute(['iw', 'reg', 'set', 'CA'])\n+    wait_regdom_changes(dev[0])\n+    try:\n+        t = threading.Thread(target=run_afcd_server)\n+        t.start()\n+\n+        hapd = None\n+        params = init_afc_dut_params()\n+        params[\"he_6ghz_reg_pwr_type\"] = \"1\"\n+        params[\"channel\"] = \"5\"\n+        params[\"op_class\"] = \"131\"\n+\n+        if not he_6ghz_supported():\n+            raise HwsimSkip(\"6 GHz frequency is not supported\")\n+\n+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)\n+        if hapd.get_status_field(\"state\") != \"COUNTRY_UPDATE\":\n+            raise Exception(\"Unexpected interface state - expected COUNTRY_UPDATE\")\n+    except Exception as e:\n+        if isinstance(e, Exception) and \\\n+            str(e) == \"Failed to set hostapd parameter afcd_sock\":\n+            raise HwsimSkip(\"AFC is not supported\")\n+        raise\n+    finally:\n+        t.join()\n+        clear_regdom(hapd, dev)\n+\n+def _test_afc(dev, apdev, freq_info, chan_info, channel, op_class, ccfs1):\n+    check_sae_capab(dev[0])\n+    dev[0].cmd_execute(['iw', 'reg', 'set', 'CA'])\n+    wait_regdom_changes(dev[0])\n+\n+    try:\n+        t = threading.Thread(target=run_afcd_server, args=(freq_info, chan_info))\n+        t.start()\n+\n+        hapd = None\n+        params = init_afc_dut_params()\n+        params[\"he_6ghz_reg_pwr_type\"] = \"1\"\n+        params[\"channel\"] = str(channel)\n+        params[\"op_class\"] = str(op_class)\n+\n+        if op_class == 137:\n+            if ccfs1 > channel:\n+                he_ccfs1 = ccfs1 - 16\n+            else:\n+                he_ccfs1 = ccfs1 + 16\n+            params[\"he_oper_centr_freq_seg0_idx\"] = str(he_ccfs1)\n+            params[\"ieee80211be\"] = \"1\"\n+            params[\"eht_oper_centr_freq_seg0_idx\"] = str(ccfs1)\n+        else:\n+            params[\"he_oper_centr_freq_seg0_idx\"] = str(ccfs1)\n+\n+        if not he_6ghz_supported():\n+            raise HwsimSkip(\"6 GHz frequency is not supported\")\n+        if op_class == 137 and not eht_320mhz_supported():\n+            raise HwsimSkip(\"320 MHz channels are not supported\")\n+\n+        hapd = hostapd.add_ap(apdev[0], params)\n+\n+        status = hapd.get_status()\n+        logger.info(\"hostapd STATUS: \" + str(status))\n+        if hapd.get_status_field(\"ieee80211ax\") != \"1\":\n+            raise Exception(\"STATUS did not indicate ieee80211ax=1\")\n+\n+        freq = hapd.get_status_field(\"freq\")\n+        if int(freq) < 5955:\n+            raise Exception(\"Unexpected frequency: \" + freq)\n+\n+        dev[0].set(\"sae_pwe\", \"1\")\n+        dev[0].set(\"sae_groups\", \"\")\n+\n+        dev[0].connect(\"AFC\", key_mgmt=\"SAE\", sae_password=\"password\", ieee80211w=\"2\",\n+                       scan_freq=freq)\n+        hwsim_utils.test_connectivity(dev[0], hapd)\n+\n+        sta = hapd.get_sta(dev[0].own_addr())\n+        if 'supp_op_classes' not in sta:\n+            raise Exception(\"supp_op_classes not indicated\")\n+        supp_op_classes = binascii.unhexlify(sta['supp_op_classes'])\n+        if op_class not in supp_op_classes:\n+            raise Exception(\"STA did not indicate support for opclass %d\" % op_class)\n+\n+        dev[0].request(\"DISCONNECT\")\n+        dev[0].wait_disconnected()\n+        hapd.wait_sta_disconnect()\n+        hapd.disable()\n+\n+    except Exception as e:\n+        if isinstance(e, Exception) and \\\n+            str(e) == \"Failed to set hostapd parameter afcd_sock\":\n+            raise HwsimSkip(\"AFC is not supported\")\n+        raise\n+\n+    finally:\n+        t.join()\n+        dev[0].set(\"sae_pwe\", \"0\")\n+        clear_regdom(hapd, dev)\n+\n+def afc_gen_freq_info(freq, max_psd):\n+    high = freq + 10\n+    low = freq - 10\n+    ranges = {\n+        \"frequencyRange\": {\n+            \"highFrequency\": high,\n+            \"lowFrequency\": low\n+        },\n+        \"maxPsd\": max_psd\n+    }\n+    return ranges\n+\n+# Make current channel unusable to force using acs\n+def test_afc_freq_20mhz(dev, apdev):\n+    \"\"\"AFC availableFrequencyInfo with 20 MHz channel width usable\"\"\"\n+    freq_info = [afc_gen_freq_info(5975, 10.0)]\n+    _test_afc(dev, apdev, freq_info, None, 5, 131, 5)\n+\n+def test_afc_freq_40mhz(dev, apdev):\n+    \"\"\"AFC availableFrequencyInfo with 40 MHz channel width usable\"\"\"\n+    freq_info = [afc_gen_freq_info(5955, 10.0), afc_gen_freq_info(5975, 10.0)]\n+    _test_afc(dev, apdev, freq_info, None, 5, 132, 3)\n+\n+def test_afc_freq_80mhz(dev, apdev):\n+    \"\"\"AFC availableFrequencyInfo with 80 MHz channel width usable\"\"\"\n+    freq_info = [afc_gen_freq_info(5955, 10.0), afc_gen_freq_info(5975, 10.0),\n+                 afc_gen_freq_info(5995, 10.0), afc_gen_freq_info(6015, 10.0)]\n+    _test_afc(dev, apdev, freq_info, None, 5, 133, 7)\n+\n+def test_afc_freq_160mhz(dev, apdev):\n+    \"\"\"AFC availableFrequencyInfo with 160 MHz channel width usable\"\"\"\n+    freq_info = [afc_gen_freq_info(5955, 10.0), afc_gen_freq_info(5975, 10.0),\n+                 afc_gen_freq_info(5995, 10.0), afc_gen_freq_info(6015, 10.0),\n+                 afc_gen_freq_info(6035, 10.0), afc_gen_freq_info(6055, 10.0),\n+                 afc_gen_freq_info(6075, 10.0), afc_gen_freq_info(6095, 10.0)]\n+    _test_afc(dev, apdev, freq_info, None, 5, 134, 15)\n+\n+def test_afc_freq_320mhz_1(dev, apdev):\n+    \"\"\"AFC availableFrequencyInfo with 320 MHz-1 channel width usable\"\"\"\n+    freq_info = [afc_gen_freq_info(5955, 10.0), afc_gen_freq_info(5975, 10.0),\n+                 afc_gen_freq_info(5995, 10.0), afc_gen_freq_info(6015, 10.0),\n+                 afc_gen_freq_info(6035, 10.0), afc_gen_freq_info(6055, 10.0),\n+                 afc_gen_freq_info(6075, 10.0), afc_gen_freq_info(6095, 10.0),\n+                 afc_gen_freq_info(6115, 10.0), afc_gen_freq_info(6135, 10.0),\n+                 afc_gen_freq_info(6155, 10.0), afc_gen_freq_info(6175, 10.0),\n+                 afc_gen_freq_info(6195, 10.0), afc_gen_freq_info(6215, 10.0),\n+                 afc_gen_freq_info(6235, 10.0), afc_gen_freq_info(6255, 10.0)]\n+    _test_afc(dev, apdev, freq_info, None, 5, 137, 31)\n+\n+def test_afc_freq_320mhz_2(dev, apdev):\n+    \"\"\"AFC availableFrequencyInfo with 320 MHz-2 channel width usable\"\"\"\n+    freq_info = [afc_gen_freq_info(6115, 10.0), afc_gen_freq_info(6135, 10.0),\n+                 afc_gen_freq_info(6155, 10.0), afc_gen_freq_info(6175, 10.0),\n+                 afc_gen_freq_info(6195, 10.0), afc_gen_freq_info(6215, 10.0),\n+                 afc_gen_freq_info(6235, 10.0), afc_gen_freq_info(6255, 10.0),\n+                 afc_gen_freq_info(6275, 10.0), afc_gen_freq_info(6295, 10.0),\n+                 afc_gen_freq_info(6315, 10.0), afc_gen_freq_info(6335, 10.0),\n+                 afc_gen_freq_info(6355, 10.0), afc_gen_freq_info(6375, 10.0),\n+                 afc_gen_freq_info(6395, 10.0), afc_gen_freq_info(6415, 10.0)]\n+    _test_afc(dev, apdev, freq_info, None, 37, 137, 63)\n+\n+\n+def afc_gen_chan_info(chan, op_class, eirp):\n+    chan_info = {\n+        \"channelCfi\": chan,\n+        \"globalOperatingClass\": op_class,\n+        \"maxEirp\": [eirp] * len(chan)\n+    }\n+    return chan_info\n+\n+def test_afc_chan_20mhz(dev, apdev):\n+    \"\"\"AFC availableChannelInfo with 20 MHz channel width usable\"\"\"\n+    chan_info = [afc_gen_chan_info([5], 131, 23.0)]\n+    _test_afc(dev, apdev, None, chan_info, 5, 131, 5)\n+\n+def test_afc_chan_40mhz(dev, apdev):\n+    \"\"\"AFC availableChannelInfo with 40 MHz channel width usable\"\"\"\n+    chan_info = [afc_gen_chan_info([1, 5], 131, 23.0),\n+                 afc_gen_chan_info([3], 132, 26.0)]\n+    _test_afc(dev, apdev, None, chan_info, 5, 132, 3)\n+\n+def test_afc_chan_80mhz(dev, apdev):\n+    \"\"\"AFC availableChannelInfo with 80 MHz channel width usable\"\"\"\n+    chan_info = [afc_gen_chan_info([1, 5, 9, 13], 131, 23.0),\n+                 afc_gen_chan_info([3, 11], 132, 26.0),\n+                 afc_gen_chan_info([7], 133, 29.0)]\n+    _test_afc(dev, apdev, None, chan_info, 5, 133, 7)\n+\n+def test_afc_chan_160mhz(dev, apdev):\n+    \"\"\"AFC availableChannelInfo with 160 MHz channel width usable\"\"\"\n+    chan_info = [afc_gen_chan_info([1, 5, 9, 13, 17, 21, 25, 29], 131, 23.0),\n+                 afc_gen_chan_info([3, 11, 19, 27], 132, 26.0),\n+                 afc_gen_chan_info([7, 23], 133, 29.0),\n+                 afc_gen_chan_info([15], 134, 32.0)]\n+    _test_afc(dev, apdev, None, chan_info, 5, 134, 15)\n+\n+def test_afc_chan_320mhz_1(dev, apdev):\n+    \"\"\"AFC availableChannelInfo with 320 MHz-1 channel width usable\"\"\"\n+    chan_info = [afc_gen_chan_info([1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61], 131, 23.0),\n+                 afc_gen_chan_info([3, 11, 19, 27, 35, 43, 51, 59], 132, 26.0),\n+                 afc_gen_chan_info([7, 23, 39, 55], 133, 29.0),\n+                 afc_gen_chan_info([15, 47], 134, 32.0),\n+                 afc_gen_chan_info([31], 137, 35.0)]\n+    _test_afc(dev, apdev, None, chan_info, 5, 137, 31)\n+\n+def test_afc_chan_320mhz_2(dev, apdev):\n+    \"\"\"AFC availableChannelInfo with 320 MHz-2 channel width usable\"\"\"\n+    chan_info = [afc_gen_chan_info([33, 37, 41, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93], 131, 23.0),\n+                 afc_gen_chan_info([35, 43, 51, 59, 67, 75, 83, 91], 132, 26.0),\n+                 afc_gen_chan_info([39, 55, 71, 87], 133, 29.0),\n+                 afc_gen_chan_info([47, 79], 134, 32.0),\n+                 afc_gen_chan_info([63], 137, 35.0)]\n+    _test_afc(dev, apdev, None, chan_info, 37, 137, 63)\n","prefixes":["v11","7/7"]}