597 lines
15 KiB
C
597 lines
15 KiB
C
/*
|
|
* Copyright (c) 2022 Trackunit Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/net/ppp.h>
|
|
#include <zephyr/sys/crc.h>
|
|
#include <zephyr/modem/ppp.h>
|
|
#include <string.h>
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(modem_ppp, CONFIG_MODEM_MODULES_LOG_LEVEL);
|
|
|
|
#define MODEM_PPP_STATE_ATTACHED_BIT (0)
|
|
#define MODEM_PPP_FRAME_TAIL_SIZE (2)
|
|
|
|
#define MODEM_PPP_CODE_DELIMITER (0x7E)
|
|
#define MODEM_PPP_CODE_ESCAPE (0x7D)
|
|
#define MODEM_PPP_VALUE_ESCAPE (0x20)
|
|
|
|
static uint16_t modem_ppp_fcs_init(uint8_t byte)
|
|
{
|
|
return crc16_ccitt(0xFFFF, &byte, 1);
|
|
}
|
|
|
|
static uint16_t modem_ppp_fcs_update(uint16_t fcs, uint8_t byte)
|
|
{
|
|
return crc16_ccitt(fcs, &byte, 1);
|
|
}
|
|
|
|
static uint16_t modem_ppp_fcs_final(uint16_t fcs)
|
|
{
|
|
return fcs ^ 0xFFFF;
|
|
}
|
|
|
|
static uint16_t modem_ppp_ppp_protocol(struct net_pkt *pkt)
|
|
{
|
|
if (net_pkt_family(pkt) == AF_INET) {
|
|
return PPP_IP;
|
|
}
|
|
|
|
if (net_pkt_family(pkt) == AF_INET6) {
|
|
return PPP_IPV6;
|
|
}
|
|
|
|
LOG_WRN("Unsupported protocol");
|
|
return 0;
|
|
}
|
|
|
|
static uint8_t modem_ppp_wrap_net_pkt_byte(struct modem_ppp *ppp)
|
|
{
|
|
uint8_t byte;
|
|
|
|
switch (ppp->transmit_state) {
|
|
case MODEM_PPP_TRANSMIT_STATE_IDLE:
|
|
LOG_WRN("Invalid transmit state");
|
|
return 0;
|
|
|
|
/* Writing header */
|
|
case MODEM_PPP_TRANSMIT_STATE_SOF:
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_HDR_FF;
|
|
return MODEM_PPP_CODE_DELIMITER;
|
|
|
|
case MODEM_PPP_TRANSMIT_STATE_HDR_FF:
|
|
net_pkt_cursor_init(ppp->tx_pkt);
|
|
ppp->tx_pkt_fcs = modem_ppp_fcs_init(0xFF);
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_HDR_7D;
|
|
return 0xFF;
|
|
|
|
case MODEM_PPP_TRANSMIT_STATE_HDR_7D:
|
|
ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, 0x03);
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_HDR_23;
|
|
return MODEM_PPP_CODE_ESCAPE;
|
|
|
|
case MODEM_PPP_TRANSMIT_STATE_HDR_23:
|
|
if (net_pkt_is_ppp(ppp->tx_pkt) == true) {
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_DATA;
|
|
} else {
|
|
ppp->tx_pkt_protocol = modem_ppp_ppp_protocol(ppp->tx_pkt);
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_PROTOCOL_HIGH;
|
|
}
|
|
|
|
return 0x23;
|
|
|
|
/* Writing protocol */
|
|
case MODEM_PPP_TRANSMIT_STATE_PROTOCOL_HIGH:
|
|
byte = (ppp->tx_pkt_protocol >> 8) & 0xFF;
|
|
ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, byte);
|
|
|
|
if ((byte == MODEM_PPP_CODE_DELIMITER) || (byte == MODEM_PPP_CODE_ESCAPE) ||
|
|
(byte < MODEM_PPP_VALUE_ESCAPE)) {
|
|
ppp->tx_pkt_escaped = byte ^ MODEM_PPP_VALUE_ESCAPE;
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_ESCAPING_PROTOCOL_HIGH;
|
|
return MODEM_PPP_CODE_ESCAPE;
|
|
}
|
|
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_PROTOCOL_LOW;
|
|
return byte;
|
|
|
|
case MODEM_PPP_TRANSMIT_STATE_ESCAPING_PROTOCOL_HIGH:
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_PROTOCOL_LOW;
|
|
return ppp->tx_pkt_escaped;
|
|
|
|
case MODEM_PPP_TRANSMIT_STATE_PROTOCOL_LOW:
|
|
byte = ppp->tx_pkt_protocol & 0xFF;
|
|
ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, byte);
|
|
|
|
if ((byte == MODEM_PPP_CODE_DELIMITER) || (byte == MODEM_PPP_CODE_ESCAPE) ||
|
|
(byte < MODEM_PPP_VALUE_ESCAPE)) {
|
|
ppp->tx_pkt_escaped = byte ^ MODEM_PPP_VALUE_ESCAPE;
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_ESCAPING_PROTOCOL_LOW;
|
|
return MODEM_PPP_CODE_ESCAPE;
|
|
}
|
|
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_DATA;
|
|
return byte;
|
|
|
|
case MODEM_PPP_TRANSMIT_STATE_ESCAPING_PROTOCOL_LOW:
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_DATA;
|
|
return ppp->tx_pkt_escaped;
|
|
|
|
/* Writing data */
|
|
case MODEM_PPP_TRANSMIT_STATE_DATA:
|
|
net_pkt_read_u8(ppp->tx_pkt, &byte);
|
|
ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, byte);
|
|
|
|
if ((byte == MODEM_PPP_CODE_DELIMITER) || (byte == MODEM_PPP_CODE_ESCAPE) ||
|
|
(byte < MODEM_PPP_VALUE_ESCAPE)) {
|
|
ppp->tx_pkt_escaped = byte ^ MODEM_PPP_VALUE_ESCAPE;
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_ESCAPING_DATA;
|
|
return MODEM_PPP_CODE_ESCAPE;
|
|
}
|
|
|
|
if (net_pkt_remaining_data(ppp->tx_pkt) == 0) {
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_FCS_LOW;
|
|
}
|
|
|
|
return byte;
|
|
|
|
case MODEM_PPP_TRANSMIT_STATE_ESCAPING_DATA:
|
|
if (net_pkt_remaining_data(ppp->tx_pkt) == 0) {
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_FCS_LOW;
|
|
} else {
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_DATA;
|
|
}
|
|
|
|
return ppp->tx_pkt_escaped;
|
|
|
|
/* Writing FCS */
|
|
case MODEM_PPP_TRANSMIT_STATE_FCS_LOW:
|
|
ppp->tx_pkt_fcs = modem_ppp_fcs_final(ppp->tx_pkt_fcs);
|
|
byte = ppp->tx_pkt_fcs & 0xFF;
|
|
|
|
if ((byte == MODEM_PPP_CODE_DELIMITER) || (byte == MODEM_PPP_CODE_ESCAPE) ||
|
|
(byte < MODEM_PPP_VALUE_ESCAPE)) {
|
|
ppp->tx_pkt_escaped = byte ^ MODEM_PPP_VALUE_ESCAPE;
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_ESCAPING_FCS_LOW;
|
|
return MODEM_PPP_CODE_ESCAPE;
|
|
}
|
|
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_FCS_HIGH;
|
|
return byte;
|
|
|
|
case MODEM_PPP_TRANSMIT_STATE_ESCAPING_FCS_LOW:
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_FCS_HIGH;
|
|
return ppp->tx_pkt_escaped;
|
|
|
|
case MODEM_PPP_TRANSMIT_STATE_FCS_HIGH:
|
|
byte = (ppp->tx_pkt_fcs >> 8) & 0xFF;
|
|
|
|
if ((byte == MODEM_PPP_CODE_DELIMITER) || (byte == MODEM_PPP_CODE_ESCAPE) ||
|
|
(byte < MODEM_PPP_VALUE_ESCAPE)) {
|
|
ppp->tx_pkt_escaped = byte ^ MODEM_PPP_VALUE_ESCAPE;
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_ESCAPING_FCS_HIGH;
|
|
return MODEM_PPP_CODE_ESCAPE;
|
|
}
|
|
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_EOF;
|
|
return byte;
|
|
|
|
case MODEM_PPP_TRANSMIT_STATE_ESCAPING_FCS_HIGH:
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_EOF;
|
|
return ppp->tx_pkt_escaped;
|
|
|
|
/* Writing end of frame */
|
|
case MODEM_PPP_TRANSMIT_STATE_EOF:
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_IDLE;
|
|
return MODEM_PPP_CODE_DELIMITER;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool modem_ppp_is_byte_expected(uint8_t byte, uint8_t expected_byte)
|
|
{
|
|
if (byte == expected_byte) {
|
|
return true;
|
|
}
|
|
LOG_DBG("Dropping byte 0x%02hhx because 0x%02hhx was expected.", byte, expected_byte);
|
|
return false;
|
|
}
|
|
|
|
static void modem_ppp_process_received_byte(struct modem_ppp *ppp, uint8_t byte)
|
|
{
|
|
switch (ppp->receive_state) {
|
|
case MODEM_PPP_RECEIVE_STATE_HDR_SOF:
|
|
if (modem_ppp_is_byte_expected(byte, MODEM_PPP_CODE_DELIMITER)) {
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_FF;
|
|
}
|
|
break;
|
|
|
|
case MODEM_PPP_RECEIVE_STATE_HDR_FF:
|
|
if (byte == MODEM_PPP_CODE_DELIMITER) {
|
|
break;
|
|
}
|
|
if (modem_ppp_is_byte_expected(byte, 0xFF)) {
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_7D;
|
|
} else {
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
|
|
}
|
|
break;
|
|
|
|
case MODEM_PPP_RECEIVE_STATE_HDR_7D:
|
|
if (modem_ppp_is_byte_expected(byte, MODEM_PPP_CODE_ESCAPE)) {
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_23;
|
|
} else {
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
|
|
}
|
|
break;
|
|
|
|
case MODEM_PPP_RECEIVE_STATE_HDR_23:
|
|
if (modem_ppp_is_byte_expected(byte, 0x23)) {
|
|
ppp->rx_pkt = net_pkt_rx_alloc_with_buffer(ppp->iface,
|
|
CONFIG_MODEM_PPP_NET_BUF_FRAG_SIZE, AF_UNSPEC, 0, K_NO_WAIT);
|
|
|
|
if (ppp->rx_pkt == NULL) {
|
|
LOG_WRN("Dropped frame, no net_pkt available");
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
|
|
break;
|
|
}
|
|
|
|
LOG_DBG("Receiving PPP frame");
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_WRITING;
|
|
net_pkt_cursor_init(ppp->rx_pkt);
|
|
} else {
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
|
|
}
|
|
|
|
break;
|
|
|
|
case MODEM_PPP_RECEIVE_STATE_WRITING:
|
|
if (byte == MODEM_PPP_CODE_DELIMITER) {
|
|
LOG_DBG("Received PPP frame (len %zu)", net_pkt_get_len(ppp->rx_pkt));
|
|
|
|
/* Remove FCS */
|
|
net_pkt_remove_tail(ppp->rx_pkt, MODEM_PPP_FRAME_TAIL_SIZE);
|
|
net_pkt_set_ppp(ppp->rx_pkt, true);
|
|
|
|
if (net_recv_data(ppp->iface, ppp->rx_pkt) < 0) {
|
|
LOG_WRN("Net pkt could not be processed");
|
|
net_pkt_unref(ppp->rx_pkt);
|
|
}
|
|
|
|
ppp->rx_pkt = NULL;
|
|
/* Skip SOF because the delimiter may be omitted for successive frames. */
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_FF;
|
|
break;
|
|
}
|
|
|
|
if (net_pkt_available_buffer(ppp->rx_pkt) == 1) {
|
|
if (net_pkt_alloc_buffer(ppp->rx_pkt, CONFIG_MODEM_PPP_NET_BUF_FRAG_SIZE,
|
|
AF_INET, K_NO_WAIT) < 0) {
|
|
LOG_WRN("Failed to alloc buffer");
|
|
net_pkt_unref(ppp->rx_pkt);
|
|
ppp->rx_pkt = NULL;
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (byte == MODEM_PPP_CODE_ESCAPE) {
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_UNESCAPING;
|
|
break;
|
|
}
|
|
|
|
if (net_pkt_write_u8(ppp->rx_pkt, byte) < 0) {
|
|
LOG_WRN("Dropped PPP frame");
|
|
net_pkt_unref(ppp->rx_pkt);
|
|
ppp->rx_pkt = NULL;
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
|
|
#if defined(CONFIG_NET_STATISTICS_PPP)
|
|
ppp->stats.drop++;
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
|
|
case MODEM_PPP_RECEIVE_STATE_UNESCAPING:
|
|
if (net_pkt_write_u8(ppp->rx_pkt, (byte ^ MODEM_PPP_VALUE_ESCAPE)) < 0) {
|
|
LOG_WRN("Dropped PPP frame");
|
|
net_pkt_unref(ppp->rx_pkt);
|
|
ppp->rx_pkt = NULL;
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
|
|
#if defined(CONFIG_NET_STATISTICS_PPP)
|
|
ppp->stats.drop++;
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_WRITING;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if CONFIG_MODEM_STATS
|
|
static uint32_t get_transmit_buf_length(struct modem_ppp *ppp)
|
|
{
|
|
return ring_buf_size_get(&ppp->transmit_rb);
|
|
}
|
|
|
|
static void advertise_transmit_buf_stats(struct modem_ppp *ppp)
|
|
{
|
|
uint32_t length;
|
|
|
|
length = get_transmit_buf_length(ppp);
|
|
modem_stats_buffer_advertise_length(&ppp->transmit_buf_stats, length);
|
|
}
|
|
|
|
static void advertise_receive_buf_stats(struct modem_ppp *ppp, uint32_t length)
|
|
{
|
|
modem_stats_buffer_advertise_length(&ppp->receive_buf_stats, length);
|
|
}
|
|
#endif
|
|
|
|
static void modem_ppp_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_event event,
|
|
void *user_data)
|
|
{
|
|
struct modem_ppp *ppp = (struct modem_ppp *)user_data;
|
|
|
|
switch (event) {
|
|
case MODEM_PIPE_EVENT_RECEIVE_READY:
|
|
k_work_submit(&ppp->process_work);
|
|
break;
|
|
|
|
case MODEM_PIPE_EVENT_OPENED:
|
|
case MODEM_PIPE_EVENT_TRANSMIT_IDLE:
|
|
k_work_submit(&ppp->send_work);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void modem_ppp_send_handler(struct k_work *item)
|
|
{
|
|
struct modem_ppp *ppp = CONTAINER_OF(item, struct modem_ppp, send_work);
|
|
uint8_t byte;
|
|
uint8_t *reserved;
|
|
uint32_t reserved_size;
|
|
int ret;
|
|
|
|
if (ppp->tx_pkt == NULL) {
|
|
ppp->tx_pkt = k_fifo_get(&ppp->tx_pkt_fifo, K_NO_WAIT);
|
|
}
|
|
|
|
if (ppp->tx_pkt != NULL) {
|
|
/* Initialize wrap */
|
|
if (ppp->transmit_state == MODEM_PPP_TRANSMIT_STATE_IDLE) {
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_SOF;
|
|
}
|
|
|
|
/* Fill transmit ring buffer */
|
|
while (ring_buf_space_get(&ppp->transmit_rb) > 0) {
|
|
byte = modem_ppp_wrap_net_pkt_byte(ppp);
|
|
|
|
ring_buf_put(&ppp->transmit_rb, &byte, 1);
|
|
|
|
if (ppp->transmit_state == MODEM_PPP_TRANSMIT_STATE_IDLE) {
|
|
net_pkt_unref(ppp->tx_pkt);
|
|
ppp->tx_pkt = k_fifo_get(&ppp->tx_pkt_fifo, K_NO_WAIT);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if CONFIG_MODEM_STATS
|
|
advertise_transmit_buf_stats(ppp);
|
|
#endif
|
|
|
|
while (!ring_buf_is_empty(&ppp->transmit_rb)) {
|
|
reserved_size = ring_buf_get_claim(&ppp->transmit_rb, &reserved, UINT32_MAX);
|
|
|
|
ret = modem_pipe_transmit(ppp->pipe, reserved, reserved_size);
|
|
if (ret < 0) {
|
|
ring_buf_get_finish(&ppp->transmit_rb, 0);
|
|
break;
|
|
}
|
|
|
|
ring_buf_get_finish(&ppp->transmit_rb, (uint32_t)ret);
|
|
|
|
if (ret < reserved_size) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void modem_ppp_process_handler(struct k_work *item)
|
|
{
|
|
struct modem_ppp *ppp = CONTAINER_OF(item, struct modem_ppp, process_work);
|
|
int ret;
|
|
|
|
ret = modem_pipe_receive(ppp->pipe, ppp->receive_buf, ppp->buf_size);
|
|
if (ret < 1) {
|
|
return;
|
|
}
|
|
|
|
#if CONFIG_MODEM_STATS
|
|
advertise_receive_buf_stats(ppp, ret);
|
|
#endif
|
|
|
|
for (int i = 0; i < ret; i++) {
|
|
modem_ppp_process_received_byte(ppp, ppp->receive_buf[i]);
|
|
}
|
|
|
|
k_work_submit(&ppp->process_work);
|
|
}
|
|
|
|
static void modem_ppp_ppp_api_init(struct net_if *iface)
|
|
{
|
|
const struct device *dev = net_if_get_device(iface);
|
|
struct modem_ppp *ppp = (struct modem_ppp *)dev->data;
|
|
|
|
net_ppp_init(iface);
|
|
net_if_flag_set(iface, NET_IF_NO_AUTO_START);
|
|
net_if_carrier_off(iface);
|
|
|
|
if (ppp->init_iface != NULL) {
|
|
ppp->init_iface(iface);
|
|
}
|
|
|
|
ppp->iface = iface;
|
|
}
|
|
|
|
static int modem_ppp_ppp_api_start(const struct device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int modem_ppp_ppp_api_stop(const struct device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int modem_ppp_ppp_api_send(const struct device *dev, struct net_pkt *pkt)
|
|
{
|
|
struct modem_ppp *ppp = (struct modem_ppp *)dev->data;
|
|
|
|
if (atomic_test_bit(&ppp->state, MODEM_PPP_STATE_ATTACHED_BIT) == false) {
|
|
return -EPERM;
|
|
}
|
|
|
|
/* Validate packet protocol */
|
|
if ((net_pkt_is_ppp(pkt) == false) && (net_pkt_family(pkt) != AF_INET) &&
|
|
(net_pkt_family(pkt) != AF_INET6)) {
|
|
return -EPROTONOSUPPORT;
|
|
}
|
|
|
|
/* Validate packet data length */
|
|
if (((net_pkt_get_len(pkt) < 2) && (net_pkt_is_ppp(pkt) == true)) ||
|
|
((net_pkt_get_len(pkt) < 1))) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
net_pkt_ref(pkt);
|
|
k_fifo_put(&ppp->tx_pkt_fifo, pkt);
|
|
k_work_submit(&ppp->send_work);
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_PPP)
|
|
static struct net_stats_ppp *modem_ppp_ppp_get_stats(const struct device *dev)
|
|
{
|
|
struct modem_ppp *ppp = (struct modem_ppp *)dev->data;
|
|
|
|
return &ppp->stats;
|
|
}
|
|
#endif
|
|
|
|
#if CONFIG_MODEM_STATS
|
|
static uint32_t get_buf_size(struct modem_ppp *ppp)
|
|
{
|
|
return ppp->buf_size;
|
|
}
|
|
|
|
static void init_buf_stats(struct modem_ppp *ppp)
|
|
{
|
|
char iface_name[CONFIG_MODEM_STATS_BUFFER_NAME_SIZE - sizeof("_xx")];
|
|
char name[CONFIG_MODEM_STATS_BUFFER_NAME_SIZE];
|
|
int ret;
|
|
uint32_t size;
|
|
|
|
ret = net_if_get_name(ppp->iface, iface_name, sizeof(iface_name));
|
|
if (ret < 0) {
|
|
snprintk(iface_name, sizeof(iface_name), "ppp");
|
|
}
|
|
|
|
size = get_buf_size(ppp);
|
|
snprintk(name, sizeof(name), "%s_rx", iface_name);
|
|
modem_stats_buffer_init(&ppp->receive_buf_stats, name, size);
|
|
snprintk(name, sizeof(name), "%s_tx", iface_name);
|
|
modem_stats_buffer_init(&ppp->transmit_buf_stats, name, size);
|
|
}
|
|
#endif
|
|
|
|
const struct ppp_api modem_ppp_ppp_api = {
|
|
.iface_api.init = modem_ppp_ppp_api_init,
|
|
.start = modem_ppp_ppp_api_start,
|
|
.stop = modem_ppp_ppp_api_stop,
|
|
.send = modem_ppp_ppp_api_send,
|
|
#if defined(CONFIG_NET_STATISTICS_PPP)
|
|
.get_stats = modem_ppp_ppp_get_stats,
|
|
#endif
|
|
};
|
|
|
|
int modem_ppp_attach(struct modem_ppp *ppp, struct modem_pipe *pipe)
|
|
{
|
|
if (atomic_test_bit(&ppp->state, MODEM_PPP_STATE_ATTACHED_BIT) == true) {
|
|
return 0;
|
|
}
|
|
|
|
ppp->pipe = pipe;
|
|
modem_pipe_attach(pipe, modem_ppp_pipe_callback, ppp);
|
|
|
|
atomic_set_bit(&ppp->state, MODEM_PPP_STATE_ATTACHED_BIT);
|
|
return 0;
|
|
}
|
|
|
|
struct net_if *modem_ppp_get_iface(struct modem_ppp *ppp)
|
|
{
|
|
return ppp->iface;
|
|
}
|
|
|
|
void modem_ppp_release(struct modem_ppp *ppp)
|
|
{
|
|
struct k_work_sync sync;
|
|
struct net_pkt *pkt;
|
|
|
|
if (atomic_test_and_clear_bit(&ppp->state, MODEM_PPP_STATE_ATTACHED_BIT) == false) {
|
|
return;
|
|
}
|
|
|
|
modem_pipe_release(ppp->pipe);
|
|
k_work_cancel_sync(&ppp->send_work, &sync);
|
|
k_work_cancel_sync(&ppp->process_work, &sync);
|
|
ppp->pipe = NULL;
|
|
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
|
|
|
|
if (ppp->rx_pkt != NULL) {
|
|
net_pkt_unref(ppp->rx_pkt);
|
|
ppp->rx_pkt = NULL;
|
|
}
|
|
|
|
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_IDLE;
|
|
|
|
if (ppp->tx_pkt != NULL) {
|
|
net_pkt_unref(ppp->tx_pkt);
|
|
ppp->tx_pkt = NULL;
|
|
}
|
|
|
|
while (1) {
|
|
pkt = k_fifo_get(&ppp->tx_pkt_fifo, K_NO_WAIT);
|
|
if (pkt == NULL) {
|
|
break;
|
|
}
|
|
|
|
net_pkt_unref(pkt);
|
|
}
|
|
}
|
|
|
|
int modem_ppp_init_internal(const struct device *dev)
|
|
{
|
|
struct modem_ppp *ppp = (struct modem_ppp *)dev->data;
|
|
|
|
atomic_set(&ppp->state, 0);
|
|
ring_buf_init(&ppp->transmit_rb, ppp->buf_size, ppp->transmit_buf);
|
|
k_work_init(&ppp->send_work, modem_ppp_send_handler);
|
|
k_work_init(&ppp->process_work, modem_ppp_process_handler);
|
|
k_fifo_init(&ppp->tx_pkt_fifo);
|
|
|
|
#if CONFIG_MODEM_STATS
|
|
init_buf_stats(ppp);
|
|
#endif
|
|
return 0;
|
|
}
|