3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-19 11:09:25 +01:00

eap-wsc: Add RX fragmentation support

This commit is contained in:
Tim Kourt 2016-11-07 13:55:28 -08:00 committed by Denis Kenzior
parent fe90dcaab4
commit 92ece898d1

View File

@ -35,7 +35,8 @@
#include "util.h"
#include "eap-wsc.h"
#define EAP_WSC_HEADER_LEN 14
#define EAP_WSC_HEADER_LEN 14
#define EAP_WSC_PDU_MAX_LEN 4096
/* WSC v2.0.5, Section 7.7.1 */
enum wsc_op {
@ -82,6 +83,9 @@ struct eap_wsc_state {
enum state state;
struct l_checksum *hmac_auth_key;
struct l_cipher *aes_cbc_128;
uint8_t *rx_pdu_buf;
size_t rx_pdu_buf_len;
size_t rx_pdu_buf_offset;
size_t tx_frag_offset;
};
@ -291,6 +295,13 @@ static void eap_wsc_remove(struct eap_state *eap)
wsc->sent_pdu = NULL;
wsc->sent_len = 0;
if (wsc->rx_pdu_buf) {
l_free(wsc->rx_pdu_buf);
wsc->rx_pdu_buf = NULL;
wsc->rx_pdu_buf_len = 0;
wsc->rx_pdu_buf_offset = 0;
}
l_checksum_free(wsc->hmac_auth_key);
l_cipher_free(wsc->aes_cbc_128);
@ -436,6 +447,16 @@ static void eap_wsc_send_done(struct eap_state *eap)
l_free(pdu);
}
static void eap_wsc_send_frag_ack(struct eap_state *eap)
{
uint8_t buf[EAP_WSC_HEADER_LEN];
buf[12] = WSC_OP_FRAG_ACK;
buf[13] = 0;
eap_send_response(eap, EAP_TYPE_EXPANDED, buf, EAP_WSC_HEADER_LEN);
}
static void eap_wsc_handle_m8(struct eap_state *eap,
const uint8_t *pdu, size_t len)
{
@ -872,6 +893,7 @@ static void eap_wsc_handle_request(struct eap_state *eap,
uint8_t flags;
uint8_t *pdu;
size_t pdu_len;
size_t rx_header_offset = 0;
if (len < 2)
return;
@ -882,10 +904,6 @@ static void eap_wsc_handle_request(struct eap_state *eap,
pkt += 2;
len -= 2;
/* TODO: Handle fragmentation */
if (flags != 0)
return;
switch (op) {
case WSC_OP_START:
if (len)
@ -916,6 +934,66 @@ static void eap_wsc_handle_request(struct eap_state *eap,
eap_wsc_send_fragment(eap);
return;
case WSC_OP_MSG:
if (flags & WSC_FLAG_LF) {
if (wsc->rx_pdu_buf ||
!(flags & WSC_FLAG_MF) || len < 2)
goto invalid_frag;
wsc->rx_pdu_buf_len = l_get_be16(pkt);
if (!wsc->rx_pdu_buf_len ||
wsc->rx_pdu_buf_len >
EAP_WSC_PDU_MAX_LEN) {
l_warn("Fragmented pkt size is outside of "
"alowed boundaries [1, %u]",
EAP_WSC_PDU_MAX_LEN);
return;
}
if (wsc->rx_pdu_buf_len < len) {
l_warn("Fragmented pkt size is smaller than "
"the received packet");
return;
}
wsc->rx_pdu_buf = l_malloc(wsc->rx_pdu_buf_len);
wsc->rx_pdu_buf_offset = 0;
rx_header_offset = 2;
}
if (wsc->rx_pdu_buf) {
pdu_len = len - rx_header_offset;
if (wsc->rx_pdu_buf_len <
(wsc->rx_pdu_buf_offset + pdu_len)) {
l_error("Request fragment pkt size mismatch");
goto invalid_frag;
}
memcpy(wsc->rx_pdu_buf + wsc->rx_pdu_buf_offset,
pkt + rx_header_offset, pdu_len);
wsc->rx_pdu_buf_offset += pdu_len;
}
if (flags & WSC_FLAG_MF) {
if (!wsc->rx_pdu_buf) {
eap_method_error(eap);
return;
}
eap_wsc_send_frag_ack(eap);
return;
} else if (wsc->rx_pdu_buf) {
if (wsc->rx_pdu_buf_len != wsc->rx_pdu_buf_offset) {
l_error("Request fragment pkt size mismatch");
goto invalid_frag;
}
pkt = wsc->rx_pdu_buf;
len = wsc->rx_pdu_buf_len;
}
break;
}
@ -941,6 +1019,18 @@ static void eap_wsc_handle_request(struct eap_state *eap,
eap_wsc_send_nack(eap, WSC_CONFIGURATION_ERROR_NO_ERROR);
return;
}
if (wsc->rx_pdu_buf) {
l_free(wsc->rx_pdu_buf);
wsc->rx_pdu_buf = NULL;
wsc->rx_pdu_buf_len = 0;
wsc->rx_pdu_buf_offset = 0;
}
return;
invalid_frag:
eap_method_error(eap);
}
static bool load_hexencoded(struct l_settings *settings, const char *key,