From patchwork Mon Apr 22 04:12:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aditya Kumar Singh X-Patchwork-Id: 1925965 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=bBKD/+cG; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=quicinc.com header.i=@quicinc.com header.a=rsa-sha256 header.s=qcppdkim1 header.b=hOUTS4hC; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=patchwork.ozlabs.org) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4VNBgw5cXsz1yP2 for ; Mon, 22 Apr 2024 14:13:32 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=b/RB8IJiqyzJ/HQhMFd3WUyFZbCClNCknnsH7dl4Mjo=; b=bBKD/+cGEISIGe eeKB92XAmnShDem3+KSMc4iaOmcovOMreX5g8v1Y8ptMmyE/bOQ8HxLbNZEWtb9gf6WX6K7pe1lck uX59vZ5NveQRfJ661uWYaQ83YbIcNm22V7P6u7wHRTb1qVQsQZBy9eED4lQJ/fLEyKNUD/NjYl6TX t1RFUidWQHhnk5unrqaUAlpy1XJ3Ko7HurDvtIMqmmB27V7fMnGAtpFkO3POyoa4eu1H7opWNeONc 2Rm4RVSby8z9GNGWfT2f21/jSCubOMSjx7igGMzTky+sk9LAHyG8K4UB9/RE0jBOQTRq4+UbqMpKt hxJ6dHyhAPys6e47HfuA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.97.1 #2 (Red Hat Linux)) id 1ryl3G-0000000BxDF-34ph; Mon, 22 Apr 2024 04:13:10 +0000 Received: from mx0b-0031df01.pphosted.com ([205.220.180.131]) by bombadil.infradead.org with esmtps (Exim 4.97.1 #2 (Red Hat Linux)) id 1ryl3D-0000000BxCG-2QGO for hostap@lists.infradead.org; Mon, 22 Apr 2024 04:13:09 +0000 Received: from pps.filterd (m0279871.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 43M3vmVm002371 for ; Mon, 22 Apr 2024 04:13:06 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s= qcppdkim1; bh=UlM3g8D9hh0Xe3knrSZFOmdLvf056mfvar9gxDGMHWU=; b=hO UTS4hCTtsU86xk/UJdHpWV/UWPf2KY2+EKWGTlmtbsB0t341jRYUKpHDNajM8viH rqIwr7pb2dVQDH2Bi7qj9RDz9wfA3Laz62L7wvSgopyYjqdUPqz8pCT9yO6RLx3U lzLlFIs31rMgROUA3EguhhosAHRZnZcv2duwFqMohtK6v5ICY4mycB5i7ZLfnHcn gOXfexdOOrvq2zMbPS7U4HnjxCordVCPisAMrP+GTEJzCim4+Iy8nuNbwdFzEyOO 62rhHpZYLhRBsWlDQHfQ6kwci/7iHqaab6jMiycAXZBXI2gu6ByUjobf/SGw1b0B nqJ/Wo03axxzMqc3oBYA== Received: from nalasppmta04.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3xmxq4s8xj-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Mon, 22 Apr 2024 04:13:06 +0000 (GMT) Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA04.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 43M4D5ZR015112 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Mon, 22 Apr 2024 04:13:05 GMT Received: from hu-adisi-blr.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.9; Sun, 21 Apr 2024 21:13:04 -0700 From: Aditya Kumar Singh To: CC: Aditya Kumar Singh Subject: [PATCH v2 1/2] tests: MLO: add basic cohosted MLDs functionality testing Date: Mon, 22 Apr 2024 09:42:38 +0530 Message-ID: <20240422041239.1823537-2-quic_adisi@quicinc.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240422041239.1823537-1-quic_adisi@quicinc.com> References: <20240422041239.1823537-1-quic_adisi@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-GUID: e77t4yHyMRPGtRwkIVtYfnhb9qizLGmw X-Proofpoint-ORIG-GUID: e77t4yHyMRPGtRwkIVtYfnhb9qizLGmw X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1011,Hydra:6.0.619,FMLib:17.11.176.26 definitions=2024-04-22_01,2024-04-19_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 adultscore=0 bulkscore=0 priorityscore=1501 impostorscore=0 lowpriorityscore=0 phishscore=0 malwarescore=0 clxscore=1015 suspectscore=0 mlxlogscore=999 mlxscore=0 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2404010003 definitions=main-2404220019 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240421_211307_789377_86C76973 X-CRM114-Status: GOOD ( 15.38 ) X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Add test case to test basic cohosted MLDs functionality. Add helper functions to create the configuration file, start hostapd instance. Client connectivty test case will be added via a subsequent change. Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Add test case to test basic cohosted MLDs functionality. Add helper functions to create the configuration file, start hostapd instance. Client connectivty test case will be added via a subsequent change. eht_mld_cohosted_discovery: 2 co-hosted MLDs without non-MLD RNR. Basic bring up and beacon, MLD RNR, scan validation. eht_mld_cohosted_discovery_with_rnr: Same like eht_mld_cohosted_discovery but additionally non-MLD RNR (rnr=1) is also enabled. Validate the non-MLD RNR as well. Signed-off-by: Aditya Kumar Singh --- tests/hwsim/test_eht.py | 230 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) diff --git a/tests/hwsim/test_eht.py b/tests/hwsim/test_eht.py index a012fe4e799d..b53f843c7ba8 100644 --- a/tests/hwsim/test_eht.py +++ b/tests/hwsim/test_eht.py @@ -15,6 +15,7 @@ from tshark import run_tshark from test_gas import hs20_ap_params from test_dpp import check_dpp_capab, wait_auth_success from test_rrm import build_beacon_request, run_req_beacon, BeaconReport +import tempfile def eht_verify_wifi_version(dev): status = dev.get_status() @@ -1823,3 +1824,232 @@ def test_eht_mlo_csa(dev, apdev): traffic_test(wpas, hapd0) #TODO: CSA on non-first link + +def create_base_conf_file(iface, channel, prefix='hostapd-', hw_mode='g', + op_class=None): + # Create configuration file and add phy characteristics + fd, fname = tempfile.mkstemp(dir='/tmp', + prefix=prefix + iface + "-chan-" + str(channel) + "-") + f = os.fdopen(fd, 'w') + + f.write("driver=nl80211\n") + f.write("hw_mode=" + str(hw_mode) + "\n") + f.write("ieee80211n=1\n") + if hw_mode == 'a' and \ + (op_class is None or \ + op_class not in [131, 132, 133, 134, 135, 136, 137]): + f.write("ieee80211ac=1\n") + f.write("ieee80211ax=1\n") + f.write("ieee80211be=1\n") + f.write("channel=" + str(channel) + "\n") + + return f, fname + +def append_bss_conf_to_file(f, ifname, params, first=False): + # Add BSS specific characteristics + config = "bss" + + if first: + config = "interface" + + f.write("\n" + config + "=%s\n" % ifname) + + for k, v in list(params.items()): + f.write("{}={}\n".format(k,v)) + + f.write("mld_ap=1\n") + +def dump_config(fname): + with open(fname, 'r') as f: + cfg = f.read() + logger.debug("hostapd config: " + str(fname) + "\n" + cfg) + +def get_config(iface, count, ssid, passphrase, channel, bssid_regex, + rnr=False, debug=False): + f, fname = create_base_conf_file(iface, channel=channel) + hapds = [] + + for i in range(count): + if i == 0: + ifname = iface + else: + ifname = iface + "-" + str(i) + + set_ssid = ssid + str(i) + set_passphrase = passphrase + str(i) + params = hostapd.wpa2_params(ssid=set_ssid, passphrase=set_passphrase, + wpa_key_mgmt="SAE", ieee80211w="2") + params['sae_pwe'] = "2" + params['group_mgmt_cipher'] = "AES-128-CMAC" + params['beacon_prot'] = "1" + params["ctrl_interface"] = "/var/run/hostapd/chan_" + str(channel) + params["bssid"] = bssid_regex % (i + 1) + + if rnr: + params["rnr"]="1" + + append_bss_conf_to_file(f, ifname, params, first=(i == 0)) + + hapds.append([ifname, params["ctrl_interface"], i]) + + f.close() + + if debug: + dump_config(fname) + + return fname, hapds + +def start_ap(prefix, configs): + pid = prefix + ".hostapd.pid" + configs = configs.split() + + cmd = ['../../hostapd/hostapd', '-ddKtB', '-P', pid, '-f', + prefix + ".hostapd-log"] + + cmd = cmd + configs + + logger.info("Starting APs") + res = subprocess.check_call(cmd) + if res != 0: + raise Exception("Could not start hostapd: %s" % str(res)) + + # Wait for hostapd to complete initialization and daemonize. + time.sleep(2) + + if not os.path.exists(pid): + raise Exception("hostapd did not create PID file.") + +def get_mld_devs(hapd_iface, count, prefix, rnr=False): + fname1, hapds1 = get_config(hapd_iface, count=count, ssid="mld-", + passphrase="qwertyuiop-", channel=1, + bssid_regex="02:00:00:00:07:%02x", + rnr=rnr, debug=True) + fname2, hapds2 = get_config(hapd_iface, count=count, ssid="mld-", + passphrase="qwertyuiop-", channel=6, + bssid_regex="02:00:00:00:08:%02x", + rnr=rnr, debug=True) + + start_ap(prefix, fname1 + " " + fname2) + + hapd_mld1_link0 = hostapd.Hostapd(ifname=hapds1[0][0], ctrl=hapds1[0][1], + bssidx=hapds1[0][2]) + hapd_mld1_link1 = hostapd.Hostapd(ifname=hapds2[0][0], ctrl=hapds2[0][1], + bssidx=hapds2[0][2]) + + hapd_mld2_link0 = hostapd.Hostapd(ifname=hapds1[1][0], ctrl=hapds1[1][1], + bssidx=hapds1[1][2]) + hapd_mld2_link1 = hostapd.Hostapd(ifname=hapds2[1][0], ctrl=hapds2[1][1], + bssidx=hapds2[1][2]) + + if not hapd_mld1_link0.ping(): + raise Exception("Could not ping hostapd") + + if not hapd_mld1_link1.ping(): + raise Exception("Could not ping hostapd") + + if not hapd_mld2_link0.ping(): + raise Exception("Could not ping hostapd") + + if not hapd_mld2_link1.ping(): + raise Exception("Could not ping hostapd") + + os.remove(fname1) + os.remove(fname2) + + return [hapd_mld1_link0, hapd_mld1_link1, hapd_mld2_link0, hapd_mld2_link1] + +def stop_mld_devs(hapds, pid): + pid = pid + ".hostapd.pid" + + if "OK" not in hapds[0].request("TERMINATE"): + raise Exception("Failed to terminate hostapd process") + + ev = hapds[0].wait_event(["CTRL-EVENT-TERMINATING"], timeout=15) + if ev is None: + raise Exception("CTRL-EVENT-TERMINATING not seen") + + time.sleep(0.5) + + if os.path.exists(pid): + raise Exception("PID file exits after process termination") + +def eht_parse_rnr(bss, rnr=False, exp_bssid=None): + partner_rnr_pattern = re.compile(".*ap_info.*, mld ID=0, link ID=", + re.MULTILINE) + ml_pattern = re.compile(".*multi-link:.*, MLD addr=.*", re.MULTILINE) + + if partner_rnr_pattern.search(bss) is None: + raise Exception("RNR element not found for first link of first MLD") + + if ml_pattern.search(bss) is None: + raise Exception("ML element not found for first link of first MLD") + + if not rnr: + return + + coloc_rnr_pattern = re.compile(".*ap_info.*, mld ID=255, link ID=..", + re.MULTILINE) + + if coloc_rnr_pattern.search(bss) is None: + raise Exception("RNR element not found for co-located BSS") + + line = coloc_rnr_pattern.search(bss).group() + if line.count('bssid') > 1: + raise Exception("More than one BSS found for co-located RNR") + + # Get the BSSID carried in the RNR + index = line.rindex('bssid') + bssid = line[index+len('bssid')+1:].split(',')[0] + + # Get the MLD ID carried in the RNR + index = line.rindex('link ID') + link_id = line[index+len('link ID')+1:].split(',')[0] + + if link_id != "15": + raise Exception("Unexpected link ID for co-located BSS which is not own partner") + + if bssid != exp_bssid: + raise Exception("Unexpected BSSID for co-located BSS") + +def eht_mld_cohosted_discovery(dev, apdev, params, rnr=False): + with HWSimRadio(use_mlo=True, n_channels=2) as (hapd_radio, hapd_iface), \ + HWSimRadio(use_mlo=True) as (wpas_radio, wpas_iface): + + wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5') + wpas.interface_add(wpas_iface) + + hapds = get_mld_devs(hapd_iface=hapd_iface, count=2, prefix=params['prefix'], + rnr=rnr) + + # Only scan link 0 + res = wpas.request("SCAN freq=2412") + if "FAIL" in res: + raise Exception("Failed to start scan") + + ev = wpas.wait_event(["CTRL-EVENT-SCAN-STARTED"]) + if ev is None: + raise Exception("Scan did not start") + + ev = wpas.wait_event(["CTRL-EVENT-SCAN-RESULTS"]) + if ev is None: + raise Exception("Scan did not complete") + + logger.info("Scan done") + + bss = wpas.request("BSS " + hapds[0].own_addr()) + logger.info("BSS 0_0: " + str(bss)) + eht_parse_rnr(bss, rnr, hapds[2].own_addr()) + + bss = wpas.request("BSS " + hapds[2].own_addr()) + logger.info("BSS 1_0: " + str(bss)) + eht_parse_rnr(bss, rnr, hapds[0].own_addr()) + + stop_mld_devs(hapds, params['prefix']) + +def test_eht_mld_cohosted_discovery(dev, apdev, params): + """EHT 2 AP MLDs discovery""" + eht_mld_cohosted_discovery(dev, apdev, params) + +def test_eht_mld_cohosted_discovery_with_rnr(dev, apdev, params): + """EHT 2 AP MLDs discovery (with co-location RNR)""" + eht_mld_cohosted_discovery(dev, apdev, params, rnr=True)