From nobody Mon Feb 9 12:24:16 2026 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11011040.outbound.protection.outlook.com [52.101.65.40]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D11A22D978A; Wed, 4 Feb 2026 18:05:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.65.40 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770228331; cv=fail; b=X6uTkPo1LPsW85qaQwWuHdfG/IwvHk3IkqyTRk80xS8rBmbC2fOb+EIZqcgqCTXTjhuLvJkff6hC3fkTnFYy8dOOkERlso4U9dCn5js12NvvJu4CUN91sj4KwSlCv+OCRmvtIoG6GYgpgGoYwtx+LJ4OJE5/8MRe0PPr6ims2GI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770228331; c=relaxed/simple; bh=JIDL9n28bDqZVbnWTGpjgZRmjE/LuCPMsEl0r+uuqf4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=gi4OzAOJ3WvRw89mnkOWO9H8gow8GYowt7sSZbL5NVcqSHdGJ/ULpp0qU42dbnME2JArqKE5zWGA9urKZJXZrUupsy3LbAQkCvQdxyB9xTN6VHqEQO6ZhKH+8nHj/lR8L2y/RC7x6Hr8mIKG46bAYlizrnlZc9V2zVwSUJh84vM= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=cr939Ksb; arc=fail smtp.client-ip=52.101.65.40 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="cr939Ksb" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Vg26Ce2+O4t9ZPKyhQsUYBJTuVDB7jATIgTKJPdX5peCcCXMA6cmyWmhoIoomEJti++RNWvSSREISFYIOFrskjTKvHcHpaUvck0p7Z7n7yPHdEKerLdmJ19zKQOKRduzDAItgEfld+ZfhqGP0FcRWjsWWQMlL2YfkzMd5FrJreA8Zhjas5/tSzS2gl1aBXkBvhMWLTC9hgNG+bpH+6+dw6cB0rnJopgXARpewCTlpV0JxuUhT3N5eCC5D3RxjB8qfVFhwAkAR48EOUzoOVm8A2ycWccBVcw4D77wvTxFEKkpOfA1JW3F8wIiEGcTHPoyekOIt8+oZzQckr5X9yBmAw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=XAFdoTVmo0O/JyWK7stabIkmM5Z/3eaM68X784VjmeM=; b=Y98FG/iv9HAw9GHmLKaXOtw0jLEdRIzAY0FxNTCNDp30HYDCtLY4YjQpK6GhZ/ClOjwvVpBpHukF0XgbQ/1jufX+DGlWCkW5C4Z0dwVnHZU+1RIdsQyVtvmVg/CnoSKHC8EbY6T4DWeV/TxeRGHqiyYNhkZNHLG6+1+pthWm5mYgSba+bkTgPUDrOQFXtzeRsde+FrKTYympje0A4j0HycG8wK42HAsPcRg60iyfu+5IVKwwdhA1aWdi8w+e99uTa6sdRyJ/4deOh3yR+CvCxBtBOQiLb9GVaLVqFOhf1/VpG+rUsnq4J24/ocT9fE0q+fKrE5sJ7si8G7r4CeSmFw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=XAFdoTVmo0O/JyWK7stabIkmM5Z/3eaM68X784VjmeM=; b=cr939Ksbby1RZVepLF2Xd+OzKBJ/PkQfzs7StcHjoK/OqMsmuiWihbbq5IT7uqmcn7/lSzzmWBSeB8++5rz6j3kGR4vBFrgID+ALgvd/qspI14qGVk0vVpXvEy9gmqWrl3zOLvTuURGFwSr6PIlnMeMNcGC61r8pEafvFt3NYCkL/yXKbOetljizROZmukqO7S2s5TKfg6DmUu3eu2+yvM4cSrhWYJ/8tOMkIzeYP69JPNixO4jGBKC2WNx4EiGRgdh8LK+BBaZdFfr+5knXeTITGC33g0ae/I2/c2Q19vEhkqAVipkuOyA0ZFRuxsWjwUNOTtD292iabfNhVGAkTA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PAXPR04MB9255.eurprd04.prod.outlook.com (2603:10a6:102:2bb::13) by GVXPR04MB12314.eurprd04.prod.outlook.com (2603:10a6:150:30f::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.11; Wed, 4 Feb 2026 18:05:28 +0000 Received: from PAXPR04MB9255.eurprd04.prod.outlook.com ([fe80::1eb5:3ebc:9f11:f20b]) by PAXPR04MB9255.eurprd04.prod.outlook.com ([fe80::1eb5:3ebc:9f11:f20b%4]) with mapi id 15.20.9564.016; Wed, 4 Feb 2026 18:05:28 +0000 From: Jeff Chen To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, briannorris@chromium.org, johannes@sipsolutions.net, francesco@dolcini.it, s.hauer@pengutronix.de, Jeff Chen Subject: [PATCH v9 07/21] wifi: nxpwifi: add join and association support Date: Thu, 5 Feb 2026 02:03:44 +0800 Message-Id: <20260204180358.632281-8-jeff.chen_1@nxp.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260204180358.632281-1-jeff.chen_1@nxp.com> References: <20260204180358.632281-1-jeff.chen_1@nxp.com> Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SI2P153CA0015.APCP153.PROD.OUTLOOK.COM (2603:1096:4:140::21) To PAXPR04MB9255.eurprd04.prod.outlook.com (2603:10a6:102:2bb::13) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PAXPR04MB9255:EE_|GVXPR04MB12314:EE_ X-MS-Office365-Filtering-Correlation-Id: 134015ab-d5da-45dc-3c80-08de6417fa0d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|52116014|366016|376014|19092799006|38350700014; X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?Sqv0+vKaq8+ZUqHpIfvx6yNTzOnuVsaZB2LCbH+xTerzeONsXyrQOHxyV8Gh?= =?us-ascii?Q?96CpKB3BBW2qwPm3mnwBzWlxdXb+xnCOCDBx2B1Wpf6/3cuy9hm/b3H8jvak?= =?us-ascii?Q?c0qM5wWsJwMSzDgMIeTG0xGCFJ5mKJKxLmbF+4qSC/FZ+/F5BYQyOah3Qfyn?= =?us-ascii?Q?RdXk4g5UsASO/k5xlb16Q4JqYzZK8ALGv+vsKxyLU1llErRTvx/l1VTljLAD?= =?us-ascii?Q?Y0BFRJUqrv6dRQbkmrx+e/wjNovhvZUX4z4csZMKFgTyfpWMdAKMu9eONyiC?= =?us-ascii?Q?a2vw11DUeIintnD9S1bRm/GrEaGWZCDf+r8BXKNhnnuKi9aIdkBPqVzONlC/?= =?us-ascii?Q?PB55h2AWEwpg4JSNfXJeMHe9AsJ2A1nA+XFimza48Y1FHEgF/swacCcyN/8B?= =?us-ascii?Q?bcE9RlYsSb3plUWLfe+tf/xE1LdvNK3RBBUXoS426ZaBDrfT4D8dRpcPz8vb?= =?us-ascii?Q?KGRld8fiaiuoIHDQl48HqSL5Xwiw2XD7Q43zlcUVPh26wzIyuH6NFYlIjzdf?= =?us-ascii?Q?CHAbyTSCFlg5RLBffuC2/PaStbFWfxk7UJBICQJoZF4Pk8Pzi6U4VV0lMJXk?= =?us-ascii?Q?4kJezllpoaaMYWklRLyYRWQtxfxZIV88YgShXoIWs9m4os50u2hx9FdDYDWF?= =?us-ascii?Q?8/wfarSTbQ7rcUH+HJhVXeUyzq0ideFbNK3LqXCvltvROM1wXQuCel0eKHED?= =?us-ascii?Q?/yiLB8vaUTpZC6X2bJAlKJhADuGmQKj3brciL8TwxNzEkSXge4wq8HGIg8T8?= =?us-ascii?Q?XMLtr2o9yi8TTiBuIlzDcOsNvTHUxJ3QdbdO0ksh9sFNFPY/fNbEMwfFcy0r?= =?us-ascii?Q?JdluYnLYukHTnV0g2NMoyEaa3SvusSGrPITiztrgSydn6HUARBFKPEV5UqZr?= =?us-ascii?Q?qeRPcVF1VcXL9tex/XbvXIOkiiPDEVuFti0Tscixq9fKFgH3vHxO5WyqM1rs?= =?us-ascii?Q?k9dfAq34jbdz8aWlcHkSK0beEliVPItC6yB+0FKVnc13+5vcvmI686KskL4u?= =?us-ascii?Q?FzkEh6efj6pmYeiw9OPNCVYwcrpR+F/EcAXPdqOFVodcYRjIYNxnvQXnXT3g?= =?us-ascii?Q?7Kpf6Zh32ALLqxT50oULQ7I6VCqP9qzhsNai7GUkJL0VEUUFRSZzw/DwGdt0?= =?us-ascii?Q?RgetT822S/86S3N5i/gh+x6yAz3Sc6kQfd6caBd5CAJonB8Q0uSq7LkETh0d?= =?us-ascii?Q?LjL5sEi5BZVIF2Yt+j8mN1YXOMhCLxVUlQLgnFIlh4hg+2OJDr+k/j6gHvmI?= =?us-ascii?Q?ES0XOICcWFrSVHAEBdqUVEVDLAVUCl5RDhCoQ05VF8dMRF/Jq8iv2oWl5k3j?= =?us-ascii?Q?WtvxVyMoVbt/2YP+1auNhz62Jfa6IytP99F5mk+kqNJRDU9PBmpEHRUHeVUT?= =?us-ascii?Q?b2g5xFaK3dtKFtCbBRZolhGVeupG7L8z9xYgAYTyvjzM8Bo6zr6/6vF8A854?= =?us-ascii?Q?qgEi4dSRcXbJNKZO84F677tVac9zsLY/9BbO7liP6ab6YvONejpkJfSC4uRv?= =?us-ascii?Q?42pAcXm6XewAy5M4NkLrRP+ApzIbPuWGVQtgcAte4exdoW89Nfp/svyjh8CN?= =?us-ascii?Q?2Bbl3cc0d+sEeLRlmJZl5NFGpzA8m4IndG46Xd0x2kWJCwGrFj25SdnkGbVU?= =?us-ascii?Q?bDFnzqCRQPVGnsaqNTU9wjc=3D?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:PAXPR04MB9255.eurprd04.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(52116014)(366016)(376014)(19092799006)(38350700014);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?lYDQMfSKga4xoQe6gIvwh0PtzVNGgBgvesDlcGT3gkt1ejnj64Ju+SzCSFKh?= =?us-ascii?Q?H4QCJM+z9HnceWYVxawh42TPZATBRvs36iXPq3pfHJF47bR9CuQyfmt8x3CW?= =?us-ascii?Q?f09H7YAqof+M5Edgm5cfPLTXOCgN1F6qRugMxza7m6MMjWqtZoryNvRbDgCs?= =?us-ascii?Q?aBcOlaVe6cJs6XwG5lg9uSZG84YMWN10R+G71T6KHO1fAc1x4gvRiDhpV9Bs?= =?us-ascii?Q?TBeVTLaupKl/0girZb/QriW+8k95AKLJTBg//nAfQS1CZppwGRk5Mcimvm6K?= =?us-ascii?Q?P1rlIg7dhFLA4V+JzCB8Q1STSlWGXesSR7cqGnLAFF8CCNo59suHIwOYBYdh?= =?us-ascii?Q?Kbh12v5+PAWe3CesxFgv88o9IMb7GyQSJ2aeTOJXs4HOTOygmWE1W1QhusCG?= =?us-ascii?Q?CYzghLXjGzb5247xUf9E5p1Dx9URcagqOOEdO+bcxamXIhd1Q7X+P2lxOARr?= =?us-ascii?Q?X+LMu32m1d/QJUMvOYM+PTK1va9HyAkb1Ec8dxpVI9l6BM7splAtjnbLnh3U?= =?us-ascii?Q?ObJvrscVIu2vwD86lRZ/Rmu1AIxaX89BW9Zn1CHzgT6kanGvgGnViFnlpOEC?= =?us-ascii?Q?ErHzbTMYmCD0pqsArKz/Bz/8NIw6d0Hu7obrMMuYg6UrEsAE7M+4Lg37mdqk?= =?us-ascii?Q?Lpkh4bg0KUseGXMFINSdtqkFapdC6x6UOoviaD2c5dGwt5DSv8l3nUE080yL?= =?us-ascii?Q?WXmFXpDYCdAqET8fK1lyOTloBDWrMuWwalvcEozDg+CnnCyUz51zj3x/z5b5?= =?us-ascii?Q?pza4pCmvNWQAQG/WhdfL1/B/XLJGMFne4AdWcJhjNOxVUGSb241b+/13mU9s?= =?us-ascii?Q?vN9dkfCOSlY1akzGUqxvk5Z7/xENy0TPw79EmvP0lKiJT73RIpYm+K10/NqK?= =?us-ascii?Q?/+Cgv4U2pB5bXV2nyPlvw4Pi1PZLzvOmL+r3WGmT33U99fdLzAJ/TVUXaPbx?= =?us-ascii?Q?9F2zCRsgDCsFeLbpqXVuU7GTvTMzuI0B4rYL9YefKdbECxYvx4poCSuwLQNH?= =?us-ascii?Q?GCr5bD20zvNFg/0wgZsAzAFNKIlZ+1BnbROVR1eATBVm2OOUiHQEyc1uiPpG?= =?us-ascii?Q?6EAEpKlv1BiH5dnDfHs7xT5KhBLEpD1l3G1ecWj48ko5tPWKIzt6Dq/pctGn?= =?us-ascii?Q?Rhyx1tLV5R+9L2Ma2PXrxBA/jKPBs/yHxDqEE71La5ddC+wH/4FLSR1Eiwla?= =?us-ascii?Q?ooYPZVD4aoCiDrsedSCT9eaD+iKvmk/kGE6xyGv4Gd+1l/oza8enYaApioqh?= =?us-ascii?Q?GcVPV8IGelGGLSAuDWb4/dRVK8nrwQKv7bMhoqi8UJnBrvDY2bGi3wMGui/p?= =?us-ascii?Q?tw51xYTMZ+Rm5R1KRf2W07VQOEgtWToYWFyYcl3STZj8DeQKUfCexc+U+XqU?= =?us-ascii?Q?LdNRhQ2ZeYHbCjhYGVTau+tBpDd5l228qmPmtqstJp7Np6Coa1pkGQVARRGW?= =?us-ascii?Q?6xQKNXY5H1YFHExNqVO138xVci0UnMkt3PvkBsmlctSECh9nOx4Rg/+gC8iD?= =?us-ascii?Q?IiXnKyOKKsEDcsLXAgbSnLcigmKATIGvYUZZtpr46fq9lcdYZjaUzwgao1ad?= =?us-ascii?Q?OptHfhJxWug0zJPo8Hw7wNaqksgt8s4RVanrqkxKq7IZw52m5cHblQ+cSpS3?= =?us-ascii?Q?k+YMLDJx/lQn+DwQ0DGE5GySAHe2KijAu9MiIfrHi0XGCTyZMY8Mq/vP/SYM?= =?us-ascii?Q?vJtULExfTaA+v5w4zTyTM8Jfy3Mj4POvPGX2EjPafqd2SSlCLtARF1ayI7hd?= =?us-ascii?Q?HKMtkb8XlQ=3D=3D?= X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 134015ab-d5da-45dc-3c80-08de6417fa0d X-MS-Exchange-CrossTenant-AuthSource: PAXPR04MB9255.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Feb 2026 18:05:27.8938 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: JlJ5Pmd94LCHmoebHd/flBsIdfgsj1ccepBEp3C+XxdSysSzSA41QJepv/Wun6N3m4PfjqASesUEsmJKSW/voQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB12314 Content-Type: text/plain; charset="utf-8" Introduce join.c to implement infrastructure mode association and deauthentication logic for the nxpwifi driver. - Implements association command construction, including: - SSID, channel, rates, authentication, WPA/WPA2/RSN IEs - 802.11n/ac/ax capability TLVs - WMM and vendor-specific IEs - TSF synchronization and scan result integration - Handles association response parsing and connection state updates - Adds support for deauthentication (infra, AP, adhoc) - Updates current BSS parameters and enables data path upon success This patch enables full STA-mode association flow with cfg80211 integration. Signed-off-by: Jeff Chen --- drivers/net/wireless/nxp/nxpwifi/join.c | 788 ++++++++++++++++++++++++ 1 file changed, 788 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/join.c diff --git a/drivers/net/wireless/nxp/nxpwifi/join.c b/drivers/net/wireless= /nxp/nxpwifi/join.c new file mode 100644 index 000000000000..e1aaa0424c25 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/join.c @@ -0,0 +1,788 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * nxpwifi: association and ad-hoc start/join + * + * Copyright 2011-2024 NXP + */ + +#include "cfg.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "cmdevt.h" +#include "wmm.h" +#include "11n.h" +#include "11ac.h" +#include "11ax.h" + +#define CAPINFO_MASK (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9))) + +/* Append generic IE as pass-through TLV for join */ +static int +nxpwifi_cmd_append_generic_ie(struct nxpwifi_private *priv, u8 **buffer) +{ + int ret_len =3D 0; + struct nxpwifi_ie_types_header ie_header; + + /* Null Checks */ + if (!buffer) + return 0; + if (!(*buffer)) + return 0; + + /* + * If there is a generic element buffer setup, append it to the return + * parameter buffer pointer. + */ + if (priv->gen_ie_buf_len) { + nxpwifi_dbg(priv->adapter, INFO, + "info: %s: append generic element len %d to %p\n", + __func__, priv->gen_ie_buf_len, *buffer); + + /* Wrap the generic element buffer with a pass through TLV type */ + ie_header.type =3D cpu_to_le16(TLV_TYPE_PASSTHROUGH); + ie_header.len =3D cpu_to_le16(priv->gen_ie_buf_len); + memcpy(*buffer, &ie_header, sizeof(ie_header)); + + /* + * Increment the return size and the return buffer pointer + * param + */ + *buffer +=3D sizeof(ie_header); + ret_len +=3D sizeof(ie_header); + + /* + * Copy the generic element buffer to the output buffer, advance + * pointer + */ + memcpy(*buffer, priv->gen_ie_buf, priv->gen_ie_buf_len); + + /* + * Increment the return size and the return buffer pointer + * param + */ + *buffer +=3D priv->gen_ie_buf_len; + ret_len +=3D priv->gen_ie_buf_len; + + /* Reset the generic element buffer */ + priv->gen_ie_buf_len =3D 0; + } + + /* return the length appended to the buffer */ + return ret_len; +} + +/* Append TSF timestamp (AP TSF and local RX TSF) for reassoc */ +static int +nxpwifi_cmd_append_tsf_tlv(struct nxpwifi_private *priv, u8 **buffer, + struct nxpwifi_bssdescriptor *bss_desc) +{ + struct nxpwifi_ie_types_tsf_timestamp tsf_tlv; + __le64 tsf_val; + + /* Null Checks */ + if (!buffer) + return 0; + if (!*buffer) + return 0; + + memset(&tsf_tlv, 0x00, sizeof(struct nxpwifi_ie_types_tsf_timestamp)); + + tsf_tlv.header.type =3D cpu_to_le16(TLV_TYPE_TSFTIMESTAMP); + tsf_tlv.header.len =3D cpu_to_le16(2 * sizeof(tsf_val)); + + memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header)); + *buffer +=3D sizeof(tsf_tlv.header); + + /* TSF at the time when beacon/probe_response was received */ + tsf_val =3D cpu_to_le64(bss_desc->fw_tsf); + memcpy(*buffer, &tsf_val, sizeof(tsf_val)); + *buffer +=3D sizeof(tsf_val); + + tsf_val =3D cpu_to_le64(bss_desc->timestamp); + + nxpwifi_dbg(priv->adapter, INFO, + "info: %s: TSF offset calc: %016llx - %016llx\n", + __func__, bss_desc->timestamp, bss_desc->fw_tsf); + + memcpy(*buffer, &tsf_val, sizeof(tsf_val)); + *buffer +=3D sizeof(tsf_val); + + return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val)); +} + +/* Compute intersection of two rate sets; rate1 updated in-place */ +static int nxpwifi_get_common_rates(struct nxpwifi_private *priv, u8 *rate= 1, + u32 rate1_size, u8 *rate2, u32 rate2_size) +{ + int ret; + u8 *ptr =3D rate1, *tmp; + u32 i, j; + + tmp =3D kmemdup(rate1, rate1_size, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + memset(rate1, 0, rate1_size); + + for (i =3D 0; i < rate2_size && rate2[i]; i++) { + for (j =3D 0; j < rate1_size && tmp[j]; j++) { + /* + * Check common rate, excluding the bit for + * basic rate + */ + if ((rate2[i] & 0x7F) =3D=3D (tmp[j] & 0x7F)) { + *rate1++ =3D tmp[j]; + break; + } + } + } + + nxpwifi_dbg(priv->adapter, INFO, "info: Tx data rate set to %#x\n", + priv->data_rate); + + if (!priv->is_data_rate_auto) { + while (*ptr) { + if ((*ptr & 0x7f) =3D=3D priv->data_rate) { + ret =3D 0; + goto done; + } + ptr++; + } + nxpwifi_dbg(priv->adapter, ERROR, + "previously set fixed data rate %#x\t" + "is not compatible with the network\n", + priv->data_rate); + + ret =3D -EPERM; + goto done; + } + + ret =3D 0; +done: + kfree(tmp); + return ret; +} + +/* Build common rates from BSS descriptor into out_rates */ +static int +nxpwifi_setup_rates_from_bssdesc(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc, + u8 *out_rates, u32 *out_rates_size) +{ + u8 card_rates[NXPWIFI_SUPPORTED_RATES]; + u32 card_rates_size; + int ret; + + /* Copy AP supported rates */ + memcpy(out_rates, bss_desc->supported_rates, NXPWIFI_SUPPORTED_RATES); + /* Get the STA supported rates */ + card_rates_size =3D nxpwifi_get_active_data_rates(priv, card_rates); + /* Get the common rates between AP and STA supported rates */ + ret =3D nxpwifi_get_common_rates(priv, out_rates, NXPWIFI_SUPPORTED_RATES, + card_rates, card_rates_size); + if (ret) { + *out_rates_size =3D 0; + nxpwifi_dbg(priv->adapter, ERROR, + "%s: cannot get common rates\n", + __func__); + } else { + *out_rates_size =3D + min_t(size_t, strlen(out_rates), NXPWIFI_SUPPORTED_RATES); + } + + return ret; +} + +/* Append WPS IE as pass-through TLV for join */ +static int +nxpwifi_cmd_append_wps_ie(struct nxpwifi_private *priv, u8 **buffer) +{ + int ret_len =3D 0; + struct nxpwifi_ie_types_header ie_header; + + if (!buffer || !*buffer) + return 0; + + /* + * If there is a wps element buffer setup, append it to the return + * parameter buffer pointer. + */ + if (priv->wps_ie_len) { + nxpwifi_dbg(priv->adapter, CMD, + "cmd: append wps element %d to %p\n", + priv->wps_ie_len, *buffer); + + /* Wrap the generic element buffer with a pass through TLV type */ + ie_header.type =3D cpu_to_le16(TLV_TYPE_PASSTHROUGH); + ie_header.len =3D cpu_to_le16(priv->wps_ie_len); + memcpy(*buffer, &ie_header, sizeof(ie_header)); + *buffer +=3D sizeof(ie_header); + ret_len +=3D sizeof(ie_header); + + memcpy(*buffer, priv->wps_ie, priv->wps_ie_len); + *buffer +=3D priv->wps_ie_len; + ret_len +=3D priv->wps_ie_len; + } + + kfree(priv->wps_ie); + priv->wps_ie_len =3D 0; + return ret_len; +} + +/* Append WPA/WPA2 RSN IE TLV */ +static int nxpwifi_append_rsn_ie_wpa_wpa2(struct nxpwifi_private *priv, + u8 **buffer) +{ + struct nxpwifi_ie_types_rsn_param_set *rsn_ie_tlv; + int rsn_ie_len; + + if (!buffer || !(*buffer)) + return 0; + + rsn_ie_tlv =3D (struct nxpwifi_ie_types_rsn_param_set *)(*buffer); + rsn_ie_tlv->header.type =3D cpu_to_le16((u16)priv->wpa_ie[0]); + rsn_ie_tlv->header.type =3D + cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF); + rsn_ie_tlv->header.len =3D cpu_to_le16((u16)priv->wpa_ie[1]); + rsn_ie_tlv->header.len =3D cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len) + & 0x00FF); + if (le16_to_cpu(rsn_ie_tlv->header.len) <=3D (sizeof(priv->wpa_ie) - 2)) + memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2], + le16_to_cpu(rsn_ie_tlv->header.len)); + else + return -ENOMEM; + + rsn_ie_len =3D sizeof(rsn_ie_tlv->header) + + le16_to_cpu(rsn_ie_tlv->header.len); + *buffer +=3D rsn_ie_len; + + return rsn_ie_len; +} + +/* Build 802.11 association command and required TLVs */ +int nxpwifi_cmd_802_11_associate(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + struct nxpwifi_bssdescriptor *bss_desc) +{ + struct nxpwifi_adapter *adapter =3D priv->adapter; + struct host_cmd_ds_802_11_associate *assoc =3D &cmd->params.associate; + struct nxpwifi_ie_types_host_mlme *host_mlme_tlv; + struct nxpwifi_ie_types_ssid_param_set *ssid_tlv; + struct nxpwifi_ie_types_phy_param_set *phy_tlv; + struct nxpwifi_ie_types_ss_param_set *ss_tlv; + struct nxpwifi_ie_types_rates_param_set *rates_tlv; + struct nxpwifi_ie_types_auth_type *auth_tlv; + struct nxpwifi_ie_types_sae_pwe_mode *sae_pwe_tlv; + struct nxpwifi_ie_types_chan_list_param_set *chan_tlv; + u8 rates[NXPWIFI_SUPPORTED_RATES]; + u32 rates_size; + u16 tmp_cap; + u8 *pos; + int rsn_ie_len =3D 0; + int ret; + + pos =3D (u8 *)assoc; + + cmd->command =3D cpu_to_le16(HOST_CMD_802_11_ASSOCIATE); + + /* Save so we know which BSS Desc to use in the response handler */ + priv->attempted_bss_desc =3D bss_desc; + + memcpy(assoc->peer_sta_addr, + bss_desc->mac_address, sizeof(assoc->peer_sta_addr)); + pos +=3D sizeof(assoc->peer_sta_addr); + + /* Set the listen interval */ + assoc->listen_interval =3D cpu_to_le16(priv->listen_interval); + /* Set the beacon period */ + assoc->beacon_period =3D cpu_to_le16(bss_desc->beacon_period); + + pos +=3D sizeof(assoc->cap_info_bitmap); + pos +=3D sizeof(assoc->listen_interval); + pos +=3D sizeof(assoc->beacon_period); + pos +=3D sizeof(assoc->dtim_period); + + host_mlme_tlv =3D (struct nxpwifi_ie_types_host_mlme *)pos; + host_mlme_tlv->header.type =3D cpu_to_le16(TLV_TYPE_HOST_MLME); + host_mlme_tlv->header.len =3D cpu_to_le16(sizeof(host_mlme_tlv->host_mlme= )); + host_mlme_tlv->host_mlme =3D 1; + pos +=3D sizeof(host_mlme_tlv->header) + sizeof(host_mlme_tlv->host_mlme); + + ssid_tlv =3D (struct nxpwifi_ie_types_ssid_param_set *)pos; + ssid_tlv->header.type =3D cpu_to_le16(WLAN_EID_SSID); + ssid_tlv->header.len =3D cpu_to_le16((u16)bss_desc->ssid.ssid_len); + memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid, + le16_to_cpu(ssid_tlv->header.len)); + pos +=3D sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len); + + phy_tlv =3D (struct nxpwifi_ie_types_phy_param_set *)pos; + phy_tlv->header.type =3D cpu_to_le16(WLAN_EID_DS_PARAMS); + phy_tlv->header.len =3D cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set)); + memcpy(&phy_tlv->fh_ds.ds_param_set, + &bss_desc->phy_param_set.ds_param_set.current_chan, + sizeof(phy_tlv->fh_ds.ds_param_set)); + pos +=3D sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len); + + ss_tlv =3D (struct nxpwifi_ie_types_ss_param_set *)pos; + ss_tlv->header.type =3D cpu_to_le16(WLAN_EID_CF_PARAMS); + ss_tlv->header.len =3D cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set)); + pos +=3D sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len); + + /* Get the common rates supported between the driver and the BSS Desc */ + ret =3D nxpwifi_setup_rates_from_bssdesc(priv, bss_desc, + rates, &rates_size); + if (ret) + return ret; + + /* Save the data rates into Current BSS state structure */ + priv->curr_bss_params.num_of_rates =3D rates_size; + memcpy(&priv->curr_bss_params.data_rates, rates, rates_size); + + /* Setup the Rates TLV in the association command */ + rates_tlv =3D (struct nxpwifi_ie_types_rates_param_set *)pos; + rates_tlv->header.type =3D cpu_to_le16(WLAN_EID_SUPP_RATES); + rates_tlv->header.len =3D cpu_to_le16((u16)rates_size); + memcpy(rates_tlv->rates, rates, rates_size); + pos +=3D sizeof(rates_tlv->header) + rates_size; + nxpwifi_dbg(adapter, INFO, "info: ASSOC_CMD: rates size =3D %d\n", + rates_size); + + /* Add the Authentication type */ + auth_tlv =3D (struct nxpwifi_ie_types_auth_type *)pos; + auth_tlv->header.type =3D cpu_to_le16(TLV_TYPE_AUTH_TYPE); + auth_tlv->header.len =3D cpu_to_le16(sizeof(auth_tlv->auth_type)); + if (priv->sec_info.wep_enabled) + auth_tlv->auth_type =3D + cpu_to_le16((u16)priv->sec_info.authentication_mode); + else + auth_tlv->auth_type =3D cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM); + + pos +=3D sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len); + + if (priv->sec_info.authentication_mode =3D=3D WLAN_AUTH_SAE) { + auth_tlv->auth_type =3D cpu_to_le16(NXPWIFI_AUTHTYPE_SAE); + if (bss_desc->bcn_rsnx_ie && + bss_desc->bcn_rsnx_ie->datalen && + (bss_desc->bcn_rsnx_ie->data[0] & + WLAN_RSNX_CAPA_SAE_H2E)) { + sae_pwe_tlv =3D + (struct nxpwifi_ie_types_sae_pwe_mode *)pos; + sae_pwe_tlv->header.type =3D + cpu_to_le16(TLV_TYPE_SAE_PWE_MODE); + sae_pwe_tlv->header.len =3D + cpu_to_le16(sizeof(sae_pwe_tlv->pwe[0])); + sae_pwe_tlv->pwe[0] =3D bss_desc->bcn_rsnx_ie->data[0]; + pos +=3D sizeof(sae_pwe_tlv->header) + + sizeof(sae_pwe_tlv->pwe[0]); + } + } + + if (IS_SUPPORT_MULTI_BANDS(adapter) && + !(ISSUPP_11NENABLED(adapter->fw_cap_info) && + !bss_desc->disable_11n && + (priv->config_bands & BAND_GN || + priv->config_bands & BAND_AN) && + bss_desc->bcn_ht_cap)) { + /* + * Append a channel TLV for the channel the attempted AP was + * found on + */ + chan_tlv =3D (struct nxpwifi_ie_types_chan_list_param_set *)pos; + chan_tlv->header.type =3D cpu_to_le16(TLV_TYPE_CHANLIST); + chan_tlv->header.len =3D + cpu_to_le16(sizeof(struct nxpwifi_chan_scan_param_set)); + + memset(chan_tlv->chan_scan_param, 0x00, + sizeof(struct nxpwifi_chan_scan_param_set)); + chan_tlv->chan_scan_param[0].chan_number =3D + (bss_desc->phy_param_set.ds_param_set.current_chan); + nxpwifi_dbg(adapter, INFO, "info: Assoc: TLV Chan =3D %d\n", + chan_tlv->chan_scan_param[0].chan_number); + + chan_tlv->chan_scan_param[0].band_cfg =3D + nxpwifi_band_to_radio_type((u8)bss_desc->bss_band); + + nxpwifi_dbg(adapter, INFO, "info: Assoc: TLV Band =3D %d\n", + chan_tlv->chan_scan_param[0].band_cfg); + pos +=3D sizeof(chan_tlv->header) + + sizeof(struct nxpwifi_chan_scan_param_set); + } + + if (!priv->wps.session_enable) { + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + rsn_ie_len =3D nxpwifi_append_rsn_ie_wpa_wpa2(priv, &pos); + + if (rsn_ie_len =3D=3D -ENOMEM) + return -ENOMEM; + } + + if (ISSUPP_11NENABLED(adapter->fw_cap_info) && + !bss_desc->disable_11n && + (priv->config_bands & BAND_GN || + priv->config_bands & BAND_AN)) + nxpwifi_cmd_append_11n_tlv(priv, bss_desc, &pos); + + if (ISSUPP_11ACENABLED(adapter->fw_cap_info) && + !bss_desc->disable_11n && !bss_desc->disable_11ac && + (priv->config_bands & BAND_GAC || + priv->config_bands & BAND_AAC)) + nxpwifi_cmd_append_11ac_tlv(priv, bss_desc, &pos); + + if (ISSUPP_11AXENABLED(adapter->fw_cap_ext) && + nxpwifi_11ax_bandconfig_allowed(priv, bss_desc)) + nxpwifi_cmd_append_11ax_tlv(priv, bss_desc, &pos); + + /* Append vendor specific element TLV */ + nxpwifi_cmd_append_vsie_tlv(priv, NXPWIFI_VSIE_MASK_ASSOC, &pos); + + nxpwifi_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie, + bss_desc->bcn_ht_cap); + + if (priv->wps.session_enable && priv->wps_ie_len) + nxpwifi_cmd_append_wps_ie(priv, &pos); + + nxpwifi_cmd_append_generic_ie(priv, &pos); + + nxpwifi_cmd_append_tsf_tlv(priv, &pos, bss_desc); + + nxpwifi_11h_process_join(priv, &pos, bss_desc); + + cmd->size =3D cpu_to_le16((u16)(pos - (u8 *)assoc) + S_DS_GEN); + + /* Set the Capability info at last */ + tmp_cap =3D bss_desc->cap_info_bitmap; + + if (priv->config_bands =3D=3D BAND_B) + tmp_cap &=3D ~WLAN_CAPABILITY_SHORT_SLOT_TIME; + + tmp_cap &=3D CAPINFO_MASK; + nxpwifi_dbg(adapter, INFO, + "info: ASSOC_CMD: tmp_cap=3D%4X CAPINFO_MASK=3D%4lX\n", + tmp_cap, CAPINFO_MASK); + assoc->cap_info_bitmap =3D cpu_to_le16(tmp_cap); + + return ret; +} + +static const char *assoc_failure_reason_to_str(u16 cap_info) +{ + switch (cap_info) { + case CONNECT_ERR_AUTH_ERR_STA_FAILURE: + return "CONNECT_ERR_AUTH_ERR_STA_FAILURE"; + case CONNECT_ERR_AUTH_MSG_UNHANDLED: + return "CONNECT_ERR_AUTH_MSG_UNHANDLED"; + case CONNECT_ERR_ASSOC_ERR_TIMEOUT: + return "CONNECT_ERR_ASSOC_ERR_TIMEOUT"; + case CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED: + return "CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED"; + case CONNECT_ERR_STA_FAILURE: + return "CONNECT_ERR_STA_FAILURE"; + } + + return "Unknown connect failure"; +} + +/* + * Handle association command response. + * Parse cap_info/status_code/AID and copy IEs, update connection state, + * WMM and HT/HE parameters, queues and filters. On failure, return the + * IEEE status code or a mapped timeout error. + */ +int nxpwifi_ret_802_11_associate(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp) +{ + struct nxpwifi_adapter *adapter =3D priv->adapter; + int ret =3D 0; + struct ieee_types_assoc_rsp *assoc_rsp; + struct nxpwifi_bssdescriptor *bss_desc; + bool enable_data =3D true; + u16 cap_info, status_code, aid; + const u8 *ie_ptr; + struct ieee80211_ht_operation *assoc_resp_ht_oper; + struct ieee80211_mgmt *hdr; + + if (!priv->attempted_bss_desc) { + nxpwifi_dbg(adapter, ERROR, + "%s: failed, association terminated by host\n", + __func__); + goto done; + } + + hdr =3D (struct ieee80211_mgmt *)&resp->params; + if (!memcmp(hdr->bssid, priv->attempted_bss_desc->mac_address, + ETH_ALEN)) + assoc_rsp =3D (struct ieee_types_assoc_rsp *)&hdr->u.assoc_resp; + else + assoc_rsp =3D (struct ieee_types_assoc_rsp *)&resp->params; + + cap_info =3D le16_to_cpu(assoc_rsp->cap_info_bitmap); + status_code =3D le16_to_cpu(assoc_rsp->status_code); + aid =3D le16_to_cpu(assoc_rsp->a_id); + + if ((aid & (BIT(15) | BIT(14))) !=3D (BIT(15) | BIT(14))) + nxpwifi_dbg(adapter, ERROR, + "invalid AID value 0x%x; bits 15:14 not set\n", aid); + + aid &=3D ~(BIT(15) | BIT(14)); + + priv->assoc_rsp_size =3D min(le16_to_cpu(resp->size) - S_DS_GEN, + sizeof(priv->assoc_rsp_buf)); + + assoc_rsp->a_id =3D cpu_to_le16(aid); + memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size); + + if (status_code) { + adapter->dbg.num_cmd_assoc_failure++; + nxpwifi_dbg(adapter, ERROR, + "ASSOC_RESP: failed,\t" + "status code=3D%d err=3D%#x a_id=3D%#x\n", + status_code, cap_info, + le16_to_cpu(assoc_rsp->a_id)); + + nxpwifi_dbg(adapter, ERROR, "assoc failure: reason %s\n", + assoc_failure_reason_to_str(cap_info)); + if (cap_info =3D=3D CONNECT_ERR_ASSOC_ERR_TIMEOUT) { + if (status_code =3D=3D NXPWIFI_ASSOC_CMD_FAILURE_AUTH) { + ret =3D WLAN_STATUS_AUTH_TIMEOUT; + nxpwifi_dbg(adapter, ERROR, + "ASSOC_RESP: AUTH timeout\n"); + } else { + ret =3D WLAN_STATUS_UNSPECIFIED_FAILURE; + nxpwifi_dbg(adapter, ERROR, + "ASSOC_RESP: UNSPECIFIED failure\n"); + } + + priv->assoc_rsp_size =3D 0; + } else { + ret =3D status_code; + } + + goto done; + } + + /* Send a Media Connected event, according to the Spec */ + priv->media_connected =3D true; + + adapter->ps_state =3D PS_STATE_AWAKE; + adapter->pps_uapsd_mode =3D false; + adapter->tx_lock_flag =3D false; + + /* Set the attempted BSSID Index to current */ + bss_desc =3D priv->attempted_bss_desc; + + nxpwifi_dbg(adapter, INFO, "info: ASSOC_RESP: %s\n", + bss_desc->ssid.ssid); + + /* Make a copy of current BSSID descriptor */ + memcpy(&priv->curr_bss_params.bss_descriptor, + bss_desc, sizeof(struct nxpwifi_bssdescriptor)); + + /* Update curr_bss_params */ + priv->curr_bss_params.bss_descriptor.channel =3D + bss_desc->phy_param_set.ds_param_set.current_chan; + + priv->curr_bss_params.band =3D (u8)bss_desc->bss_band; + + if (bss_desc->wmm_ie.element_id =3D=3D WLAN_EID_VENDOR_SPECIFIC) + priv->curr_bss_params.wmm_enabled =3D true; + else + priv->curr_bss_params.wmm_enabled =3D false; + + if ((priv->wmm_required || bss_desc->bcn_ht_cap) && + priv->curr_bss_params.wmm_enabled) + priv->wmm_enabled =3D true; + else + priv->wmm_enabled =3D false; + + priv->curr_bss_params.wmm_uapsd_enabled =3D false; + + if (priv->wmm_enabled) + priv->curr_bss_params.wmm_uapsd_enabled =3D + ((bss_desc->wmm_ie.qos_info & + IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0); + + /* Store the bandwidth information from assoc response */ + ie_ptr =3D cfg80211_find_ie(WLAN_EID_HT_OPERATION, assoc_rsp->ie_buffer, + priv->assoc_rsp_size + - sizeof(struct ieee_types_assoc_rsp)); + if (ie_ptr) { + assoc_resp_ht_oper =3D (struct ieee80211_ht_operation *)(ie_ptr + + sizeof(struct element)); + priv->assoc_resp_ht_param =3D assoc_resp_ht_oper->ht_param; + priv->ht_param_present =3D true; + } else { + priv->ht_param_present =3D false; + } + + nxpwifi_dbg(adapter, INFO, + "info: ASSOC_RESP: curr_pkt_filter is %#x\n", + priv->curr_pkt_filter); + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + priv->wpa_is_gtk_set =3D false; + + if (priv->wmm_enabled) { + /* Don't re-enable carrier until we get the WMM_GET_STATUS event */ + enable_data =3D false; + } else { + /* Since WMM is not enabled, setup the queues with the defaults */ + nxpwifi_wmm_setup_queue_priorities(priv, NULL); + nxpwifi_wmm_setup_ac_downgrade(priv); + } + + if (enable_data) + nxpwifi_dbg(adapter, INFO, + "info: post association, re-enabling data flow\n"); + + /* Reset SNR/NF/RSSI values */ + priv->data_rssi_last =3D 0; + priv->data_nf_last =3D 0; + priv->data_rssi_avg =3D 0; + priv->data_nf_avg =3D 0; + priv->bcn_rssi_last =3D 0; + priv->bcn_nf_last =3D 0; + priv->bcn_rssi_avg =3D 0; + priv->bcn_nf_avg =3D 0; + priv->rxpd_rate =3D 0; + priv->rxpd_htinfo =3D 0; + + nxpwifi_save_curr_bcn(priv); + + adapter->dbg.num_cmd_assoc_success++; + + nxpwifi_dbg(adapter, MSG, "assoc: associated with %pM\n", + priv->attempted_bss_desc->mac_address); + + /* Add the ra_list here for infra mode as there will be only 1 ra always = */ + nxpwifi_ralist_add(priv, + priv->curr_bss_params.bss_descriptor.mac_address); + + netif_carrier_on(priv->netdev); + nxpwifi_wake_up_net_dev_queue(priv->netdev, adapter); + + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + priv->scan_block =3D true; + else + priv->port_open =3D true; + +done: + /* Need to indicate IOCTL complete */ + if (adapter->curr_cmd->wait_q_enabled) { + if (ret) + adapter->cmd_wait_q.status =3D -1; + else + adapter->cmd_wait_q.status =3D 0; + } + + return ret; +} + +/* Associate to the specified BSS (STA only) */ +int nxpwifi_associate(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc) +{ + /* + * Return error if the adapter is not STA role or table entry + * is not marked as infra. + */ + if ((GET_BSS_ROLE(priv) !=3D NXPWIFI_BSS_ROLE_STA) || + bss_desc->bss_mode !=3D NL80211_IFTYPE_STATION) + return -EINVAL; + + if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && + !bss_desc->disable_11n && !bss_desc->disable_11ac && + priv->config_bands & BAND_AAC) + nxpwifi_set_11ac_ba_params(priv); + else + nxpwifi_set_ba_params(priv); + + /* + * Clear any past association response stored for application + * retrieval + */ + priv->assoc_rsp_size =3D 0; + + return nxpwifi_send_cmd(priv, HOST_CMD_802_11_ASSOCIATE, + HOST_ACT_GEN_SET, 0, bss_desc, true); +} + +/* Send deauth to disconnect from an infrastructure BSS */ +static int nxpwifi_deauthenticate_infra(struct nxpwifi_private *priv, u8 *= mac) +{ + u8 mac_address[ETH_ALEN]; + int ret; + + if (!mac || is_zero_ether_addr(mac)) + memcpy(mac_address, + priv->curr_bss_params.bss_descriptor.mac_address, + ETH_ALEN); + else + memcpy(mac_address, mac, ETH_ALEN); + + ret =3D nxpwifi_send_cmd(priv, HOST_CMD_802_11_DEAUTHENTICATE, + HOST_ACT_GEN_SET, 0, mac_address, true); + + return ret; +} + +/* Disconnect from the current BSS (STA/P2P/AP) */ +int nxpwifi_deauthenticate(struct nxpwifi_private *priv, u8 *mac) +{ + int ret =3D 0; + + if (!priv->media_connected) + return 0; + + priv->auth_flag =3D 0; + priv->auth_alg =3D WLAN_AUTH_NONE; + priv->host_mlme_reg =3D false; + priv->mgmt_frame_mask =3D 0; + + ret =3D nxpwifi_send_cmd(priv, HOST_CMD_MGMT_FRAME_REG, + HOST_ACT_GEN_SET, 0, + &priv->mgmt_frame_mask, false); + if (ret) { + nxpwifi_dbg(priv->adapter, ERROR, + "could not unregister mgmt frame rx\n"); + return ret; + } + + switch (priv->bss_mode) { + case NL80211_IFTYPE_STATION: + ret =3D nxpwifi_deauthenticate_infra(priv, mac); + if (ret) + cfg80211_disconnected(priv->netdev, 0, NULL, 0, + true, GFP_KERNEL); + break; + case NL80211_IFTYPE_AP: + ret =3D nxpwifi_send_cmd(priv, HOST_CMD_UAP_BSS_STOP, + HOST_ACT_GEN_SET, 0, NULL, true); + default: + break; + } + + return ret; +} + +/* Deauthenticate/disconnect from all BSS. */ +void nxpwifi_deauthenticate_all(struct nxpwifi_adapter *adapter) +{ + struct nxpwifi_private *priv; + int i; + + for (i =3D 0; i < adapter->priv_num; i++) { + priv =3D adapter->priv[i]; + nxpwifi_deauthenticate(priv, NULL); + } +} +EXPORT_SYMBOL_GPL(nxpwifi_deauthenticate_all); + +/* Convert band to radio type used in channel TLV. */ +u8 nxpwifi_band_to_radio_type(u16 config_bands) +{ + if (config_bands & BAND_A || config_bands & BAND_AN || + config_bands & BAND_AAC || config_bands & BAND_AAX) + return HOST_SCAN_RADIO_TYPE_A; + + return HOST_SCAN_RADIO_TYPE_BG; +} --=20 2.34.1