mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2025-01-03 10:32:33 +01:00
peap: handle fragmented request
This commit is contained in:
parent
bcf9ec5922
commit
84be0eb8d3
123
src/eap-peap.c
123
src/eap-peap.c
@ -31,6 +31,8 @@
|
||||
|
||||
#include "eap.h"
|
||||
|
||||
#define PEAP_PDU_MAX_LEN 65536
|
||||
|
||||
enum peap_version {
|
||||
PEAP_VERSION_0 = 0x00,
|
||||
PEAP_VERSION_1 = 0x01,
|
||||
@ -42,6 +44,8 @@ enum peap_version {
|
||||
enum peap_flag {
|
||||
/* Reserved = 0x00, */
|
||||
PEAP_FLAG_S = 0x20,
|
||||
PEAP_FLAG_M = 0x40,
|
||||
PEAP_FLAG_L = 0x80,
|
||||
};
|
||||
|
||||
struct eap_peap_state {
|
||||
@ -51,6 +55,10 @@ struct eap_peap_state {
|
||||
uint8_t *tx_pdu_buf;
|
||||
size_t tx_pdu_buf_len;
|
||||
|
||||
uint8_t *rx_pdu_buf;
|
||||
size_t rx_pdu_buf_len;
|
||||
size_t rx_pdu_buf_offset;
|
||||
|
||||
char *ca_cert;
|
||||
char *client_cert;
|
||||
char *client_key;
|
||||
@ -69,6 +77,19 @@ static void eap_peap_free_tx_buffer(struct eap_state *eap)
|
||||
peap->tx_pdu_buf_len = 0;
|
||||
}
|
||||
|
||||
static void eap_peap_free_rx_buffer(struct eap_state *eap)
|
||||
{
|
||||
struct eap_peap_state *peap = eap_get_data(eap);
|
||||
|
||||
if (!peap->rx_pdu_buf)
|
||||
return;
|
||||
|
||||
l_free(peap->rx_pdu_buf);
|
||||
peap->rx_pdu_buf = NULL;
|
||||
peap->rx_pdu_buf_len = 0;
|
||||
peap->rx_pdu_buf_offset = 0;
|
||||
}
|
||||
|
||||
static void eap_peap_free(struct eap_state *eap)
|
||||
{
|
||||
struct eap_peap_state *peap = eap_get_data(eap);
|
||||
@ -80,6 +101,8 @@ static void eap_peap_free(struct eap_state *eap)
|
||||
|
||||
eap_peap_free_tx_buffer(eap);
|
||||
|
||||
eap_peap_free_rx_buffer(eap);
|
||||
|
||||
eap_set_data(eap, NULL);
|
||||
|
||||
l_free(peap->ca_cert);
|
||||
@ -95,6 +118,10 @@ static void eap_peap_send_response(struct eap_state *eap,
|
||||
{
|
||||
}
|
||||
|
||||
static void eap_peap_send_empty_response(struct eap_state *eap)
|
||||
{
|
||||
}
|
||||
|
||||
static void eap_peap_tunnel_data_send(const uint8_t *data, size_t data_len,
|
||||
void *user_data)
|
||||
{
|
||||
@ -151,6 +178,41 @@ static void eap_peap_handle_payload(struct eap_state *eap,
|
||||
{
|
||||
}
|
||||
|
||||
static bool eap_peap_init_request_assembly(struct eap_state *eap,
|
||||
const uint8_t *pkt, size_t len,
|
||||
uint8_t flags) {
|
||||
struct eap_peap_state *peap = eap_get_data(eap);
|
||||
|
||||
if (peap->rx_pdu_buf || !(flags & PEAP_FLAG_M) || len < 4)
|
||||
return false;
|
||||
|
||||
peap->rx_pdu_buf_len = l_get_be32(pkt);
|
||||
|
||||
if (!peap->rx_pdu_buf_len || peap->rx_pdu_buf_len > PEAP_PDU_MAX_LEN) {
|
||||
l_warn("Fragmented pkt size is outside of alowed boundaries "
|
||||
"[1, %u]", PEAP_PDU_MAX_LEN);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (peap->rx_pdu_buf_len < len) {
|
||||
l_warn("Fragmented pkt size is smaller than the received "
|
||||
"packet");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
peap->rx_pdu_buf = l_malloc(peap->rx_pdu_buf_len);
|
||||
peap->rx_pdu_buf_offset = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void eap_peap_send_fragmented_request_ack(struct eap_state *eap)
|
||||
{
|
||||
eap_peap_send_empty_response(eap);
|
||||
}
|
||||
|
||||
static bool eap_peap_validate_version(struct eap_state *eap,
|
||||
uint8_t flags_version)
|
||||
{
|
||||
@ -172,6 +234,46 @@ static bool eap_peap_validate_version(struct eap_state *eap,
|
||||
return true;
|
||||
}
|
||||
|
||||
static int eap_peap_handle_fragmented_request(struct eap_state *eap,
|
||||
const uint8_t *pkt,
|
||||
size_t len,
|
||||
uint8_t flags_version)
|
||||
{
|
||||
struct eap_peap_state *peap = eap_get_data(eap);
|
||||
size_t rx_header_offset = 0;
|
||||
size_t pdu_len;
|
||||
|
||||
if (flags_version & PEAP_FLAG_L) {
|
||||
if (!eap_peap_init_request_assembly(eap, pkt, len,
|
||||
flags_version))
|
||||
return -EINVAL;
|
||||
|
||||
rx_header_offset = 4;
|
||||
}
|
||||
|
||||
if (!peap->rx_pdu_buf)
|
||||
return -EINVAL;
|
||||
|
||||
pdu_len = len - rx_header_offset;
|
||||
|
||||
if (peap->rx_pdu_buf_len < peap->rx_pdu_buf_offset + pdu_len) {
|
||||
l_error("Request fragment pkt size mismatch");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(peap->rx_pdu_buf + peap->rx_pdu_buf_offset,
|
||||
pkt + rx_header_offset, pdu_len);
|
||||
peap->rx_pdu_buf_offset += pdu_len;
|
||||
|
||||
if (flags_version & PEAP_FLAG_M) {
|
||||
eap_peap_send_fragmented_request_ack(eap);
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void eap_peap_handle_request(struct eap_state *eap,
|
||||
const uint8_t *pkt, size_t len)
|
||||
{
|
||||
@ -193,6 +295,25 @@ static void eap_peap_handle_request(struct eap_state *eap,
|
||||
pkt += 1;
|
||||
len -= 1;
|
||||
|
||||
if (flags_version & PEAP_FLAG_L || peap->rx_pdu_buf) {
|
||||
int r = eap_peap_handle_fragmented_request(eap, pkt, len,
|
||||
flags_version);
|
||||
|
||||
if (r == -EAGAIN)
|
||||
return;
|
||||
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
if (peap->rx_pdu_buf_len != peap->rx_pdu_buf_offset) {
|
||||
l_error("Request fragment pkt size mismatch");
|
||||
goto error;
|
||||
}
|
||||
|
||||
pkt = peap->rx_pdu_buf;
|
||||
len = peap->rx_pdu_buf_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* tx_pdu_buf is used for the retransmission and needs to be cleared on
|
||||
* a new request
|
||||
@ -218,6 +339,8 @@ static void eap_peap_handle_request(struct eap_state *eap,
|
||||
|
||||
eap_peap_handle_payload(eap, pkt, len);
|
||||
|
||||
eap_peap_free_rx_buffer(eap);
|
||||
|
||||
send_response:
|
||||
if (!peap->tx_pdu_buf)
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user