From patchwork Fri May 31 06:54:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brendan Jackman X-Patchwork-Id: 1108185 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=bluwireless.co.uk Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="m0jFK7TB"; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=bluewireless.onmicrosoft.com header.i=@bluewireless.onmicrosoft.com header.b="XE7OwtBg"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45FZvW40pHz9s00 for ; Fri, 31 May 2019 16:55:03 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-ID:Date:Subject:To :From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=kwTlDbr/DFxCEUYm6x+kSOAdgMSGqUTXzT4wdiUrrq8=; b=m0jFK7TBfjEAi5 5acVsl96JO6h+hmTNbYBcuc7/7dH+RnmneZi3pNHOU9ESnRfW2CB4le4gBSHeK72EXu1ZITzcZh23 FW6XEi5FKbLIhEe2ugw2nrM1fx19pFSbzJoK6GO7yI3twtsBtGqVnDEPsbrVVoOiD5us5Vqi2vP1o hzYqGOj8kxNHvhQ004nhqBTAewTesNYW6MwjfGEesfJG8nCqgMH3Cyb0OkFicS26MQhWIeTAzLxuf Tg+qYOoicYOv2g1kaCkm6NcwddEDZY2P5htVeZoNw29BsntbCXe62nbIX/xOLTCL3UPC9ol/gpX1B b8X2XVpGVro5OYDwWBuw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hWbRL-0001Nh-9G; Fri, 31 May 2019 06:54:59 +0000 Received: from mail-eopbgr130084.outbound.protection.outlook.com ([40.107.13.84] helo=EUR01-HE1-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1hWbRF-0001Lk-5p for hostap@lists.infradead.org; Fri, 31 May 2019 06:54:55 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bluewireless.onmicrosoft.com; s=selector2-bluewireless-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=hHlvhp4tEN+ZoDWdUNXBmxwafnRrGUup/6HtK4uMQ/g=; b=XE7OwtBgAMALWjnqtJUsYJ/oLOwbyN1ucrK6IR4fNL2g6kOehmfa1phQv4pN2P8GAmcl8Oy9Q2aGzLOEvTs1cKz6cF6h78Yk5hiaRRFOuyBHfTaD1dSRsNp6Djx4BlvBrGC/liSqbeDTVFu7biVPm4ONmcmBjKeF7V0/+7nmZNo= Received: from AM0PR09MB3362.eurprd09.prod.outlook.com (20.179.253.213) by AM0PR09MB2786.eurprd09.prod.outlook.com (20.178.119.14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1943.18; Fri, 31 May 2019 06:54:48 +0000 Received: from AM0PR09MB3362.eurprd09.prod.outlook.com ([fe80::1ef:eeb4:6106:a796]) by AM0PR09MB3362.eurprd09.prod.outlook.com ([fe80::1ef:eeb4:6106:a796%3]) with mapi id 15.20.1922.021; Fri, 31 May 2019 06:54:47 +0000 From: Brendan Jackman To: "hostap@lists.infradead.org" Subject: [PATCH] wpa_supplicant: Send EAPoL-Key frames over NL80211 where available Thread-Topic: [PATCH] wpa_supplicant: Send EAPoL-Key frames over NL80211 where available Thread-Index: AQHVF328QKm0fpcXT0GDBW8fjRrrCA== Date: Fri, 31 May 2019 06:54:47 +0000 Message-ID: <20190531065426.25654-1-brendan.jackman@bluwireless.co.uk> Accept-Language: en-GB, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: SG2PR0601CA0001.apcprd06.prod.outlook.com (2603:1096:3::11) To AM0PR09MB3362.eurprd09.prod.outlook.com (2603:10a6:208:170::21) authentication-results: spf=none (sender IP is ) smtp.mailfrom=brendan.jackman@bluwireless.com; x-ms-exchange-messagesentrepresentingtype: 1 x-mailer: git-send-email 2.17.1 x-originating-ip: [222.252.15.82] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 06342e83-6163-46ce-9f41-08d6e594deba x-microsoft-antispam: BCL:0; PCL:0; RULEID:(2390118)(7020095)(4652040)(8989299)(5600148)(711020)(4605104)(1401327)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(2017052603328)(7193020); SRVR:AM0PR09MB2786; x-ms-traffictypediagnostic: AM0PR09MB2786: x-ms-exchange-purlcount: 1 x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:8273; x-forefront-prvs: 00540983E2 x-forefront-antispam-report: SFV:NSPM; SFS:(10009020)(366004)(136003)(376002)(396003)(39850400004)(346002)(189003)(199004)(6916009)(305945005)(2351001)(186003)(81156014)(50226002)(42882007)(1730700003)(8676002)(8936002)(68736007)(6486002)(6436002)(5640700003)(6512007)(6306002)(7736002)(102836004)(74482002)(73956011)(66476007)(64756008)(66446008)(66556008)(66946007)(26005)(386003)(6506007)(476003)(2616005)(44832011)(486006)(2906002)(36756003)(71200400001)(71190400001)(256004)(14444005)(3846002)(6116002)(2501003)(52116002)(14454004)(30864003)(99286004)(478600001)(1076003)(966005)(316002)(66066001)(81166006)(107886003)(54906003)(4326008)(5660300002)(53936002)(25786009); DIR:OUT; SFP:1101; SCL:1; SRVR:AM0PR09MB2786; H:AM0PR09MB3362.eurprd09.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; MX:1; A:1; received-spf: None (protection.outlook.com: bluwireless.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 x-microsoft-antispam-message-info: hgnAwPNpJSWzLA5g5eB7oIC9VEbvI+hzrBkfNpwQfFF9hw67+B4oQrEQSLq+kSJLH0T5hbJEWb0dbwwijcfzhNmcIUfUNMQRe+I+rqWUNHLTDz23zVpW4HHB+/g+eN4+eVfiXRZYkjs7E2iCkDANj1HJMz2WV9J3kmpp70XQFWPYdT79/xYfyOmWCjvFVsiN6YmXp6o/E+RkUR/zobZRRjUlbzYfFfqPjX7g6aPdKZdqrhOmqdYQzCw5rwvrvmCf56SEqFHM7+0NAqlG2cU67O7u04lGh6JRf1YuKwW74yvslpxNwGYLeEAShYXnMSPQCevLq8t9z6OihTmmMhOuhGzOiz7GXuWT81hEKSRQKE9/atqQ9XXbgYKBCyF4/dMjhltmsvJBd/JY4C8+hAb4pK1nte3c3YLoAeXKM6pf9Tg= MIME-Version: 1.0 X-OriginatorOrg: bluwireless.co.uk X-MS-Exchange-CrossTenant-Network-Message-Id: 06342e83-6163-46ce-9f41-08d6e594deba X-MS-Exchange-CrossTenant-originalarrivaltime: 31 May 2019 06:54:47.7814 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: e906b266-f5ff-4368-b47b-0f526edbc2b5 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: brendan.jackman@bluwireless.com X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM0PR09MB2786 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190530_235453_442070_81CB6C4E X-CRM114-Status: GOOD ( 24.62 ) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [40.107.13.84 listed in list.dnswl.org] -0.0 SPF_HELO_PASS SPF: HELO matches SPF record 0.0 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Chaitanya Tata , Antony King Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Linux kernel v4.17 added the ability to request sending control port frames via NL80211 instead of a normal network socket. Doing this provides the device driver with ordering information between the control port frames and the installation of keys. This empowers it to avoid race conditions between, for example, PTK replacement and the sending of frame 4 of the 4-way rekeying handshake in an RSNA. This patch adds a TX_CONTROL_PORT flag to the hostap driver API to report that it supports, for a given device, a new operation called tx_control_port. This operation is exactly like an ethernet send except for the extra ordering information it provides for device drivers. The nl80211 driver is updated to support this operation when the device reports the CONTROL_PORT_OVER_NL80211 extended feature. Finally the RSN supplicant system is updated to use this new operation for sending EAPoL-Key frames when the driver reports that it is available; otherwise falling back to a normal ethernet TX. There may be other cases than these EAPoL-Key frames that would benefit from using the new operation but I do not know of them. I have tested this on DMG (11ad/ay) devices with an out-of-tree Linux driver that does not use mac80211. Without this patch I consistently see PTK rekeying fail if message 4/4 shares a stream with other in-flight traffic. With this patch, and the driver updated to flush the relevant TX queue before overwriting a PTK (knowing, now, that if there was a message 4/4 related to the key installation, it has already entered the driver queue), rekeying is reliable. There is still data loss surrounding key installation - this problem is alluded to in 802.11-2016 12.6.21, where extended Key ID support is described as the eventual solution. This patch aims to at least prevent rekeying from totally breaking the association, in a way that works on kernels as far back as 4.17 (as per Alexander Wetzel extended Key ID support should be possible on 5.2). See http://lists.infradead.org/pipermail/hostap/2019-May/040089.html for a little more context. Cc: Chaitanya Tata Cc: Antony King Signed-off-by: Brendan Jackman --- src/drivers/driver.h | 26 +++++++++++++ src/drivers/driver_nl80211.c | 39 ++++++++++++++++++++ src/drivers/driver_nl80211_capa.c | 4 ++ src/rsn_supp/wpa.c | 2 +- src/rsn_supp/wpa.h | 2 + src/rsn_supp/wpa_i.h | 7 ++++ wpa_supplicant/driver_i.h | 8 ++++ wpa_supplicant/ibss_rsn.c | 18 +++++++++ wpa_supplicant/wpas_glue.c | 61 ++++++++++++++++++++++++------- 9 files changed, 153 insertions(+), 14 deletions(-) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 496bd522e..7cf1582ce 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1625,6 +1625,8 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_FTM_RESPONDER 0x0100000000000000ULL /** Driver support 4-way handshake offload for WPA-Personal */ #define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK 0x0200000000000000ULL +/** Driver has working tx_control_port */ +#define WPA_DRIVER_FLAGS_TX_CONTROL_PORT 0x0400000000000000ULL u64 flags; #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \ @@ -2280,6 +2282,30 @@ struct wpa_driver_ops { const u8 *seq, size_t seq_len, const u8 *key, size_t key_len); + /** + * tx_control_port - Send a frame over the 802.1X controlled port + * @priv: private driver interface data + * @dest: Destination MAC address + * @proto: Ethertype in host byte order + * @buf: Frame payload starting from IEEE 802.1X header + * @len: Frame payload length + * + * Returns 0 on success, else an error + * + * This is like a normal ethernet send except that the OS device driver + * is aware (by other means than the ethertype) that this frame is + * ~special~, and more importantly it gains an ordering between the + * transmission of the frame and other driver operations such as key + * installations. This can be used to work around known limitations in + * 802.11 protocols such as race conditions between 802.1X rekeying + * handshake message 4/4 and a PTK being overwritten. + * + * This function is only implemented for a given interface if the driver + * instance reports WPA_DRIVER_FLAGS_TX_CONTROL_PORT. Otherwise API + * users should fall back to sending the frame via a normal socket. + */ + int (*tx_control_port)(void *priv, const u8 *dest, + u16 proto, const u8 *buf, size_t len); /** * init - Initialize driver interface * @ctx: context to be used when calling wpa_supplicant functions, diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 3556b6d69..b1d0220e9 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -3007,6 +3007,44 @@ static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv, } +static int driver_nl80211_tx_control_port(void *priv, const u8 *dest, + u16 proto, const u8 *buf, size_t len) +{ + struct i802_bss *bss = priv; + struct nl_msg *msg = NULL; + int ifindex = if_nametoindex(bss->ifname); + int ret = 0; + + wpa_printf(MSG_DEBUG, + "nl80211: tx_control_port "MACSTR" proto=0x%04x len=%zu", + MAC2STR(dest), proto, len); + + msg = nl80211_ifindex_msg(bss->drv, ifindex, 0, + NL80211_CMD_CONTROL_PORT_FRAME); + if (!msg) + return -ENOBUFS; + + if (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto)) + goto fail; + if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dest)) + goto fail; + if (nla_put(msg, NL80211_ATTR_FRAME, len, buf)) + goto fail; + + ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL); + if (ret) + wpa_printf(MSG_DEBUG, + "nl80211: tx_control_port failed: ret=%d (%s)", + ret, strerror(ret)); + + return ret; + +fail: + nl80211_nlmsg_clear(msg); + nlmsg_free(msg); + return -ENOBUFS; +} + static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, @@ -10940,6 +10978,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .get_bssid = wpa_driver_nl80211_get_bssid, .get_ssid = wpa_driver_nl80211_get_ssid, .set_key = driver_nl80211_set_key, + .tx_control_port = driver_nl80211_tx_control_port, .scan2 = driver_nl80211_scan2, .sched_scan = wpa_driver_nl80211_sched_scan, .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan, diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index a90a55db8..f87621003 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -433,6 +433,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info, if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER)) capa->flags |= WPA_DRIVER_FLAGS_FTM_RESPONDER; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211)) + capa->flags |= WPA_DRIVER_FLAGS_TX_CONTROL_PORT; } diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index e0039fac0..aecabac0b 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -158,7 +158,7 @@ int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk, } wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len); - ret = wpa_sm_ether_send(sm, dest, proto, msg, msg_len); + ret = wpa_sm_tx_control_port(sm, dest, proto, msg, msg_len); eapol_sm_notify_tx_eapol_key(sm->eapol); out: os_free(msg); diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index ae9cd6484..145d57988 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -33,6 +33,8 @@ struct wpa_sm_ctx { const u8 *key, size_t key_len); void * (*get_network_ctx)(void *ctx); int (*get_bssid)(void *ctx, u8 *bssid); + int (*tx_control_port)(void *ctx, const u8 *dest, u16 proto, + const u8 *buf, size_t len); int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf, size_t len); int (*get_beacon_ie)(void *ctx); diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index d86734b0d..908af3d25 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -216,6 +216,13 @@ static inline int wpa_sm_get_bssid(struct wpa_sm *sm, u8 *bssid) return sm->ctx->get_bssid(sm->ctx->ctx, bssid); } +static inline int wpa_sm_tx_control_port(struct wpa_sm *sm, const u8 *dest, + u16 proto, const u8 *buf, size_t len) +{ + WPA_ASSERT(sm->ctx->tx_control_port); + return sm->ctx->tx_control_port(sm->ctx->ctx, dest, proto, buf, len); +} + static inline int wpa_sm_ether_send(struct wpa_sm *sm, const u8 *dest, u16 proto, const u8 *buf, size_t len) { diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index f073b8a6d..2372344fa 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -138,6 +138,14 @@ static inline int wpa_drv_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid) return -1; } +static inline int wpa_drv_tx_contol_port(struct wpa_supplicant *wpa_s, + const u8 *dest, + u16 proto, const u8 *buf, size_t len) +{ + return wpa_s->driver->tx_control_port(wpa_s->drv_priv, + dest, proto, buf, len); +} + static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c index 6934c4725..cdadadee1 100644 --- a/wpa_supplicant/ibss_rsn.c +++ b/wpa_supplicant/ibss_rsn.c @@ -76,6 +76,23 @@ static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf, } +static int supp_tx_control_port(void *ctx, const u8 *dest, u16 proto, + const u8 *buf, size_t len) +{ + struct ibss_rsn_peer *peer = ctx; + struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s; + + wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x " + "len=%lu)", + __func__, MAC2STR(dest), proto, (unsigned long) len); + + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TX_CONTROL_PORT) + return wpa_drv_tx_contol_port(wpa_s, dest, proto, buf, len); + else + return supp_ether_send(wpa_s, dest, proto, buf, len); +} + + static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data, u16 data_len, size_t *msg_len, void **data_pos) { @@ -211,6 +228,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, ctx->set_state = supp_set_state; ctx->get_state = supp_get_state; ctx->ether_send = supp_ether_send; + ctx->tx_control_port = supp_tx_control_port; ctx->get_beacon_ie = supp_get_beacon_ie; ctx->alloc_eapol = supp_alloc_eapol; ctx->set_key = supp_set_key; diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index e98bf1147..6f5c301f8 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -85,17 +85,9 @@ static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type, } -/** - * wpa_ether_send - Send Ethernet frame - * @wpa_s: Pointer to wpa_supplicant data - * @dest: Destination MAC address - * @proto: Ethertype in host byte order - * @buf: Frame payload starting from IEEE 802.1X header - * @len: Frame payload length - * Returns: >=0 on success, <0 on failure - */ -static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, - u16 proto, const u8 *buf, size_t len) +static inline int ext_eapol_frame_io_notify_tx(struct wpa_supplicant *wpa_s, + const u8 *dest, u16 proto, + const u8 *buf, size_t len) { #ifdef CONFIG_TESTING_OPTIONS if (wpa_s->ext_eapol_frame_io && proto == ETH_P_EAPOL) { @@ -108,18 +100,60 @@ static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, wpa_msg(wpa_s, MSG_INFO, "EAPOL-TX " MACSTR " %s", MAC2STR(dest), hex); os_free(hex); - return 0; + return -1; } #endif /* CONFIG_TESTING_OPTIONS */ + return 0; +} + +/** + * wpa_ether_send - Send Ethernet frame + * @wpa_s: Pointer to wpa_supplicant data + * @dest: Destination MAC address + * @proto: Ethertype in host byte order + * @buf: Frame payload starting from IEEE 802.1X header + * @len: Frame payload length + * Returns: >=0 on success, <0 on failure + */ +static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, + u16 proto, const u8 *buf, size_t len) +{ + if (ext_eapol_frame_io_notify_tx(wpa_s, dest, proto, buf, len)) + return 0; + if (wpa_s->l2) { return l2_packet_send(wpa_s->l2, dest, proto, buf, len); } return -1; } -#endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */ +/** + * wpa_supplicant_tx_control_port - Send Ethernet frame over 802.1X control port + * @wpa_s: Pointer to wpa_supplicant data + * @dest: Destination MAC address + * @proto: Ethertype in host byte order + * @buf: Frame payload starting from IEEE 802.1X header + * @len: Frame payload length + * Just like wpa_ether_send, but when this function is used the driver may be + * able to handle control port frames specially. + * Returns: >=0 on success, <0 on failure + */ +static int wpa_supplicant_tx_control_port(void *ctx, const u8 *dest, + u16 proto, const u8 *buf, size_t len) +{ + struct wpa_supplicant *wpa_s = ctx; + + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TX_CONTROL_PORT) { + if (ext_eapol_frame_io_notify_tx(wpa_s, dest, proto, buf, len)) + return 0; + return wpa_drv_tx_contol_port(wpa_s, dest, proto, buf, len); + } else { + return wpa_ether_send(wpa_s, dest, proto, buf, len); + } +} +#endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */ #ifdef IEEE8021X_EAPOL @@ -1214,6 +1248,7 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) ctx->get_network_ctx = wpa_supplicant_get_network_ctx; ctx->get_bssid = wpa_supplicant_get_bssid; ctx->ether_send = _wpa_ether_send; + ctx->tx_control_port = wpa_supplicant_tx_control_port; ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie; ctx->alloc_eapol = _wpa_alloc_eapol; ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout;