diff --git a/include/zephyr/net/ppp.h b/include/zephyr/net/ppp.h index 82e026483806d..e992a7512bd69 100644 --- a/include/zephyr/net/ppp.h +++ b/include/zephyr/net/ppp.h @@ -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) diff --git a/subsys/modem/modem_ppp.c b/subsys/modem/modem_ppp.c index 09b62bdaa11eb..eb3f54bf07f93 100644 --- a/subsys/modem/modem_ppp.c +++ b/subsys/modem/modem_ppp.c @@ -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; @@ -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; } @@ -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--; @@ -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; } diff --git a/subsys/net/l2/ppp/lcp.c b/subsys/net/l2/ppp/lcp.c index a62a9e52541ea..6cc8f32716c1f 100644 --- a/subsys/net/l2/ppp/lcp.c +++ b/subsys/net/l2/ppp/lcp.c @@ -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; }; @@ -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, @@ -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; @@ -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)", @@ -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); } diff --git a/subsys/net/l2/ppp/ppp_l2.c b/subsys/net/l2/ppp/ppp_l2.c index ae573a6e7cee8..0a2018ead71f0 100644 --- a/subsys/net/l2/ppp/ppp_l2.c +++ b/subsys/net/l2/ppp/ppp_l2.c @@ -15,6 +15,7 @@ LOG_MODULE_REGISTER(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL); #include #include #include +#include #include #include "net_private.h" @@ -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) diff --git a/tests/subsys/modem/modem_ppp/src/main.c b/tests/subsys/modem/modem_ppp/src/main.c index 0948eb2c4b5ab..84cfc73c0ed2f 100644 --- a/tests/subsys/modem/modem_ppp/src/main.c +++ b/tests/subsys/modem/modem_ppp/src/main.c @@ -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, @@ -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, @@ -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; @@ -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;