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
21 changes: 1 addition & 20 deletions include/zephyr/modem/ppp.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,27 +50,10 @@ enum modem_ppp_receive_state {
};

enum modem_ppp_transmit_state {
/* Idle */
MODEM_PPP_TRANSMIT_STATE_IDLE = 0,
/* Writing header */
MODEM_PPP_TRANSMIT_STATE_SOF,
MODEM_PPP_TRANSMIT_STATE_HDR_FF,
MODEM_PPP_TRANSMIT_STATE_HDR_7D,
MODEM_PPP_TRANSMIT_STATE_HDR_23,
/* Writing protocol */
MODEM_PPP_TRANSMIT_STATE_PROTOCOL_HIGH,
MODEM_PPP_TRANSMIT_STATE_ESCAPING_PROTOCOL_HIGH,
MODEM_PPP_TRANSMIT_STATE_PROTOCOL_LOW,
MODEM_PPP_TRANSMIT_STATE_ESCAPING_PROTOCOL_LOW,
/* Writing data */
MODEM_PPP_TRANSMIT_STATE_PROTOCOL,
MODEM_PPP_TRANSMIT_STATE_DATA,
MODEM_PPP_TRANSMIT_STATE_ESCAPING_DATA,
/* Writing FCS */
MODEM_PPP_TRANSMIT_STATE_FCS_LOW,
MODEM_PPP_TRANSMIT_STATE_ESCAPING_FCS_LOW,
MODEM_PPP_TRANSMIT_STATE_FCS_HIGH,
MODEM_PPP_TRANSMIT_STATE_ESCAPING_FCS_HIGH,
/* Writing end of frame */
MODEM_PPP_TRANSMIT_STATE_EOF,
};

Expand Down Expand Up @@ -100,8 +83,6 @@ struct modem_ppp {
/* Packet being sent */
enum modem_ppp_transmit_state transmit_state;
struct net_pkt *tx_pkt;
uint8_t tx_pkt_escaped;
uint16_t tx_pkt_protocol;
uint16_t tx_pkt_fcs;

/* Ring buffer used for transmitting partial PPP frame */
Expand Down
282 changes: 136 additions & 146 deletions subsys/modem/modem_ppp.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,148 +49,134 @@ static uint16_t modem_ppp_ppp_protocol(struct net_pkt *pkt)
return 0;
}

static uint8_t modem_ppp_wrap_net_pkt_byte(struct modem_ppp *ppp)
static bool modem_ppp_needs_escape(uint8_t byte)
{
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:
(void)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;
}
return (byte == MODEM_PPP_CODE_DELIMITER) || (byte == MODEM_PPP_CODE_ESCAPE) ||
(byte < MODEM_PPP_VALUE_ESCAPE);
}

if (net_pkt_remaining_data(ppp->tx_pkt) == 0) {
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_FCS_LOW;
}
static uint32_t modem_ppp_wrap(struct modem_ppp *ppp, uint8_t *buffer, uint32_t available)
{
uint32_t offset = 0;
uint32_t remaining;
uint16_t protocol;
uint8_t upper;
uint8_t lower;
uint8_t byte;

return byte;
while (offset < available) {
remaining = available - offset;

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 {
switch (ppp->transmit_state) {
case MODEM_PPP_TRANSMIT_STATE_SOF:
if (remaining < 4) {
/* Insufficient space for constant header prefix */
goto end;
}
/* Init cursor for later phases */
net_pkt_cursor_init(ppp->tx_pkt);
/* 3 byte common header */
buffer[offset++] = MODEM_PPP_CODE_DELIMITER;
buffer[offset++] = 0xFF;
buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
buffer[offset++] = 0x23;
/* Initialise the FCS.
* This value is always the same at this point, so use the constant value.
* Equivelent to:
* ppp->tx_pkt_fcs = modem_ppp_fcs_init(0xFF);
* ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, 0x03);
*/
ARG_UNUSED(modem_ppp_fcs_init);
ppp->tx_pkt_fcs = 0x3DE3;
/* Next state */
if (net_pkt_is_ppp(ppp->tx_pkt)) {
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_DATA;
} else {
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_PROTOCOL;
}
break;
case MODEM_PPP_TRANSMIT_STATE_PROTOCOL:
/* If both protocol bytes need escaping, it could be 4 bytes */
if (remaining < 4) {
/* Insufficient space for protocol bytes */
goto end;
}
/* Extract protocol bytes */
protocol = modem_ppp_ppp_protocol(ppp->tx_pkt);
upper = (protocol >> 8) & 0xFF;
lower = (protocol >> 0) & 0xFF;
/* FCS is computed without the escape/modification */
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)) {
buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
upper ^= MODEM_PPP_VALUE_ESCAPE;
}
buffer[offset++] = upper;
if (modem_ppp_needs_escape(lower)) {
buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
lower ^= MODEM_PPP_VALUE_ESCAPE;
}
buffer[offset++] = lower;
/* Next state */
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_DATA;
break;
case MODEM_PPP_TRANSMIT_STATE_DATA:
/* Push all data bytes into the buffer */
while (net_pkt_remaining_data(ppp->tx_pkt) > 0) {
/* Space available, taking into account possible escapes */
if (remaining < 2) {
goto end;
}
/* Pull next byte we're sending */
(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)) {
buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
byte ^= MODEM_PPP_VALUE_ESCAPE;
remaining--;
}
buffer[offset++] = byte;
remaining--;
}
/* Data phase finished */
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_EOF;
break;
case MODEM_PPP_TRANSMIT_STATE_EOF:
/* If both FCS bytes need escaping, it could be 5 bytes */
if (remaining < 5) {
/* Insufficient space for protocol bytes */
goto end;
}
/* Push FCS (order is [lower, upper] unlike the protocol) */
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)) {
buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
lower ^= MODEM_PPP_VALUE_ESCAPE;
}
buffer[offset++] = lower;
if (modem_ppp_needs_escape(upper)) {
buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
upper ^= MODEM_PPP_VALUE_ESCAPE;
}
buffer[offset++] = upper;
buffer[offset++] = MODEM_PPP_CODE_DELIMITER;

/* Packet has finished */
ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_IDLE;
goto end;
default:
LOG_DBG("Invalid transmit state (%d)", ppp->transmit_state);
goto end;
}

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;
end:
return offset;
}

static bool modem_ppp_is_byte_expected(uint8_t byte, uint8_t expected_byte)
Expand Down Expand Up @@ -357,32 +343,36 @@ static void modem_ppp_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_eve
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;
uint32_t pushed;
int ret;

if (ppp->tx_pkt == NULL) {
ppp->tx_pkt = k_fifo_get(&ppp->tx_pkt_fifo, K_NO_WAIT);
}

if (ring_buf_is_empty(&ppp->transmit_rb)) {
/* Reset to initial state to maximise contiguous claim */
ring_buf_reset(&ppp->transmit_rb);
}

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);
/* Claim as much space as possible */
reserved_size = ring_buf_put_claim(&ppp->transmit_rb, &reserved, UINT32_MAX);
/* Push wrapped data into claimed buffer */
pushed = modem_ppp_wrap(ppp, reserved, reserved_size);
/* Limit claimed data to what was actually pushed */
ring_buf_put_finish(&ppp->transmit_rb, pushed);

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 (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);
}
}

Expand Down