From patchwork Thu Mar 28 18:16:51 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: 1917547 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=RZCvZvnx; 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=nZ1RvGlZ; 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 4V5Bg75zyLz1yYM for ; Fri, 29 Mar 2024 05:20:51 +1100 (AEDT) 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=R3aHPCxIW+jx/hMiD1pJ07gxT3YUC/RdUfYCSE4Ig8U=; b=RZCvZvnxwJIzLJ ShUegZurwAVgWn7MnNW14iV/9CZE6IA10VgajgABkkOLF8/v8G9kawVxm/v44XmyiMpBcwyRXNspD i10eKev3vVwi/4LS7vgUMP3SNTYhq6Ryl3H5ssqa1CeQyt+PMRxKWJ1x3exiPVpaShqhKsQ61fqix tOItgTJ6JTklExvnmUw2scBCnCW/T5UzP+5yDZv13slQeKLgWYKZpIN51QkWZkTfamgeWDMr8EhR9 ftYIdpPfEKfmNdzpFjT/1Ob1Hz6kxP+7I9M//eFelsSXTTjl4JYRwIqc0iQNKo8uNyorvWfgy3NdY NG2LCL70N1ryv2PwZUWg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.97.1 #2 (Red Hat Linux)) id 1rpuMY-0000000F9Fz-1xo7; Thu, 28 Mar 2024 18:20:30 +0000 Received: from mx0a-0031df01.pphosted.com ([205.220.168.131]) by bombadil.infradead.org with esmtps (Exim 4.97.1 #2 (Red Hat Linux)) id 1rpuK4-0000000F7HM-0JrL for hostap@lists.infradead.org; Thu, 28 Mar 2024 18:18:19 +0000 Received: from pps.filterd (m0279864.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.24/8.17.1.24) with ESMTP id 42SI9nGp028982 for ; Thu, 28 Mar 2024 18:17:54 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=FGDWYsbu7lzQIoAje34M1cB55y2K5qlGLY4pjQzA9Ns=; b=nZ 1RvGlZd5HKg6+Xx1zMrLQ6NK/Wr0x5pD/LWlrbyVIKKmy/bbTMnfTfTne+Kt2YY9 pXthBpEUXuUPdFKqphVNTEAcqOqs/IO9nPouMr0wOmwf8aQ19hyrKyBLP3tgE8Nn YdQCf7DP73YOtb5rjrR6/C/vR8KGJxqLkeA1gQaRjDqGq4oAkSaPOZ4yDTGUMD7D emvXHBYRbzviZHttFIWazogcOihqm1TkwHIXnovazaLO6jH6re5/LkD7asgeGs8l XxJ/fI7ZMErTuGGIFLUYvU14W8pT15SIueECR4ZogLKq5As9LqTQhmNVCIrsCl4J RU20jwGEqbv8DE9y5ktg== Received: from nalasppmta01.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3x562rhfcc-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Thu, 28 Mar 2024 18:17:53 +0000 (GMT) Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA01.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 42SIHrAJ011544 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Thu, 28 Mar 2024 18:17:53 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.1118.40; Thu, 28 Mar 2024 11:17:52 -0700 From: Aditya Kumar Singh To: CC: Aditya Kumar Singh Subject: [PATCH 21/22] tests: MLO: add basic cohosted MLDs functionality testing Date: Thu, 28 Mar 2024 23:46:51 +0530 Message-ID: <20240328181652.2956122-22-quic_adisi@quicinc.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240328181652.2956122-1-quic_adisi@quicinc.com> References: <20240328181652.2956122-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-ORIG-GUID: LqvPVXCdQsYXKupa2Q90i-j4xKBPzb_j X-Proofpoint-GUID: LqvPVXCdQsYXKupa2Q90i-j4xKBPzb_j X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.272,Aquarius:18.0.1011,Hydra:6.0.619,FMLib:17.11.176.26 definitions=2024-03-28_17,2024-03-28_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 bulkscore=0 phishscore=0 spamscore=0 malwarescore=0 mlxlogscore=999 mlxscore=0 priorityscore=1501 lowpriorityscore=0 impostorscore=0 clxscore=1015 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2403210001 definitions=main-2403280128 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240328_111757_458925_720E19E5 X-CRM114-Status: GOOD ( 15.29 ) 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_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's 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..732406219e5c 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 os, subprocess, time, 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)