ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_net_provision.c File Reference

Bounded runtime network provisioning parser and UART receiver. More...

#include "ra8_net_provision.h"
#include <stddef.h>
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_err.h"
#include "ra8_secure.h"
Include dependency graph for ra8_net_provision.c:

Go to the source code of this file.

Enumerations

enum  ra8_net_provision_text_byte_t : uint8_t {
  k_ra8_net_provision_text_printable_min = 0x20U ,
  k_ra8_net_provision_text_delete = 0x7FU
}
 Control-byte boundaries rejected from decoded text fields. More...
enum  ra8_net_provision_hex_t : uint8_t { k_ra8_net_provision_hex_alpha_offset = 10U }
 Numeric base of hexadecimal alphabet digits. More...

Functions

static bool internal_hex_nibble (uint8_t digit, uint8_t *out)
 Decode one hexadecimal digit.
static ra8_err_t internal_decode_field (const uint8_t *line, size_t begin, size_t end, char *output, size_t capacity, size_t *out_length)
 Decode one bounded hexadecimal field.
static bool internal_has_no_controls (const char *text, size_t length)
 Check a decoded text field for C0 and DEL control bytes.
static bool internal_psk_is_hex (const char *psk)
 Check whether a decoded 64-byte PSK contains only ASCII hex.
static ra8_err_t internal_validate_candidate (const ra8_net_credentials_t *candidate)
 Validate decoded field lengths and string compatibility.
static ra8_err_t internal_decode_line (const uint8_t *line, size_t line_length, ra8_net_credentials_t *candidate)
 Decode the three fields between already-validated framing bytes.
static bool internal_prefix_matches (const uint8_t *line)
 Check the fixed version prefix without a libc comparison.
void ra8_net_provision_clear (ra8_net_credentials_t *credentials)
 Explicitly erase one decoded credential record.
ra8_err_t ra8_net_provision_parse (const uint8_t *line, size_t line_length, ra8_net_credentials_t *out)
 Parse one complete version-one ASCII-hex provisioning line.
static ra8_err_t internal_validate_receiver (const ra8_net_provision_uart_t *uart, uint32_t timeout_ms)
 Validate the injected receiver dependencies and timeout.
static bool internal_find_newline (const uint8_t *chunk, size_t length, size_t *newline_offset)
 Locate a newline in one newly received chunk.
static ra8_err_t internal_receive_line (const ra8_net_provision_uart_t *uart, uint32_t timeout_ms, uint8_t *line, size_t line_capacity, size_t *line_length)
 Receive exactly one newline-terminated provisioning record.
ra8_err_t ra8_net_provision_receive (const ra8_net_provision_uart_t *uart, uint32_t timeout_ms, ra8_net_credentials_t *out)
 Prompt once and receive one provisioning line within a fixed timeout.

Variables

static const uint8_t s_prefix [k_ra8_net_provision_prefix_bytes]
 Exact protocol prefix, including the first field separator.
const char k_ra8_net_provision_ready_prompt [] = "ra8_net_provision: READY v1\r\n"
 Exact non-secret line emitted before the receiver drains UART input.

Detailed Description

Bounded runtime network provisioning parser and UART receiver.

Tag
[Ring 6 / APP] {World: S}

Decodes one versioned ASCII-hex record into caller-owned fixed storage and collects that record through injected non-blocking UART operations. Raw and decoded transient storage is explicitly erased on all return paths.

Since
0.1.0

Definition in file ra8_net_provision.c.

Enumeration Type Documentation

◆ ra8_net_provision_hex_t

enum ra8_net_provision_hex_t : uint8_t

Numeric base of hexadecimal alphabet digits.

Converts an alphabet index beginning at A or a into the corresponding nibble value beginning at decimal ten.

Invariant
The value fits in one decoded nibble.
Both accepted ASCII letter cases use the same offset.
Example:
nibble = letter_index + k_ra8_net_provision_hex_alpha_offset;
@ k_ra8_net_provision_hex_alpha_offset
Value represented by A or a.
See also
internal_hex_nibble
Since
0.1.0
Enumerator
k_ra8_net_provision_hex_alpha_offset 

Value represented by A or a.

Definition at line 73 of file ra8_net_provision.c.

◆ ra8_net_provision_text_byte_t

Control-byte boundaries rejected from decoded text fields.

Mirrors the host provisioner's text policy so a direct UART sender cannot inject C0 or DEL control bytes into C-string consumers.

Invariant
Printable ASCII begins at k_ra8_net_provision_text_printable_min.
k_ra8_net_provision_text_delete is the only C0-adjacent control byte above the printable ASCII range.
Example:
if (byte < k_ra8_net_provision_text_printable_min) { reject(); }
@ k_ra8_net_provision_text_printable_min
First printable ASCII byte.
See also
internal_has_no_controls
Since
0.1.0
Enumerator
k_ra8_net_provision_text_printable_min 

First printable ASCII byte.

k_ra8_net_provision_text_delete 

ASCII DEL control byte.

Definition at line 54 of file ra8_net_provision.c.

Function Documentation

◆ internal_decode_field()

ra8_err_t internal_decode_field ( const uint8_t * line,
size_t begin,
size_t end,
char * output,
size_t capacity,
size_t * out_length )
static

Decode one bounded hexadecimal field.

Processes exactly two input characters per output byte and appends one NUL terminator after the decoded extent.

Parameters
[in]lineComplete provisioning line.
[in]beginFirst hex byte of the field.
[in]endOne-past-last hex byte of the field.
[out]outputDestination text buffer.
[in]capacityPayload capacity, excluding the trailing NUL.
[out]out_lengthDecoded payload length.
Returns
Repository error code.
Return values
k_ra8_okThe field decoded completely.
k_ra8_err_invalid_sizeThe encoded extent was odd or too large.
k_ra8_err_protocol_errorA character was not hexadecimal.
Precondition
Input and output extents are valid and non-overlapping.
output has capacity + 1 writable bytes.
Postcondition
Success writes *out_length bytes and a trailing NUL.
Failure leaves only a caller-owned transient that will be erased.
Note
The loop is bounded by capacity (NASA Rule 2).
Since
0.1.0

Definition at line 133 of file ra8_net_provision.c.

References internal_hex_nibble(), k_ra8_err_invalid_size, k_ra8_err_protocol_error, k_ra8_ok, and RA8_INTERNAL.

Referenced by internal_decode_line().

◆ internal_decode_line()

ra8_err_t internal_decode_line ( const uint8_t * line,
size_t line_length,
ra8_net_credentials_t * candidate )
static

Decode the three fields between already-validated framing bytes.

Finds exactly two field separators, decodes each bounded hex extent into the candidate record, and validates the completed candidate.

Parameters
[in]lineComplete input line.
[in]line_lengthComplete input length.
[out]candidateCleared candidate record to populate.
Returns
Repository error code from separator, decode, or field validation.
Return values
k_ra8_okAll three fields decoded and validated.
k_ra8_err_invalid_sizeA field exceeded its capacity.
k_ra8_err_protocol_errorSeparator or hex syntax was invalid.
Precondition
Prefix and trailing newline were validated by the caller.
candidate was zero-initialized.
Postcondition
Success fully initializes the candidate.
Failure may partially initialize the candidate for caller erasure.
Note
Each scan is bounded by the fixed line maximum.
Since
0.1.0

Definition at line 278 of file ra8_net_provision.c.

References internal_decode_field(), internal_validate_candidate(), k_ra8_err_protocol_error, k_ra8_net_provision_prefix_bytes, k_ra8_net_provision_psk_bytes_max, k_ra8_net_provision_ssid_bytes_max, k_ra8_net_provision_url_bytes_max, k_ra8_ok, ra8_net_credentials::psk, ra8_net_credentials::psk_len, ra8_net_credentials::ssid, ra8_net_credentials::ssid_len, ra8_net_credentials::url, and ra8_net_credentials::url_len.

Referenced by ra8_net_provision_parse().

◆ internal_find_newline()

bool internal_find_newline ( const uint8_t * chunk,
size_t length,
size_t * newline_offset )
static

Locate a newline in one newly received chunk.

Performs a forward bounded scan and reports only the first newline, allowing the receiver to reject any bytes that follow one record.

Parameters
[in]chunkNewly received bytes.
[in]lengthNumber of bytes in the chunk.
[out]newline_offsetOffset of the first newline when found.
Returns
Whether a newline was found.
Return values
truenewline_offset names the first newline.
falseNo newline was present and newline_offset is zero.
Precondition
chunk addresses length readable bytes.
newline_offset is non-null.
Postcondition
At most length bytes were examined.
Input remains unchanged.
Note
Pure helper; thread-safe.
Since
0.1.0

Definition at line 443 of file ra8_net_provision.c.

Referenced by internal_receive_line().

◆ internal_has_no_controls()

bool internal_has_no_controls ( const char * text,
size_t length )
static

Check a decoded text field for C0 and DEL control bytes.

Scans the caller-bounded decoded extent and stops at the first C0 or DEL byte because downstream network APIs require printable text.

Parameters
[in]textDecoded text storage.
[in]lengthBytes to examine, excluding the appended terminator.
Returns
Whether every payload byte is free of control bytes.
Return values
trueNo C0 or DEL control byte was present.
falseA decoded payload byte was C0 or DEL.
Precondition
text addresses at least length bytes.
length is bounded by one protocol field maximum.
Postcondition
Input remains unchanged.
Exactly length bytes were examined unless a control byte was found.
Note
Pure helper; thread-safe.
Since
0.1.0

Definition at line 180 of file ra8_net_provision.c.

References k_ra8_net_provision_text_delete, k_ra8_net_provision_text_printable_min, and RA8_INTERNAL.

Referenced by internal_validate_candidate().

◆ internal_hex_nibble()

bool internal_hex_nibble ( uint8_t digit,
uint8_t * out )
static

Decode one hexadecimal digit.

Accepts decimal and either case of ASCII hexadecimal letters.

Parameters
[in]digitASCII byte to decode.
[out]outDecoded nibble on success.
Returns
Whether digit was hexadecimal.
Return values
trueout contains a value in 0..15.
falsedigit was not hexadecimal and out is zero.
Precondition
out is non-null.
digit is one byte from the bounded input line.
Postcondition
Success initializes out with one nibble.
Failure initializes out to zero.
Note
Pure helper; thread-safe.
Since
0.1.0

Definition at line 94 of file ra8_net_provision.c.

References k_ra8_net_provision_hex_alpha_offset, and RA8_INTERNAL.

Referenced by internal_decode_field(), and internal_psk_is_hex().

◆ internal_prefix_matches()

bool internal_prefix_matches ( const uint8_t * line)
static

Check the fixed version prefix without a libc comparison.

Compares each byte against immutable prefix storage so the caller needs no temporary NUL terminator or unbounded string operation.

Parameters
[in]lineInput line with at least the prefix length.
Returns
Whether every fixed prefix byte matched.
Return values
trueThe line begins with RA8NET1:.
falseAt least one prefix byte differed.
Precondition
line addresses at least eight readable bytes.
Prefix storage is initialized.
Postcondition
Neither input nor prefix storage changes.
At most eight bytes were examined.
Note
Pure helper; thread-safe.
Since
0.1.0

Definition at line 340 of file ra8_net_provision.c.

References k_ra8_net_provision_prefix_bytes, RA8_INTERNAL, and s_prefix.

Referenced by ra8_net_provision_parse().

◆ internal_psk_is_hex()

bool internal_psk_is_hex ( const char * psk)
static

Check whether a decoded 64-byte PSK contains only ASCII hex.

Reuses the protocol nibble classifier for every decoded PSK byte; this distinguishes a raw 256-bit hexadecimal key from passphrases.

Parameters
[in]pskDecoded PSK text.
Returns
Whether all 64 bytes are hexadecimal characters.
Return values
trueEvery byte is ASCII hexadecimal.
falseAt least one byte is not ASCII hexadecimal.
Precondition
psk addresses at least 64 bytes.
The caller invokes this only for a 64-byte PSK.
Postcondition
Input remains unchanged.
At most 64 bytes were examined.
Note
Pure helper; thread-safe.
Since
0.1.0

Definition at line 207 of file ra8_net_provision.c.

References internal_hex_nibble(), k_ra8_net_provision_psk_bytes_max, and RA8_INTERNAL.

Referenced by internal_validate_candidate().

◆ internal_receive_line()

ra8_err_t internal_receive_line ( const ra8_net_provision_uart_t * uart,
uint32_t timeout_ms,
uint8_t * line,
size_t line_capacity,
size_t * line_length )
static

Receive exactly one newline-terminated provisioning record.

Polls the injected UART for at most timeout_ms iterations, rejects bytes after the first newline, and bounds all writes by the supplied line capacity.

Parameters
[in]uartValidated UART binding.
[in]timeout_msMaximum one-millisecond polling iterations.
[out]lineCaller-owned receive buffer.
[in]line_capacityWritable bytes in line.
[out]line_lengthReceived bytes through the newline on success.
Returns
Bounded receive status.
Return values
k_ra8_okOne complete record was received.
k_ra8_err_timeoutNo complete record arrived before the deadline.
k_ra8_err_invalid_sizeThe record filled the buffer without a newline.
k_ra8_err_protocol_errorA read over-reported bytes or included trailing data.
Precondition
uart contains non-NULL read and wait callbacks.
line and line_length are non-NULL and line_capacity is nonzero.
Postcondition
Success sets line_length to the complete record size.
The helper performs no reads or waits after detecting a newline.
Note
Synchronous and not thread-safe for a shared UART binding.
Since
0.1.0

Definition at line 477 of file ra8_net_provision.c.

References internal_find_newline(), k_ra8_err_invalid_size, k_ra8_err_protocol_error, k_ra8_err_timeout, k_ra8_ok, RA8_INTERNAL, ra8_net_provision_uart::read, and ra8_net_provision_uart::wait_ms.

Referenced by ra8_net_provision_receive().

◆ internal_validate_candidate()

ra8_err_t internal_validate_candidate ( const ra8_net_credentials_t * candidate)
static

Validate decoded field lengths and string compatibility.

Applies required-field bounds first, then rejects C0 and DEL controls and enforces the hexadecimal rule for 64-byte PSKs.

Parameters
[in]candidateFully decoded candidate record.
Returns
Repository error code.
Return values
k_ra8_okEvery field satisfies the version-one contract.
k_ra8_err_invalid_sizeA required field length was invalid.
k_ra8_err_protocol_errorA field contained a control byte or a 64-byte PSK was not hexadecimal.
Precondition
Candidate length fields describe their corresponding arrays.
Every array has a trailing NUL after its declared length.
Postcondition
Candidate remains unchanged.
Success guarantees compatibility with existing C-string consumers.
Note
Pure helper; thread-safe.
Since
0.1.0

Definition at line 235 of file ra8_net_provision.c.

References internal_has_no_controls(), internal_psk_is_hex(), k_ra8_err_invalid_size, k_ra8_err_protocol_error, k_ra8_net_provision_psk_bytes_max, k_ra8_ok, ra8_net_credentials::psk, ra8_net_credentials::psk_len, RA8_INTERNAL, ra8_net_credentials::ssid, ra8_net_credentials::ssid_len, ra8_net_credentials::url, and ra8_net_credentials::url_len.

Referenced by internal_decode_line().

◆ internal_validate_receiver()

ra8_err_t internal_validate_receiver ( const ra8_net_provision_uart_t * uart,
uint32_t timeout_ms )
static

Validate the injected receiver dependencies and timeout.

Rejects an absent operation row before any callback can run, then constrains the caller's timeout to the protocol's fixed maximum.

Parameters
[in]uartUART operation table to validate.
[in]timeout_msRequested timeout.
Returns
Repository error code.
Return values
k_ra8_okEvery dependency and bound is valid.
k_ra8_err_null_ptrThe table or one row was null.
k_ra8_err_invalid_argThe timeout was outside 1..60000.
Precondition
No operation row is invoked by this helper.
The timeout is an untrusted caller input.
Postcondition
UART state remains unchanged.
Success permits the bounded receiver loop to start.
Note
Pure validation helper; thread-safe.
Since
0.1.0

Definition at line 404 of file ra8_net_provision.c.

References k_ra8_err_invalid_arg, k_ra8_err_null_ptr, k_ra8_net_provision_timeout_ms_max, k_ra8_ok, RA8_INTERNAL, ra8_net_provision_uart::read, ra8_net_provision_uart::wait_ms, and ra8_net_provision_uart::write.

Referenced by ra8_net_provision_receive().

◆ ra8_net_provision_clear()

void ra8_net_provision_clear ( ra8_net_credentials_t * credentials)

Explicitly erase one decoded credential record.

Uses the repository secure-memory primitive so optimization cannot discard the overwrite. A null record is accepted for cleanup paths that do not know whether provisioning completed.

Parameters
[in,out]credentialsRecord to erase; null is a no-op.
Returns
Nothing.
Precondition
credentials is null or addresses a writable record.
No concurrent consumer is reading the record.
Postcondition
Every byte in a non-null record is zero.
The erase cannot be removed as a dead store by optimization.
Note
Call immediately after the final synchronous credential consumer.
Warning
This does not erase copies already retained by another subsystem.
Since
0.1.0

Definition at line 350 of file ra8_net_provision.c.

References ra8_secure_memzero().

Referenced by c6_join_worker_entry(), internal_c6_cam_worker_entry(), internal_worker(), ra8_net_provision_parse(), ra8_net_provision_receive(), and wifi_hal_worker_entry().

◆ ra8_net_provision_parse()

ra8_err_t ra8_net_provision_parse ( const uint8_t * line,
size_t line_length,
ra8_net_credentials_t * out )
nodiscard

Parse one complete version-one ASCII-hex provisioning line.

Accepts exactly RA8NET1:<ssid_hex>:<psk_hex>:<url_hex>\n. Each pair of hexadecimal characters decodes to one output byte. SSID is required and at most 32 bytes. PSK is 8..63 bytes, or exactly 64 hexadecimal characters. URL is optional and at most 511 bytes. Decoded C0 and DEL control bytes are rejected because the existing Wi-Fi and media APIs consume printable text.

Parameters
[in]lineComplete line bytes, including the final newline.
[in]line_lengthNumber of readable bytes at line.
[out]outDecoded record; cleared before parsing and on every failure.
Returns
Repository error code.
Return values
k_ra8_okThe complete line was valid and decoded.
k_ra8_err_null_ptrline or out was null.
k_ra8_err_invalid_sizeA line or decoded field exceeded its bound.
k_ra8_err_protocol_errorPrefix, separators, newline, or hex syntax was invalid.
Precondition
line addresses line_length readable bytes when non-null.
out addresses one writable credential record.
Postcondition
On success, every output field is bounded and NUL-terminated.
On failure, every byte of out is zero.
Note
Thread-safe for distinct input and output objects.
Warning
Treat the input and successful output as secret-bearing memory.
Since
0.1.0

Definition at line 358 of file ra8_net_provision.c.

References internal_decode_line(), internal_prefix_matches(), k_ra8_err_invalid_size, k_ra8_err_null_ptr, k_ra8_err_protocol_error, k_ra8_net_provision_line_bytes_max, k_ra8_net_provision_prefix_bytes, k_ra8_ok, and ra8_net_provision_clear().

Referenced by ra8_net_provision_receive().

◆ ra8_net_provision_receive()

ra8_err_t ra8_net_provision_receive ( const ra8_net_provision_uart_t * uart,
uint32_t timeout_ms,
ra8_net_credentials_t * out )
nodiscard

Prompt once and receive one provisioning line within a fixed timeout.

Writes k_ra8_net_provision_ready_prompt, then drains the injected non-blocking UART into fixed stack storage. It never echoes input. Every incomplete poll waits one millisecond; therefore timeout_ms is both the poll limit and a lower bound on elapsed wait time. The budget is capped at 60 seconds. The raw line buffer is explicitly zeroed before every return.

Parameters
[in]uartComplete UART operation table.
[in]timeout_msReceive budget in milliseconds, 1..60000.
[out]outDecoded record; cleared before receive and on every failure.
Returns
Repository error code.
Return values
k_ra8_okOne valid line was received and decoded.
k_ra8_err_null_ptruart, an operation row, or out was null.
k_ra8_err_invalid_argtimeout_ms was zero or above the fixed cap.
k_ra8_err_invalid_sizeInput filled the fixed line buffer.
k_ra8_err_timeoutNo complete line arrived within the budget.
k_ra8_err_protocol_errorThe complete line was malformed.
Precondition
The UART was initialized before this call.
read is non-blocking and never reports more than its capacity.
Postcondition
The prompt was attempted before the first read.
Raw line storage is zeroed and failure leaves out zeroed.
Note
Not thread-safe when callers share one UART.
Warning
The UART is a controlled-bench provisioning channel, not durable storage.
Since
0.1.0

Definition at line 520 of file ra8_net_provision.c.

References internal_receive_line(), internal_validate_receiver(), k_ra8_err_null_ptr, k_ra8_net_provision_line_bytes_max, k_ra8_net_provision_ready_prompt, k_ra8_ok, ra8_net_provision_clear(), ra8_net_provision_parse(), ra8_secure_memzero(), and ra8_net_provision_uart::write.

Referenced by c6_join_worker_entry(), internal_c6_cam_worker_entry(), internal_worker(), and wifi_hal_worker_entry().

Variable Documentation

◆ k_ra8_net_provision_ready_prompt

const char k_ra8_net_provision_ready_prompt[] = "ra8_net_provision: READY v1\r\n"

Exact non-secret line emitted before the receiver drains UART input.

The HIL provisioner waits for this versioned prompt before sending one RA8NET1 line to a freshly flashed credential-free image.

Note
This constant never contains user or network data.
Since
0.1.0

Definition at line 77 of file ra8_net_provision.c.

Referenced by ra8_net_provision_receive().

◆ s_prefix

const uint8_t s_prefix[k_ra8_net_provision_prefix_bytes]
static
Initial value:
= {
'R',
'A',
'8',
'N',
'E',
'T',
'1',
':',
}

Exact protocol prefix, including the first field separator.

Definition at line 28 of file ra8_net_provision.c.

Referenced by internal_prefix_matches(), internal_temp_name(), internal_temp_name(), internal_temp_name(), and internal_temp_name().