Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions include/zephyr/net/ppp.h
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,15 @@ struct net_if;

/** @endcond */

/**
* @brief Retrieve the PPP peers Asynchronous Control Character Map
*
* @param iface PPP network interface.
*
* @return uint32_t Current bitmask for the Asynchronous Control Character Map
*/
uint32_t ppp_peer_async_control_character_map(struct net_if *iface);

/** Event emitted when PPP carrier is on */
#define NET_EVENT_PPP_CARRIER_ON \
(NET_PPP_EVENT | NET_EVENT_PPP_CMD_CARRIER_ON)
Expand Down
29 changes: 20 additions & 9 deletions subsys/modem/modem_ppp.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,25 @@ static uint16_t modem_ppp_ppp_protocol(struct net_pkt *pkt)
return 0;
}

static bool modem_ppp_needs_escape(uint8_t byte)
static bool modem_ppp_needs_escape(uint32_t async_map, uint8_t byte)
{
return (byte == MODEM_PPP_CODE_DELIMITER) || (byte == MODEM_PPP_CODE_ESCAPE) ||
(byte < MODEM_PPP_VALUE_ESCAPE);
uint32_t byte_bit;

if ((byte == MODEM_PPP_CODE_DELIMITER) || (byte == MODEM_PPP_CODE_ESCAPE)) {
/* Always escaped */
return true;
} else if (byte >= MODEM_PPP_VALUE_ESCAPE) {
/* Never escaped */
return false;
}
byte_bit = BIT(byte);
/* Escaped if required by the async control character map */
return byte_bit & async_map;
}

static uint32_t modem_ppp_wrap(struct modem_ppp *ppp, uint8_t *buffer, uint32_t available)
{
uint32_t async_map = ppp_peer_async_control_character_map(ppp->iface);
uint32_t offset = 0;
uint32_t remaining;
uint16_t protocol;
Expand Down Expand Up @@ -111,12 +122,12 @@ static uint32_t modem_ppp_wrap(struct modem_ppp *ppp, uint8_t *buffer, uint32_t
ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, upper);
ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, lower);
/* Push protocol bytes (with required escaping) */
if (modem_ppp_needs_escape(upper)) {
if (modem_ppp_needs_escape(async_map, upper)) {
buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
upper ^= MODEM_PPP_VALUE_ESCAPE;
}
buffer[offset++] = upper;
if (modem_ppp_needs_escape(lower)) {
if (modem_ppp_needs_escape(async_map, lower)) {
buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
lower ^= MODEM_PPP_VALUE_ESCAPE;
}
Expand All @@ -135,8 +146,8 @@ static uint32_t modem_ppp_wrap(struct modem_ppp *ppp, uint8_t *buffer, uint32_t
(void)net_pkt_read_u8(ppp->tx_pkt, &byte);
/* FCS is computed without the escape/modification */
ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, byte);
/* Push encoded bytes into buffer */
if (modem_ppp_needs_escape(byte)) {
/* Push encoded bytes into buffer*/
if (modem_ppp_needs_escape(async_map, byte)) {
buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
byte ^= MODEM_PPP_VALUE_ESCAPE;
remaining--;
Expand All @@ -157,12 +168,12 @@ static uint32_t modem_ppp_wrap(struct modem_ppp *ppp, uint8_t *buffer, uint32_t
ppp->tx_pkt_fcs = modem_ppp_fcs_final(ppp->tx_pkt_fcs);
lower = (ppp->tx_pkt_fcs >> 0) & 0xFF;
upper = (ppp->tx_pkt_fcs >> 8) & 0xFF;
if (modem_ppp_needs_escape(lower)) {
if (modem_ppp_needs_escape(async_map, lower)) {
buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
lower ^= MODEM_PPP_VALUE_ESCAPE;
}
buffer[offset++] = lower;
if (modem_ppp_needs_escape(upper)) {
if (modem_ppp_needs_escape(async_map, upper)) {
buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
upper ^= MODEM_PPP_VALUE_ESCAPE;
}
Expand Down
26 changes: 26 additions & 0 deletions subsys/net/l2/ppp/lcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ static enum net_verdict lcp_handle(struct ppp_context *ctx,

struct lcp_option_data {
bool auth_proto_present;
uint32_t async_ctrl_char_map;
uint16_t auth_proto;
};

Expand Down Expand Up @@ -103,9 +104,28 @@ static int lcp_auth_proto_nack(struct ppp_fsm *fsm, struct net_pkt *ret_pkt,
return net_pkt_write_be16(ret_pkt, PPP_PAP);
}

static int lcp_async_ctrl_char_map_parse(struct ppp_fsm *fsm, struct net_pkt *pkt,
void *user_data)
{
struct lcp_option_data *data = user_data;
int ret;

ret = net_pkt_read_be32(pkt, &data->async_ctrl_char_map);
if (ret < 0) {
/* Should not happen, is the pkt corrupt? */
return -EMSGSIZE;
}

NET_DBG("[LCP] Received Asynchronous Control Character Map %08x",
data->async_ctrl_char_map);
return 0;
}

static const struct ppp_peer_option_info lcp_peer_options[] = {
PPP_PEER_OPTION(LCP_OPTION_AUTH_PROTO, lcp_auth_proto_parse,
lcp_auth_proto_nack),
PPP_PEER_OPTION(LCP_OPTION_ASYNC_CTRL_CHAR_MAP, lcp_async_ctrl_char_map_parse,
NULL),
};

static int lcp_config_info_req(struct ppp_fsm *fsm,
Expand All @@ -117,6 +137,7 @@ static int lcp_config_info_req(struct ppp_fsm *fsm,
lcp.fsm);
struct lcp_option_data data = {
.auth_proto_present = false,
.async_ctrl_char_map = 0xffffffff,
};
int ret;

Expand All @@ -130,6 +151,8 @@ static int lcp_config_info_req(struct ppp_fsm *fsm,
}

ctx->lcp.peer_options.auth_proto = data.auth_proto;
ctx->lcp.peer_options.async_map = data.async_ctrl_char_map;
NET_DBG("Asynchronous Control Character Map: %08X", data.async_ctrl_char_map);

if (data.auth_proto_present) {
NET_DBG("Authentication protocol negotiated: %x (%s)",
Expand Down Expand Up @@ -157,6 +180,9 @@ static void lcp_lower_up(struct ppp_context *ctx)

static void lcp_open(struct ppp_context *ctx)
{
/* Reset peer async control character map */
ctx->lcp.peer_options.async_map = 0xffffffff;

ppp_fsm_open(&ctx->lcp.fsm);
}

Expand Down
12 changes: 12 additions & 0 deletions subsys/net/l2/ppp/ppp_l2.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ LOG_MODULE_REGISTER(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL);
#include <zephyr/net/net_pkt.h>
#include <zephyr/net/net_mgmt.h>
#include <zephyr/net/ppp.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/sys/iterable_sections.h>

#include "net_private.h"
Expand Down Expand Up @@ -345,6 +346,17 @@ static int ppp_enable(struct net_if *iface, bool state)
return ret;
}

uint32_t ppp_peer_async_control_character_map(struct net_if *iface)
{
struct ppp_context *ctx;

#ifndef CONFIG_ZTEST
__ASSERT(net_if_l2(iface) == &NET_L2_GET_NAME(PPP), "Not PPP L2");
#endif /* !CONFIG_ZTEST */
ctx = net_if_l2_data(iface);
return ctx->lcp.peer_options.async_map;
}

NET_L2_INIT(PPP_L2, ppp_recv, ppp_send, ppp_enable, ppp_flags);

#if defined(CONFIG_NET_SHELL)
Expand Down
81 changes: 81 additions & 0 deletions tests/subsys/modem/modem_ppp/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ static uint8_t ppp_frame_wrapped[] = {0x7E, 0xFF, 0x7D, 0x23, 0xC0, 0x21, 0x7D,

static uint8_t ppp_frame_unwrapped[] = {0xC0, 0x21, 0x01, 0x01, 0x00, 0x04};

/* Custom ACCM (Only 0-15 need to be escaped) */
static uint32_t accm_custom1 = 0x0000ffff;
static uint8_t ppp_frame_wrapped_accm1[] = {0x7E, 0xFF, 0x7D, 0x23, 0xC0, 0x21, 0x16, 0x7D,
0x21, 0x7D, 0x20, 0x7D, 0x24, 0x51, 0x21, 0x7E};

/* Custom ACCM (Only 16-31 need to be escaped) */
static uint32_t accm_custom2 = 0xffff0000;
static uint8_t ppp_frame_wrapped_accm2[] = {0x7E, 0xFF, 0x7D, 0x23, 0xC0, 0x21, 0x7D, 0x36,
0x01, 0x00, 0x04, 0x51, 0x21, 0x7E};

static uint8_t ppp_frame_unwrapped_accm[] = {0xC0, 0x21, 0x16, 0x01, 0x00, 0x04};

static uint8_t ip_frame_wrapped[] = {
0x7E, 0xFF, 0x7D, 0x23, 0x7D, 0x20, 0x21, 0x45, 0x7D, 0x20, 0x7D, 0x20, 0x29, 0x87, 0x6E,
0x40, 0x7D, 0x20, 0xE8, 0x7D, 0x31, 0xC1, 0xE9, 0x7D, 0x23, 0xFB, 0x7D, 0x25, 0x20, 0x7D,
Expand Down Expand Up @@ -94,10 +106,14 @@ static enum net_verdict test_net_l2_recv(struct net_if *iface, struct net_pkt *p
static struct net_l2 test_net_l2 = {
.recv = test_net_l2_recv,
};
static struct ppp_context test_net_l2_data = {
.lcp.peer_options.async_map = 0xffffffff,
};

/* This emulates the network interface device which will receive unwrapped network packets */
static struct net_if_dev test_net_if_dev = {
.l2 = &test_net_l2,
.l2_data = &test_net_l2_data,
.link_addr.addr = {0x00, 0x00, 0x5E, 0x00, 0x53, 0x01},
.link_addr.len = NET_ETH_ADDR_LEN,
.link_addr.type = NET_LINK_DUMMY,
Expand Down Expand Up @@ -287,6 +303,9 @@ static void test_modem_ppp_before(void *f)
net_pkt_unref(received_packets[i]);
}

/* Reset ACCM */
test_net_l2_data.lcp.peer_options.async_map = 0xffffffff;

/* Reset packets received buffer */
received_packets_len = 0;

Expand Down Expand Up @@ -381,6 +400,68 @@ ZTEST(modem_ppp, test_ppp_frame_send)
"Wrapped frame content is incorrect");
}

ZTEST(modem_ppp, test_ppp_frame_send_custom_accm1)
{
struct net_pkt *pkt;
int ret;

/* Allocate net pkt */
pkt = net_pkt_alloc_with_buffer(&test_iface, 256, AF_UNSPEC, 0, K_NO_WAIT);

zassert_true(pkt != NULL, "Failed to allocate network packet");

/* Set network packet data */
net_pkt_cursor_init(pkt);
ret = net_pkt_write(pkt, ppp_frame_unwrapped_accm, sizeof(ppp_frame_unwrapped_accm));
zassert_true(ret == 0, "Failed to write data to allocated network packet");
net_pkt_set_ppp(pkt, true);

test_net_l2_data.lcp.peer_options.async_map = accm_custom1;

/* Send network packet */
zassert_true(test_net_send(pkt) == 0, "Failed to send PPP pkt");

/* Give modem ppp time to wrap and send frame */
k_msleep(1000);

/* Get any sent data */
ret = modem_backend_mock_get(&mock, buffer, sizeof(buffer));
zassert_true(ret == sizeof(ppp_frame_wrapped_accm1), "Wrapped frame length incorrect");
zassert_true(memcmp(buffer, ppp_frame_wrapped_accm1, ret) == 0,
"Wrapped frame content is incorrect");
}

ZTEST(modem_ppp, test_ppp_frame_send_custom_accm2)
{
struct net_pkt *pkt;
int ret;

/* Allocate net pkt */
pkt = net_pkt_alloc_with_buffer(&test_iface, 256, AF_UNSPEC, 0, K_NO_WAIT);

zassert_true(pkt != NULL, "Failed to allocate network packet");

/* Set network packet data */
net_pkt_cursor_init(pkt);
ret = net_pkt_write(pkt, ppp_frame_unwrapped_accm, sizeof(ppp_frame_unwrapped_accm));
zassert_true(ret == 0, "Failed to write data to allocated network packet");
net_pkt_set_ppp(pkt, true);

test_net_l2_data.lcp.peer_options.async_map = accm_custom2;

/* Send network packet */
zassert_true(test_net_send(pkt) == 0, "Failed to send PPP pkt");

/* Give modem ppp time to wrap and send frame */
k_msleep(1000);

/* Get any sent data */
ret = modem_backend_mock_get(&mock, buffer, sizeof(buffer));
zassert_true(ret == sizeof(ppp_frame_wrapped_accm2), "Wrapped frame length incorrect");
zassert_true(memcmp(buffer, ppp_frame_wrapped_accm2, ret) == 0,
"Wrapped frame content is incorrect");
}

ZTEST(modem_ppp, test_ip_frame_receive)
{
struct net_pkt *pkt;
Expand Down