S557 · SOURCE-BOUND GATE EVIDENCE
S557 · R1 modem: paket veri PDP bağlamı ve PPP çerçeve modeli
tam S557 implementation modülü → Operations --test hedefi ile bağlı tam focused test → ayrı Operations kaydı Bu sayfa yalnız S557 kapısına aittir; komşu kapıların kaynakları bu kabulün içine katılmaz.
S557Focused kod testiOperations id exactsource SHA exacttest target exact
operation: g8l-s557-r1-packet-data-pdp-context-ppp-frame-model
uygulama/model · focused test · Operations · 3 exact excerpt
sequence-bound=true · implementation-bound=true
01 · Yürütme / doğrulama kodu
Kapının gerçek repository sözleşmesi
tam dosyaL1–L799
kernel/src/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s557_r1_packet_data_pdp_context_ppp_frame_model.rs::S557 r1 packet data pdp context ppp frame model implementation
#![allow(unexpected_cfgs)]
//! S557 models the R1 packet-data bring-up path of the modem stage as a pure
//! source/host model: `+CGDCONT` PDP context definition (cid, PDP type,
//! validated APN), the `+CGACT` activation state machine, `+CGPADDR` address
//! parsing, and a PPP/HDLC framing layer (0x7E flags, 0x7D/0x20 byte stuffing,
//! ACCM, FCS-16 with polynomial 0x8408, initial 0xFFFF and good residue
//! 0xF0B8) with minimal LCP/IPCP option parsing into tagged structures.
//!
//! The gate makes no hardware claim: no modem, no UART, no PPP peer, no
//! board observation exists for S557; physical observations = 0,
//! `RUNBOOK_EXECUTED_IN_S557=NO`, Boot-to-UI physically observed = false and
//! R1 acceptance complete = false. Nothing here is wired into a boot, IRQ,
//! scheduler or driver path; the focused host test is the only caller. It
//! performs no device operation and does not rerun S540 or S543, whose
//! physical RED verdicts remain immutable.
//!
//! Predecessor: S556 (SMS PDU encode/decode model). Next gate: S558 (voice
//! call state machine model).
use alloc::string::String;
use alloc::vec::Vec;
pub const S557_SEQUENCE: usize = 557;
pub const S557_EXPECTED_PREDECESSOR: usize = 556;
pub const S557_R1_STAGE: u8 = 3;
pub const S557_R1_RANGE_FIRST: usize = 536;
pub const S557_R1_RANGE_LAST: usize = 568;
pub const S557_SUPPORTED_PROFILE_RUNTIME_OBSERVATIONS: usize = 0;
pub const S557_PHYSICAL_OBSERVATIONS: usize = 0;
pub const S557_PHYSICAL_OR_DEVICE_OPERATIONS: usize = 0;
pub const S557_SD_WRITES: usize = 0;
pub const S557_UART_OPENS: usize = 0;
pub const S557_POWER_TRANSITIONS: usize = 0;
pub const S557_NEW_IMMUTABLE_RAW_CAPTURES: usize = 0;
pub const S557_S540_PHYSICAL_VERDICT_RETAINED_RED: bool = true;
pub const S557_S543_PHYSICAL_VERDICT_RETAINED_RED: bool = true;
pub const S557_AUTOMATIC_PROMOTION: bool = false;
pub const S557_BOOT_TO_UI_PHYSICALLY_OBSERVED: bool = false;
pub const S557_HARDWARE_PRESENT: bool = false;
pub const S557_R1_ACCEPTANCE_COMPLETE: bool = false;
pub const RUNBOOK_EXECUTED_IN_S557: bool = false;
pub const S557_CID_MIN: u8 = 1;
pub const S557_CID_MAX: u8 = 8;
pub const S557_APN_MAX_LEN: usize = 63;
pub const S557_APN_LABEL_MAX_LEN: usize = 63;
pub const S557_PPP_FLAG: u8 = 0x7E;
pub const S557_PPP_ESCAPE: u8 = 0x7D;
pub const S557_PPP_ESCAPE_XOR: u8 = 0x20;
pub const S557_PPP_ADDRESS: u8 = 0xFF;
pub const S557_PPP_CONTROL: u8 = 0x03;
pub const S557_PPP_DEFAULT_ACCM: u32 = 0xFFFF_FFFF;
pub const S557_FCS_POLY: u16 = 0x8408;
pub const S557_FCS_INIT: u16 = 0xFFFF;
pub const S557_FCS_GOOD: u16 = 0xF0B8;
pub const S557_PPP_MAX_INFO: usize = 1500;
pub const S557_PPP_HEADER_LEN: usize = 4;
pub const S557_PPP_FCS_LEN: usize = 2;
pub const S557_PPP_MAX_UNSTUFFED_FRAME: usize =
S557_PPP_MAX_INFO + S557_PPP_HEADER_LEN + S557_PPP_FCS_LEN;
pub const S557_PROTOCOL_LCP: u16 = 0xC021;
pub const S557_PROTOCOL_IPCP: u16 = 0x8021;
pub const S557_PROTOCOL_IPV4: u16 = 0x0021;
pub const S557_LCP_OPTION_MRU: u8 = 1;
pub const S557_LCP_OPTION_MAGIC: u8 = 5;
pub const S557_IPCP_OPTION_IP_ADDRESS: u8 = 3;
pub const S557_CP_HEADER_LEN: usize = 4;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS557PdpType {
Ip,
Ipv4v6,
}
impl G8lS557PdpType {
pub const fn at_token(self) -> &'static str {
match self {
Self::Ip => "IP",
Self::Ipv4v6 => "IPV4V6",
}
}
pub fn from_at_token(token: &str) -> Option<Self> {
match token {
"IP" => Some(Self::Ip),
"IPV4V6" => Some(Self::Ipv4v6),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS557Apn {
bytes: [u8; S557_APN_MAX_LEN],
len: u8,
labels: u8,
}
impl G8lS557Apn {
pub fn parse(text: &str) -> Result<Self, G8lS557PacketDataError> {
let raw = text.as_bytes();
if raw.is_empty() {
return Err(G8lS557PacketDataError::ApnEmpty);
}
if raw.len() > S557_APN_MAX_LEN {
return Err(G8lS557PacketDataError::ApnTooLong);
}
let mut labels: u8 = 0;
for label in raw.split(|&byte| byte == b'.') {
if label.is_empty() || label.len() > S557_APN_LABEL_MAX_LEN {
return Err(G8lS557PacketDataError::ApnInvalidLabel);
}
if label[0] == b'-' || label[label.len() - 1] == b'-' {
return Err(G8lS557PacketDataError::ApnInvalidLabel);
}
for &byte in label {
if !(byte.is_ascii_alphanumeric() || byte == b'-') {
return Err(G8lS557PacketDataError::ApnInvalidCharacter);
}
}
labels = labels
.checked_add(1)
.ok_or(G8lS557PacketDataError::ApnInvalidLabel)?;
}
let mut bytes = [0u8; S557_APN_MAX_LEN];
bytes[..raw.len()].copy_from_slice(raw);
Ok(Self {
bytes,
len: raw.len() as u8,
labels,
})
}
pub fn as_str(&self) -> &str {
core::str::from_utf8(&self.bytes[..self.len as usize]).unwrap_or("")
}
pub const fn len(&self) -> usize {
self.len as usize
}
pub const fn is_empty(&self) -> bool {
self.len == 0
}
pub const fn label_count(&self) -> u8 {
self.labels
}
/// Deterministic FNV-1a 64-bit digest of the APN bytes for the receipt.
pub fn fnv1a(&self) -> u64 {
let mut hash: u64 = 0xcbf2_9ce4_8422_2325;
for &byte in &self.bytes[..self.len as usize] {
hash ^= byte as u64;
hash = hash.wrapping_mul(0x0000_0100_0000_01b3);
}
hash
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS557PdpContext {
pub cid: u8,
pub pdp_type: G8lS557PdpType,
pub apn: G8lS557Apn,
}
impl G8lS557PdpContext {
pub fn define(
cid: u8,
pdp_type: G8lS557PdpType,
apn: &str,
) -> Result<Self, G8lS557PacketDataError> {
if !(S557_CID_MIN..=S557_CID_MAX).contains(&cid) {
return Err(G8lS557PacketDataError::CidOutOfRange);
}
Ok(Self {
cid,
pdp_type,
apn: G8lS557Apn::parse(apn)?,
})
}
pub fn encode_cgdcont(&self) -> String {
alloc::format!(
"AT+CGDCONT={},\"{}\",\"{}\"",
self.cid,
self.pdp_type.at_token(),
self.apn.as_str()
)
}
pub fn encode_cgact(&self, activate: bool) -> String {
alloc::format!("AT+CGACT={},{}", u8::from(activate), self.cid)
}
}
/// Parses `+CGDCONT: <cid>,"<type>","<apn>"[,...]` into a validated context.
pub fn parse_cgdcont_line(line: &str) -> Result<G8lS557PdpContext, G8lS557PacketDataError> {
let body = line
.strip_prefix("+CGDCONT: ")
.ok_or(G8lS557PacketDataError::CgdcontMalformed)?;
let mut fields = body.splitn(4, ',');
let cid = fields
.next()
.and_then(|field| field.parse::<u8>().ok())
.ok_or(G8lS557PacketDataError::CgdcontMalformed)?;
let pdp_type = fields
.next()
.and_then(strip_quotes)
.and_then(G8lS557PdpType::from_at_token)
.ok_or(G8lS557PacketDataError::CgdcontMalformed)?;
let apn = fields
.next()
.and_then(strip_quotes)
.ok_or(G8lS557PacketDataError::CgdcontMalformed)?;
G8lS557PdpContext::define(cid, pdp_type, apn)
}
fn strip_quotes(field: &str) -> Option<&str> {
field.strip_prefix('"')?.strip_suffix('"')
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum G8lS557ActivationState {
#[default]
Defined,
Activating,
Active,
Deactivating,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS557ActivationEvent {
ActivateRequested,
ActivateOk,
ActivateError,
DeactivateRequested,
DeactivateOk,
NetworkDetach,
}
/// Table-driven `+CGACT` transition; every pair not listed fails closed.
pub fn activation_transition(
state: G8lS557ActivationState,
event: G8lS557ActivationEvent,
) -> Result<G8lS557ActivationState, G8lS557PacketDataError> {
use G8lS557ActivationEvent as E;
use G8lS557ActivationState as S;
match (state, event) {
(S::Defined, E::ActivateRequested) => Ok(S::Activating),
(S::Activating, E::ActivateOk) => Ok(S::Active),
(S::Activating, E::ActivateError) => Ok(S::Defined),
(S::Active, E::DeactivateRequested) => Ok(S::Deactivating),
(S::Active, E::NetworkDetach) => Ok(S::Defined),
(S::Deactivating, E::DeactivateOk) => Ok(S::Defined),
_ => Err(G8lS557PacketDataError::ActivationTransitionInvalid),
}
}
/// Parses `+CGACT: <cid>,<state>` where state is `0` or `1`.
pub fn parse_cgact_line(line: &str) -> Result<(u8, bool), G8lS557PacketDataError> {
let body = line
.strip_prefix("+CGACT: ")
.ok_or(G8lS557PacketDataError::CgactMalformed)?;
let (cid, state) = body
.split_once(',')
.ok_or(G8lS557PacketDataError::CgactMalformed)?;
let cid = cid
.parse::<u8>()
.map_err(|_| G8lS557PacketDataError::CgactMalformed)?;
if !(S557_CID_MIN..=S557_CID_MAX).contains(&cid) {
return Err(G8lS557PacketDataError::CidOutOfRange);
}
match state {
"0" => Ok((cid, false)),
"1" => Ok((cid, true)),
_ => Err(G8lS557PacketDataError::CgactMalformed),
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS557PdpAddress {
V4([u8; 4]),
V6([u8; 16]),
}
fn parse_dotted_address(text: &str) -> Result<G8lS557PdpAddress, G8lS557PacketDataError> {
let mut octets = [0u8; 16];
let mut count: usize = 0;
for group in text.split('.') {
if group.is_empty() || group.len() > 3 || !group.bytes().all(|b| b.is_ascii_digit()) {
return Err(G8lS557PacketDataError::AddressOctetOutOfRange);
}
let value = group
.parse::<u16>()
.map_err(|_| G8lS557PacketDataError::AddressOctetOutOfRange)?;
if value > 255 {
return Err(G8lS557PacketDataError::AddressOctetOutOfRange);
}
if count >= 16 {
return Err(G8lS557PacketDataError::AddressGroupCount);
}
octets[count] = value as u8;
count += 1;
}
match count {
4 => Ok(G8lS557PdpAddress::V4([
octets[0], octets[1], octets[2], octets[3],
])),
16 => Ok(G8lS557PdpAddress::V6(octets)),
_ => Err(G8lS557PacketDataError::AddressGroupCount),
}
}
/// Parses `+CGPADDR: <cid>,"<addr>"[,"<addr6>"]` and returns the cid plus the
/// first (IPv4) address and the optional second (IPv6) address.
pub fn parse_cgpaddr_line(
line: &str,
) -> Result<(u8, G8lS557PdpAddress, Option<G8lS557PdpAddress>), G8lS557PacketDataError> {
let body = line
.strip_prefix("+CGPADDR: ")
.ok_or(G8lS557PacketDataError::CgpaddrMalformed)?;
let mut fields = body.splitn(3, ',');
let cid = fields
.next()
.and_then(|field| field.parse::<u8>().ok())
.ok_or(G8lS557PacketDataError::CgpaddrMalformed)?;
if !(S557_CID_MIN..=S557_CID_MAX).contains(&cid) {
return Err(G8lS557PacketDataError::CidOutOfRange);
}
let first = fields
.next()
.and_then(strip_quotes)
.ok_or(G8lS557PacketDataError::CgpaddrMalformed)?;
let first = parse_dotted_address(first)?;
let second = match fields.next() {
None => None,
Some(field) => Some(parse_dotted_address(
strip_quotes(field).ok_or(G8lS557PacketDataError::CgpaddrMalformed)?,
)?),
};
Ok((cid, first, second))
}
/// RFC 1662 FCS-16 running computation (polynomial 0x8408, reflected).
pub fn ppp_fcs16(init: u16, data: &[u8]) -> u16 {
let mut fcs = init;
for &byte in data {
fcs ^= byte as u16;
for _ in 0..8 {
fcs = if fcs & 1 != 0 {
(fcs >> 1) ^ S557_FCS_POLY
} else {
fcs >> 1
};
}
}
fcs
}
/// The two FCS bytes appended on the wire (ones-complement, low byte first).
pub fn ppp_fcs16_trailer(data: &[u8]) -> [u8; 2] {
let fcs = ppp_fcs16(S557_FCS_INIT, data) ^ 0xFFFF;
[(fcs & 0xFF) as u8, (fcs >> 8) as u8]
}
const fn needs_escape(byte: u8, accm: u32) -> bool {
byte == S557_PPP_FLAG || byte == S557_PPP_ESCAPE || (byte < 0x20 && (accm >> byte) & 1 == 1)
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct G8lS557PppFrame {
pub protocol: u16,
pub info: Vec<u8>,
pub fcs_trailer: [u8; 2],
}
pub fn encode_ppp_frame(
protocol: u16,
info: &[u8],
accm: u32,
) -> Result<Vec<u8>, G8lS557PacketDataError> {
if info.len() > S557_PPP_MAX_INFO {
return Err(G8lS557PacketDataError::PppInfoOversize);
}
if protocol & 0x0100 != 0 || protocol & 0x0001 != 1 {
return Err(G8lS557PacketDataError::PppProtocolMalformed);
}
let mut unstuffed: Vec<u8> =
Vec::with_capacity(info.len() + S557_PPP_HEADER_LEN + S557_PPP_FCS_LEN);
unstuffed.push(S557_PPP_ADDRESS);
unstuffed.push(S557_PPP_CONTROL);
unstuffed.push((protocol >> 8) as u8);
unstuffed.push((protocol & 0xFF) as u8);
unstuffed.extend_from_slice(info);
let trailer = ppp_fcs16_trailer(&unstuffed);
unstuffed.extend_from_slice(&trailer);
let mut wire: Vec<u8> = Vec::with_capacity(unstuffed.len() * 2 + 2);
wire.push(S557_PPP_FLAG);
for &byte in &unstuffed {
if needs_escape(byte, accm) {
wire.push(S557_PPP_ESCAPE);
wire.push(byte ^ S557_PPP_ESCAPE_XOR);
} else {
wire.push(byte);
}
}
wire.push(S557_PPP_FLAG);
Ok(wire)
}
pub fn decode_ppp_frame(wire: &[u8], accm: u32) -> Result<G8lS557PppFrame, G8lS557PacketDataError> {
if wire.len() < 2 || wire[0] != S557_PPP_FLAG || wire[wire.len() - 1] != S557_PPP_FLAG {
return Err(G8lS557PacketDataError::PppMissingFlag);
}
let body = &wire[1..wire.len() - 1];
let mut unstuffed: Vec<u8> = Vec::with_capacity(body.len());
let mut index = 0usize;
while index < body.len() {
let byte = body[index];
if byte == S557_PPP_FLAG {
return Err(G8lS557PacketDataError::PppMissingFlag);
}
if byte == S557_PPP_ESCAPE {
let next = *body
.get(index + 1)
.ok_or(G8lS557PacketDataError::PppBadEscape)?;
if next == S557_PPP_FLAG {
// 0x7D 0x7E is the RFC 1662 abort sequence.
return Err(G8lS557PacketDataError::PppBadEscape);
}
unstuffed.push(next ^ S557_PPP_ESCAPE_XOR);
index += 2;
} else {
if byte < 0x20 && (accm >> byte) & 1 == 1 {
return Err(G8lS557PacketDataError::PppUnescapedControl);
}
unstuffed.push(byte);
index += 1;
}
if unstuffed.len() > S557_PPP_MAX_UNSTUFFED_FRAME {
return Err(G8lS557PacketDataError::PppInfoOversize);
}
}
if unstuffed.len() < S557_PPP_HEADER_LEN + S557_PPP_FCS_LEN {
return Err(G8lS557PacketDataError::PppFrameTooShort);
}
if ppp_fcs16(S557_FCS_INIT, &unstuffed) != S557_FCS_GOOD {
return Err(G8lS557PacketDataError::PppBadFcs);
}
if unstuffed[0] != S557_PPP_ADDRESS || unstuffed[1] != S557_PPP_CONTROL {
return Err(G8lS557PacketDataError::PppAddressControlMismatch);
}
let protocol = ((unstuffed[2] as u16) << 8) | unstuffed[3] as u16;
if unstuffed[2] & 1 != 0 || unstuffed[3] & 1 != 1 {
return Err(G8lS557PacketDataError::PppProtocolMalformed);
}
let info_end = unstuffed.len() - S557_PPP_FCS_LEN;
Ok(G8lS557PppFrame {
protocol,
info: unstuffed[S557_PPP_HEADER_LEN..info_end].to_vec(),
fcs_trailer: [unstuffed[info_end], unstuffed[info_end + 1]],
})
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS557CpCode {
ConfigureRequest,
ConfigureAck,
ConfigureNak,
ConfigureReject,
TerminateRequest,
TerminateAck,
CodeReject,
ProtocolReject,
EchoRequest,
EchoReply,
DiscardRequest,
}
impl G8lS557CpCode {
pub const fn from_byte(code: u8) -> Option<Self> {
match code {
1 => Some(Self::ConfigureRequest),
2 => Some(Self::ConfigureAck),
3 => Some(Self::ConfigureNak),
4 => Some(Self::ConfigureReject),
5 => Some(Self::TerminateRequest),
6 => Some(Self::TerminateAck),
7 => Some(Self::CodeReject),
8 => Some(Self::ProtocolReject),
9 => Some(Self::EchoRequest),
10 => Some(Self::EchoReply),
11 => Some(Self::DiscardRequest),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS557CpOption {
LcpMru(u16),
LcpMagic(u32),
IpcpIpAddress([u8; 4]),
Unrecognized { kind: u8, length: u8 },
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct G8lS557CpPacket {
pub protocol: u16,
pub code: G8lS557CpCode,
pub identifier: u8,
pub options: Vec<G8lS557CpOption>,
}
/// Parses an LCP (0xC021) or IPCP (0x8021) packet from a PPP information field.
pub fn parse_cp_packet(
protocol: u16,
info: &[u8],
) -> Result<G8lS557CpPacket, G8lS557PacketDataError> {
if protocol != S557_PROTOCOL_LCP && protocol != S557_PROTOCOL_IPCP {
return Err(G8lS557PacketDataError::CpProtocolUnsupported);
}
if info.len() < S557_CP_HEADER_LEN {
return Err(G8lS557PacketDataError::CpPacketTooShort);
}
let code = G8lS557CpCode::from_byte(info[0]).ok_or(G8lS557PacketDataError::CpUnknownCode)?;
let identifier = info[1];
let length = ((info[2] as usize) << 8) | info[3] as usize;
if length != info.len() {
return Err(G8lS557PacketDataError::CpLengthMismatch);
}
let mut options = Vec::new();
let mut cursor = S557_CP_HEADER_LEN;
while cursor < info.len() {
let remaining = info.len() - cursor;
if remaining < 2 {
return Err(G8lS557PacketDataError::CpOptionLengthInvalid);
}
let kind = info[cursor];
let option_len = info[cursor + 1] as usize;
if option_len < 2 || option_len > remaining {
return Err(G8lS557PacketDataError::CpOptionLengthInvalid);
}
let payload = &info[cursor + 2..cursor + option_len];
let option = match (protocol, kind) {
(S557_PROTOCOL_LCP, S557_LCP_OPTION_MRU) => {
if payload.len() != 2 {
return Err(G8lS557PacketDataError::CpOptionLengthInvalid);
}
G8lS557CpOption::LcpMru(((payload[0] as u16) << 8) | payload[1] as u16)
}
(S557_PROTOCOL_LCP, S557_LCP_OPTION_MAGIC) => {
if payload.len() != 4 {
return Err(G8lS557PacketDataError::CpOptionLengthInvalid);
}
G8lS557CpOption::LcpMagic(u32::from_be_bytes([
payload[0], payload[1], payload[2], payload[3],
]))
}
(S557_PROTOCOL_IPCP, S557_IPCP_OPTION_IP_ADDRESS) => {
if payload.len() != 4 {
return Err(G8lS557PacketDataError::CpOptionLengthInvalid);
}
G8lS557CpOption::IpcpIpAddress([payload[0], payload[1], payload[2], payload[3]])
}
_ => G8lS557CpOption::Unrecognized {
kind,
length: option_len as u8,
},
};
options.push(option);
cursor += option_len;
}
Ok(G8lS557CpPacket {
protocol,
code,
identifier,
options,
})
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS557PacketDataReceipt {
pub sequence: usize,
pub predecessor_sequence: usize,
pub r1_stage: u8,
pub cid: u8,
pub pdp_type: G8lS557PdpType,
pub apn_len: usize,
pub apn_label_count: u8,
pub apn_fnv1a: u64,
pub activation_state: G8lS557ActivationState,
pub activation_events: usize,
pub pdp_address: G8lS557PdpAddress,
pub has_ipv6_address: bool,
pub ipcp_identifier: u8,
pub ipcp_ip_address: [u8; 4],
pub frame_info_len: usize,
pub frame_fcs_trailer: [u8; 2],
pub hardware_present: bool,
pub s540_physical_verdict_retained_red: bool,
pub s543_physical_verdict_retained_red: bool,
pub automatic_promotion: bool,
pub supported_profile_runtime_observations: usize,
pub physical_observations: usize,
pub runbook_executed: bool,
}
#[derive(Debug)]
pub struct G8lS557PacketDataState {
receipt: Option<G8lS557PacketDataReceipt>,
}
impl G8lS557PacketDataState {
pub const fn new() -> Self {
Self { receipt: None }
}
pub const fn receipt(&self) -> Option<G8lS557PacketDataReceipt> {
self.receipt
}
}
impl Default for G8lS557PacketDataState {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS557PacketDataOutcome {
Published(G8lS557PacketDataReceipt),
Retained(G8lS557PacketDataReceipt),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS557PacketDataError {
CidOutOfRange,
ApnEmpty,
ApnTooLong,
ApnInvalidCharacter,
ApnInvalidLabel,
CgdcontMalformed,
CgactMalformed,
ActivationTransitionInvalid,
ActivationNotActive,
CgpaddrMalformed,
CgpaddrCidMismatch,
AddressOctetOutOfRange,
AddressGroupCount,
PppInfoOversize,
PppFrameTooShort,
PppMissingFlag,
PppBadEscape,
PppUnescapedControl,
PppAddressControlMismatch,
PppProtocolMalformed,
PppBadFcs,
CpProtocolUnsupported,
CpPacketTooShort,
CpLengthMismatch,
CpUnknownCode,
CpOptionLengthInvalid,
IpcpNotConfigureAck,
IpcpAddressMissing,
IpcpAddressMismatch,
PublishedStateDrift,
}
impl G8lS557PacketDataError {
pub const fn diagnostic_code(self) -> u64 {
match self {
Self::CidOutOfRange => 1,
Self::ApnEmpty => 2,
Self::ApnTooLong => 3,
Self::ApnInvalidCharacter => 4,
Self::ApnInvalidLabel => 5,
Self::CgdcontMalformed => 6,
Self::CgactMalformed => 7,
Self::ActivationTransitionInvalid => 8,
Self::ActivationNotActive => 9,
Self::CgpaddrMalformed => 10,
Self::CgpaddrCidMismatch => 11,
Self::AddressOctetOutOfRange => 12,
Self::AddressGroupCount => 13,
Self::PppInfoOversize => 14,
Self::PppFrameTooShort => 15,
Self::PppMissingFlag => 16,
Self::PppBadEscape => 17,
Self::PppUnescapedControl => 18,
Self::PppAddressControlMismatch => 19,
Self::PppProtocolMalformed => 20,
Self::PppBadFcs => 21,
Self::CpProtocolUnsupported => 22,
Self::CpPacketTooShort => 23,
Self::CpLengthMismatch => 24,
Self::CpUnknownCode => 25,
Self::CpOptionLengthInvalid => 26,
Self::IpcpNotConfigureAck => 27,
Self::IpcpAddressMissing => 28,
Self::IpcpAddressMismatch => 29,
Self::PublishedStateDrift => 30,
}
}
}
/// Pure packet-data bring-up: define the context, drive the `+CGACT` state
/// machine to `Active`, parse the `+CGPADDR` line for the same cid, decode the
/// IPCP Configure-Ack frame and require its IP-Address option to match the
/// assigned IPv4 address. Every invalid input fails closed; an exact replay
/// retains the published receipt; any divergence after publication is
/// rejected.
pub fn service_s557_model_packet_data_bring_up(
state: &mut G8lS557PacketDataState,
context: G8lS557PdpContext,
activation_events: &[G8lS557ActivationEvent],
cgpaddr_line: &str,
ipcp_ack_wire: &[u8],
accm: u32,
) -> Result<G8lS557PacketDataOutcome, G8lS557PacketDataError> {
if !(S557_CID_MIN..=S557_CID_MAX).contains(&context.cid) {
return Err(G8lS557PacketDataError::CidOutOfRange);
}
G8lS557Apn::parse(context.apn.as_str())?;
let mut activation = G8lS557ActivationState::Defined;
for &event in activation_events {
activation = activation_transition(activation, event)?;
}
if activation != G8lS557ActivationState::Active {
return Err(G8lS557PacketDataError::ActivationNotActive);
}
let (cid, pdp_address, ipv6_address) = parse_cgpaddr_line(cgpaddr_line)?;
if cid != context.cid {
return Err(G8lS557PacketDataError::CgpaddrCidMismatch);
}
let ipv4 = match pdp_address {
G8lS557PdpAddress::V4(octets) => octets,
G8lS557PdpAddress::V6(_) => return Err(G8lS557PacketDataError::AddressGroupCount),
};
if context.pdp_type == G8lS557PdpType::Ip && ipv6_address.is_some() {
return Err(G8lS557PacketDataError::CgpaddrMalformed);
}
let frame = decode_ppp_frame(ipcp_ack_wire, accm)?;
if frame.protocol != S557_PROTOCOL_IPCP {
return Err(G8lS557PacketDataError::CpProtocolUnsupported);
}
let packet = parse_cp_packet(frame.protocol, &frame.info)?;
if packet.code != G8lS557CpCode::ConfigureAck {
return Err(G8lS557PacketDataError::IpcpNotConfigureAck);
}
let ipcp_ip_address = packet
.options
.iter()
.find_map(|option| match option {
G8lS557CpOption::IpcpIpAddress(octets) => Some(*octets),
_ => None,
})
.ok_or(G8lS557PacketDataError::IpcpAddressMissing)?;
if ipcp_ip_address != ipv4 {
return Err(G8lS557PacketDataError::IpcpAddressMismatch);
}
let receipt = G8lS557PacketDataReceipt {
sequence: S557_SEQUENCE,
predecessor_sequence: S557_EXPECTED_PREDECESSOR,
r1_stage: S557_R1_STAGE,
cid: context.cid,
pdp_type: context.pdp_type,
apn_len: context.apn.len(),
apn_label_count: context.apn.label_count(),
apn_fnv1a: context.apn.fnv1a(),
activation_state: activation,
activation_events: activation_events.len(),
pdp_address,
has_ipv6_address: ipv6_address.is_some(),
ipcp_identifier: packet.identifier,
ipcp_ip_address,
frame_info_len: frame.info.len(),
frame_fcs_trailer: frame.fcs_trailer,
hardware_present: S557_HARDWARE_PRESENT,
s540_physical_verdict_retained_red: S557_S540_PHYSICAL_VERDICT_RETAINED_RED,
s543_physical_verdict_retained_red: S557_S543_PHYSICAL_VERDICT_RETAINED_RED,
automatic_promotion: S557_AUTOMATIC_PROMOTION,
supported_profile_runtime_observations: S557_SUPPORTED_PROFILE_RUNTIME_OBSERVATIONS,
physical_observations: S557_PHYSICAL_OBSERVATIONS,
runbook_executed: RUNBOOK_EXECUTED_IN_S557,
};
if let Some(published) = state.receipt {
if published != receipt {
return Err(G8lS557PacketDataError::PublishedStateDrift);
}
return Ok(G8lS557PacketDataOutcome::Retained(published));
}
state.receipt = Some(receipt);
Ok(G8lS557PacketDataOutcome::Published(receipt))
}
snippet sha256: 201e68b46969…file sha256: 201e68b46969…
02 · Doğrulayan test kodu
Operations komutuna bağlı focused test
tam dosyaL1–L900
simulation/tests/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s557_r1_packet_data_pdp_context_ppp_frame_model.rs::S557 r1 packet data pdp context ppp frame model focused tests
use aselsan_microkernel_simulation::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s557_r1_packet_data_pdp_context_ppp_frame_model::*;
use std::collections::BTreeSet;
const SOURCE: &str = include_str!(
"../../kernel/src/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s557_r1_packet_data_pdp_context_ppp_frame_model.rs"
);
const MAIN: &str = include_str!("../../kernel/src/main.rs");
const SIMULATION_LIB: &str = include_str!("../src/lib.rs");
const ACTIVATE: [G8lS557ActivationEvent; 2] = [
G8lS557ActivationEvent::ActivateRequested,
G8lS557ActivationEvent::ActivateOk,
];
const CGPADDR: &str = "+CGPADDR: 1,\"10.20.30.40\"";
const IPV4: [u8; 4] = [10, 20, 30, 40];
fn context() -> G8lS557PdpContext {
G8lS557PdpContext::define(1, G8lS557PdpType::Ip, "internet").unwrap()
}
fn ipcp_ack_info(identifier: u8, address: [u8; 4]) -> Vec<u8> {
let mut info = vec![2, identifier, 0x00, 0x0A, 3, 6];
info.extend_from_slice(&address);
info
}
fn ipcp_ack_wire(identifier: u8, address: [u8; 4], accm: u32) -> Vec<u8> {
encode_ppp_frame(
S557_PROTOCOL_IPCP,
&ipcp_ack_info(identifier, address),
accm,
)
.unwrap()
}
fn bring_up(
state: &mut G8lS557PacketDataState,
identifier: u8,
) -> Result<G8lS557PacketDataOutcome, G8lS557PacketDataError> {
service_s557_model_packet_data_bring_up(
state,
context(),
&ACTIVATE,
CGPADDR,
&ipcp_ack_wire(identifier, IPV4, S557_PPP_DEFAULT_ACCM),
S557_PPP_DEFAULT_ACCM,
)
}
#[test]
fn sequence_scope_and_nonpromotion_are_exact() {
assert_eq!(S557_SEQUENCE, 557);
assert_eq!(S557_EXPECTED_PREDECESSOR, 556);
assert_eq!(S557_R1_STAGE, 3);
assert_eq!(S557_R1_RANGE_FIRST, 536);
assert_eq!(S557_R1_RANGE_LAST, 568);
assert_eq!(S557_SUPPORTED_PROFILE_RUNTIME_OBSERVATIONS, 0);
assert_eq!(S557_PHYSICAL_OBSERVATIONS, 0);
assert_eq!(S557_PHYSICAL_OR_DEVICE_OPERATIONS, 0);
assert_eq!(S557_SD_WRITES, 0);
assert_eq!(S557_UART_OPENS, 0);
assert_eq!(S557_POWER_TRANSITIONS, 0);
assert_eq!(S557_NEW_IMMUTABLE_RAW_CAPTURES, 0);
assert!(S557_S540_PHYSICAL_VERDICT_RETAINED_RED);
assert!(S557_S543_PHYSICAL_VERDICT_RETAINED_RED);
assert!(!S557_AUTOMATIC_PROMOTION);
assert!(!S557_BOOT_TO_UI_PHYSICALLY_OBSERVED);
assert!(!S557_HARDWARE_PRESENT);
assert!(!S557_R1_ACCEPTANCE_COMPLETE);
assert!(!RUNBOOK_EXECUTED_IN_S557);
assert_eq!(S557_FCS_POLY, 0x8408);
assert_eq!(S557_FCS_INIT, 0xFFFF);
assert_eq!(S557_FCS_GOOD, 0xF0B8);
assert_eq!(S557_PPP_MAX_INFO, 1500);
assert_eq!(S557_PPP_MAX_UNSTUFFED_FRAME, 1506);
}
#[test]
fn module_is_registered_in_kernel_and_simulation() {
let module = "g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s557_r1_packet_data_pdp_context_ppp_frame_model";
let kernel = regex_lite_contains(MAIN, &format!("mod {module};"));
let simulation = regex_lite_contains(SIMULATION_LIB, &format!("pub mod {module};"));
assert!(kernel, "kernel main.rs must register the S557 module");
assert!(
simulation,
"simulation lib.rs must register the S557 module"
);
}
fn regex_lite_contains(haystack: &str, needle: &str) -> bool {
haystack.lines().any(|line| line.trim() == needle)
}
#[test]
fn source_has_no_device_execution_or_uart_emission_surface() {
for forbidden in [
"unsafe",
"asm!",
"write_volatile",
"crate::uart",
"crate::arch",
"#[no_mangle]",
"spin::",
"std::",
"kprintln!",
] {
assert!(!SOURCE.contains(forbidden), "forbidden token: {forbidden}");
}
assert!(SOURCE.contains("performs no device operation"));
assert!(SOURCE.contains("does not rerun S540 or S543"));
assert!(SOURCE.contains("S557_SUPPORTED_PROFILE_RUNTIME_OBSERVATIONS: usize = 0"));
assert!(SOURCE.contains("S557_PHYSICAL_OBSERVATIONS: usize = 0"));
assert!(SOURCE.contains("S557_HARDWARE_PRESENT: bool = false"));
assert!(SOURCE.contains("S557_R1_ACCEPTANCE_COMPLETE: bool = false"));
assert!(SOURCE.contains("RUNBOOK_EXECUTED_IN_S557: bool = false"));
}
#[test]
fn diagnostic_codes_are_nonzero_and_unique() {
use G8lS557PacketDataError as E;
let errors = [
E::CidOutOfRange,
E::ApnEmpty,
E::ApnTooLong,
E::ApnInvalidCharacter,
E::ApnInvalidLabel,
E::CgdcontMalformed,
E::CgactMalformed,
E::ActivationTransitionInvalid,
E::ActivationNotActive,
E::CgpaddrMalformed,
E::CgpaddrCidMismatch,
E::AddressOctetOutOfRange,
E::AddressGroupCount,
E::PppInfoOversize,
E::PppFrameTooShort,
E::PppMissingFlag,
E::PppBadEscape,
E::PppUnescapedControl,
E::PppAddressControlMismatch,
E::PppProtocolMalformed,
E::PppBadFcs,
E::CpProtocolUnsupported,
E::CpPacketTooShort,
E::CpLengthMismatch,
E::CpUnknownCode,
E::CpOptionLengthInvalid,
E::IpcpNotConfigureAck,
E::IpcpAddressMissing,
E::IpcpAddressMismatch,
E::PublishedStateDrift,
];
let codes: BTreeSet<u64> = errors.iter().map(|e| e.diagnostic_code()).collect();
assert_eq!(codes.len(), errors.len());
assert!(!codes.contains(&0));
assert_eq!(E::PublishedStateDrift.diagnostic_code(), 30);
}
#[test]
fn exact_replay_retains_the_same_receipt() {
let mut state = G8lS557PacketDataState::new();
let G8lS557PacketDataOutcome::Published(receipt) = bring_up(&mut state, 0x11).unwrap() else {
panic!("first S557 publication missing")
};
assert_eq!(state.receipt(), Some(receipt));
assert_eq!(
bring_up(&mut state, 0x11),
Ok(G8lS557PacketDataOutcome::Retained(receipt))
);
assert_eq!(state.receipt(), Some(receipt));
}
#[test]
fn divergent_input_after_publication_fails_closed() {
let mut state = G8lS557PacketDataState::new();
bring_up(&mut state, 0x11).unwrap();
assert_eq!(
bring_up(&mut state, 0x12),
Err(G8lS557PacketDataError::PublishedStateDrift)
);
let other = G8lS557PdpContext::define(1, G8lS557PdpType::Ip, "internet2").unwrap();
assert_eq!(
service_s557_model_packet_data_bring_up(
&mut state,
other,
&ACTIVATE,
CGPADDR,
&ipcp_ack_wire(0x11, IPV4, S557_PPP_DEFAULT_ACCM),
S557_PPP_DEFAULT_ACCM,
),
Err(G8lS557PacketDataError::PublishedStateDrift)
);
let receipt = state.receipt().unwrap();
assert_eq!(receipt.ipcp_identifier, 0x11);
assert_eq!(receipt.apn_len, 8);
}
#[test]
fn cgdcont_context_definition_validates_cid_type_and_apn() {
let ctx = context();
assert_eq!(ctx.encode_cgdcont(), "AT+CGDCONT=1,\"IP\",\"internet\"");
assert_eq!(ctx.encode_cgact(true), "AT+CGACT=1,1");
assert_eq!(ctx.encode_cgact(false), "AT+CGACT=0,1");
assert_eq!(ctx.apn.len(), 8);
assert_eq!(ctx.apn.label_count(), 1);
assert!(!ctx.apn.is_empty());
let dual =
G8lS557PdpContext::define(8, G8lS557PdpType::Ipv4v6, "ims.mnc001.mcc286.gprs").unwrap();
assert_eq!(
dual.encode_cgdcont(),
"AT+CGDCONT=8,\"IPV4V6\",\"ims.mnc001.mcc286.gprs\""
);
assert_eq!(dual.apn.label_count(), 4);
use G8lS557PacketDataError as E;
assert_eq!(
G8lS557PdpContext::define(0, G8lS557PdpType::Ip, "internet"),
Err(E::CidOutOfRange)
);
assert_eq!(
G8lS557PdpContext::define(9, G8lS557PdpType::Ip, "internet"),
Err(E::CidOutOfRange)
);
assert_eq!(
G8lS557PdpContext::define(1, G8lS557PdpType::Ip, ""),
Err(E::ApnEmpty)
);
assert_eq!(
G8lS557Apn::parse(&"a".repeat(63)).map(|apn| apn.len()),
Ok(63)
);
assert_eq!(G8lS557Apn::parse(&"a".repeat(64)), Err(E::ApnTooLong));
assert_eq!(G8lS557Apn::parse("inter net"), Err(E::ApnInvalidCharacter));
assert_eq!(G8lS557Apn::parse("inter_net"), Err(E::ApnInvalidCharacter));
assert_eq!(G8lS557Apn::parse("internet."), Err(E::ApnInvalidLabel));
assert_eq!(G8lS557Apn::parse("a..b"), Err(E::ApnInvalidLabel));
assert_eq!(G8lS557Apn::parse("-apn"), Err(E::ApnInvalidLabel));
assert_eq!(G8lS557Apn::parse("apn-"), Err(E::ApnInvalidLabel));
assert_ne!(
G8lS557Apn::parse("internet").unwrap().fnv1a(),
G8lS557Apn::parse("internet2").unwrap().fnv1a()
);
assert_eq!(
G8lS557Apn::parse("internet").unwrap().fnv1a(),
G8lS557Apn::parse("internet").unwrap().fnv1a()
);
}
#[test]
fn cgdcont_response_line_round_trips_and_rejects_malformed() {
let parsed = parse_cgdcont_line("+CGDCONT: 1,\"IP\",\"internet\",\"0.0.0.0\",0,0").unwrap();
assert_eq!(parsed, context());
let dual = parse_cgdcont_line("+CGDCONT: 3,\"IPV4V6\",\"ims\"").unwrap();
assert_eq!(dual.cid, 3);
assert_eq!(dual.pdp_type, G8lS557PdpType::Ipv4v6);
use G8lS557PacketDataError as E;
assert_eq!(parse_cgdcont_line("+CGACT: 1,1"), Err(E::CgdcontMalformed));
assert_eq!(
parse_cgdcont_line("+CGDCONT: x,\"IP\",\"internet\""),
Err(E::CgdcontMalformed)
);
assert_eq!(
parse_cgdcont_line("+CGDCONT: 1,IP,\"internet\""),
Err(E::CgdcontMalformed)
);
assert_eq!(
parse_cgdcont_line("+CGDCONT: 1,\"PPP\",\"internet\""),
Err(E::CgdcontMalformed)
);
assert_eq!(
parse_cgdcont_line("+CGDCONT: 1,\"IP\""),
Err(E::CgdcontMalformed)
);
assert_eq!(
parse_cgdcont_line("+CGDCONT: 1,\"IP\",\"internet"),
Err(E::CgdcontMalformed)
);
assert_eq!(
parse_cgdcont_line("+CGDCONT: 12,\"IP\",\"internet\""),
Err(E::CidOutOfRange)
);
assert_eq!(
parse_cgdcont_line("+CGDCONT: 1,\"IP\",\"\""),
Err(E::ApnEmpty)
);
}
#[test]
fn cgact_activation_state_machine_is_table_driven() {
use G8lS557ActivationEvent as E;
use G8lS557ActivationState as S;
assert_eq!(S::default(), S::Defined);
let mut state = S::Defined;
for (event, expected) in [
(E::ActivateRequested, S::Activating),
(E::ActivateError, S::Defined),
(E::ActivateRequested, S::Activating),
(E::ActivateOk, S::Active),
(E::DeactivateRequested, S::Deactivating),
(E::DeactivateOk, S::Defined),
(E::ActivateRequested, S::Activating),
(E::ActivateOk, S::Active),
(E::NetworkDetach, S::Defined),
] {
state = activation_transition(state, event).unwrap();
assert_eq!(state, expected);
}
for (from, event) in [
(S::Defined, E::ActivateOk),
(S::Defined, E::DeactivateRequested),
(S::Defined, E::DeactivateOk),
(S::Activating, E::ActivateRequested),
(S::Activating, E::DeactivateOk),
(S::Active, E::ActivateRequested),
(S::Active, E::ActivateOk),
(S::Active, E::DeactivateOk),
(S::Deactivating, E::ActivateRequested),
(S::Deactivating, E::DeactivateRequested),
] {
assert_eq!(
activation_transition(from, event),
Err(G8lS557PacketDataError::ActivationTransitionInvalid),
"{from:?} + {event:?}"
);
}
assert_eq!(parse_cgact_line("+CGACT: 1,1"), Ok((1, true)));
assert_eq!(parse_cgact_line("+CGACT: 8,0"), Ok((8, false)));
assert_eq!(
parse_cgact_line("+CGACT: 0,1"),
Err(G8lS557PacketDataError::CidOutOfRange)
);
assert_eq!(
parse_cgact_line("+CGACT: 1,2"),
Err(G8lS557PacketDataError::CgactMalformed)
);
assert_eq!(
parse_cgact_line("+CGACT: 1"),
Err(G8lS557PacketDataError::CgactMalformed)
);
assert_eq!(
parse_cgact_line("CGACT: 1,1"),
Err(G8lS557PacketDataError::CgactMalformed)
);
}
#[test]
fn cgpaddr_parses_ipv4_and_dotted_ipv6_and_rejects_bad_octets() {
use G8lS557PacketDataError as E;
assert_eq!(
parse_cgpaddr_line(CGPADDR),
Ok((1, G8lS557PdpAddress::V4(IPV4), None))
);
let dual =
parse_cgpaddr_line("+CGPADDR: 2,\"100.64.0.255\",\"32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1\"")
.unwrap();
assert_eq!(dual.0, 2);
assert_eq!(dual.1, G8lS557PdpAddress::V4([100, 64, 0, 255]));
assert_eq!(
dual.2,
Some(G8lS557PdpAddress::V6([
32, 1, 13, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
]))
);
assert_eq!(
parse_cgpaddr_line("+CGPADDR: 1,\"10.20.30.256\""),
Err(E::AddressOctetOutOfRange)
);
assert_eq!(
parse_cgpaddr_line("+CGPADDR: 1,\"10.20.30\""),
Err(E::AddressGroupCount)
);
assert_eq!(
parse_cgpaddr_line("+CGPADDR: 1,\"10.20.30.40.50\""),
Err(E::AddressGroupCount)
);
assert_eq!(
parse_cgpaddr_line("+CGPADDR: 1,\"1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1\""),
Err(E::AddressGroupCount)
);
assert_eq!(
parse_cgpaddr_line("+CGPADDR: 1,\"10.20..40\""),
Err(E::AddressOctetOutOfRange)
);
assert_eq!(
parse_cgpaddr_line("+CGPADDR: 1,\"10.20.30.4a\""),
Err(E::AddressOctetOutOfRange)
);
assert_eq!(
parse_cgpaddr_line("+CGPADDR: 1,\"0010.20.30.40\""),
Err(E::AddressOctetOutOfRange)
);
assert_eq!(
parse_cgpaddr_line("+CGPADDR: 1,10.20.30.40"),
Err(E::CgpaddrMalformed)
);
assert_eq!(
parse_cgpaddr_line("+CGPADDR: 9,\"10.20.30.40\""),
Err(E::CidOutOfRange)
);
assert_eq!(parse_cgpaddr_line("+CGPADDR: 1"), Err(E::CgpaddrMalformed));
assert_eq!(
parse_cgpaddr_line("+CGPADDR: 1,\"10.20.30.40\",10.0.0.1"),
Err(E::CgpaddrMalformed)
);
}
#[test]
fn fcs16_pins_known_vectors() {
assert_eq!(ppp_fcs16(S557_FCS_INIT, b"123456789"), 0x6F91);
assert_eq!(ppp_fcs16_trailer(b"123456789"), [0x6E, 0x90]);
assert_eq!(ppp_fcs16(S557_FCS_INIT, b""), 0xFFFF);
assert_eq!(ppp_fcs16_trailer(b""), [0x00, 0x00]);
assert_eq!(ppp_fcs16(S557_FCS_INIT, &[0x00, 0x00]), S557_FCS_GOOD);
let lcp = [0xFF, 0x03, 0xC0, 0x21, 0x01, 0x01, 0x00, 0x04];
assert_eq!(ppp_fcs16(S557_FCS_INIT, &lcp), 0x4A2E);
assert_eq!(ppp_fcs16_trailer(&lcp), [0xD1, 0xB5]);
let ipcp = [
0xFF, 0x03, 0x80, 0x21, 0x01, 0x01, 0x00, 0x0A, 0x03, 0x06, 0x0A, 0x14, 0x1E, 0x28,
];
assert_eq!(ppp_fcs16(S557_FCS_INIT, &ipcp), 0x4F7D);
assert_eq!(ppp_fcs16_trailer(&ipcp), [0x82, 0xB0]);
for data in [&b"123456789"[..], &lcp[..], &ipcp[..]] {
let mut with_fcs = data.to_vec();
with_fcs.extend_from_slice(&ppp_fcs16_trailer(data));
assert_eq!(ppp_fcs16(S557_FCS_INIT, &with_fcs), S557_FCS_GOOD);
with_fcs[0] ^= 0x01;
assert_ne!(ppp_fcs16(S557_FCS_INIT, &with_fcs), S557_FCS_GOOD);
}
}
#[test]
fn ppp_frame_encode_stuffs_flags_escapes_and_accm_control_bytes() {
let info = [0x01, 0x01, 0x00, 0x04];
let default_accm = encode_ppp_frame(S557_PROTOCOL_LCP, &info, S557_PPP_DEFAULT_ACCM).unwrap();
assert_eq!(
default_accm,
[
0x7E, 0xFF, 0x7D, 0x23, 0xC0, 0x21, 0x7D, 0x21, 0x7D, 0x21, 0x7D, 0x20, 0x7D, 0x24,
0xD1, 0xB5, 0x7E
]
);
let zero_accm = encode_ppp_frame(S557_PROTOCOL_LCP, &info, 0).unwrap();
assert_eq!(
zero_accm,
[0x7E, 0xFF, 0x03, 0xC0, 0x21, 0x01, 0x01, 0x00, 0x04, 0xD1, 0xB5, 0x7E]
);
let flags = encode_ppp_frame(S557_PROTOCOL_IPV4, &[0x7E, 0x7D, 0x41], 0).unwrap();
assert_eq!(
&flags[1..9],
&[0xFF, 0x03, 0x00, 0x21, 0x7D, 0x5E, 0x7D, 0x5D]
);
assert_eq!(flags[9], 0x41);
assert_eq!(flags[0], S557_PPP_FLAG);
assert_eq!(*flags.last().unwrap(), S557_PPP_FLAG);
let only_xon_xoff =
encode_ppp_frame(S557_PROTOCOL_IPV4, &[0x11, 0x13, 0x12], 0x000A_0000).unwrap();
assert_eq!(&only_xon_xoff[5..10], &[0x7D, 0x31, 0x7D, 0x33, 0x12]);
assert_eq!(
encode_ppp_frame(0xC020, &info, 0),
Err(G8lS557PacketDataError::PppProtocolMalformed)
);
assert_eq!(
encode_ppp_frame(0xC121, &info, 0),
Err(G8lS557PacketDataError::PppProtocolMalformed)
);
}
#[test]
fn ppp_frame_decode_round_trips_and_fails_closed_on_bad_fcs_and_escapes() {
use G8lS557PacketDataError as E;
let info = [0x01, 0x01, 0x00, 0x04];
for accm in [S557_PPP_DEFAULT_ACCM, 0, 0x000A_0000] {
let wire = encode_ppp_frame(S557_PROTOCOL_LCP, &info, accm).unwrap();
let frame = decode_ppp_frame(&wire, accm).unwrap();
assert_eq!(frame.protocol, S557_PROTOCOL_LCP);
assert_eq!(frame.info, info);
assert_eq!(frame.fcs_trailer, [0xD1, 0xB5]);
}
let good = [
0x7E, 0xFF, 0x03, 0xC0, 0x21, 0x01, 0x01, 0x00, 0x04, 0xD1, 0xB5, 0x7E,
];
assert!(decode_ppp_frame(&good, 0).is_ok());
let mut bad_fcs = good;
bad_fcs[10] = 0xB4;
assert_eq!(decode_ppp_frame(&bad_fcs, 0), Err(E::PppBadFcs));
let mut flipped_payload = good;
flipped_payload[5] = 0x02;
assert_eq!(decode_ppp_frame(&flipped_payload, 0), Err(E::PppBadFcs));
assert_eq!(decode_ppp_frame(&good[1..], 0), Err(E::PppMissingFlag));
assert_eq!(decode_ppp_frame(&good[..11], 0), Err(E::PppMissingFlag));
assert_eq!(decode_ppp_frame(&[0x7E], 0), Err(E::PppMissingFlag));
let mut inner_flag = good.to_vec();
inner_flag.insert(5, 0x7E);
assert_eq!(decode_ppp_frame(&inner_flag, 0), Err(E::PppMissingFlag));
assert_eq!(
decode_ppp_frame(&[0x7E, 0xFF, 0x03, 0x7D, 0x7E], 0),
Err(E::PppBadEscape)
);
assert_eq!(
decode_ppp_frame(&[0x7E, 0xFF, 0x03, 0x7D, 0x7E], 0),
Err(E::PppBadEscape)
);
let mut trailing_escape = good.to_vec();
trailing_escape.insert(11, 0x7D);
assert_eq!(decode_ppp_frame(&trailing_escape, 0), Err(E::PppBadEscape));
assert_eq!(
decode_ppp_frame(&good, S557_PPP_DEFAULT_ACCM),
Err(E::PppUnescapedControl)
);
let mut wrong_address = encode_ppp_frame(S557_PROTOCOL_LCP, &info, 0).unwrap();
wrong_address[1] = 0x00;
let trailer = ppp_fcs16_trailer(&wrong_address[1..9]);
wrong_address[9] = trailer[0];
wrong_address[10] = trailer[1];
assert_eq!(
decode_ppp_frame(&wrong_address, 0),
Err(E::PppAddressControlMismatch)
);
let mut even_protocol = [0xFF, 0x03, 0xC0, 0x20, 0x01, 0x01, 0x00, 0x04].to_vec();
even_protocol.extend_from_slice(&ppp_fcs16_trailer(&even_protocol.clone()));
let mut wire = vec![0x7E];
wire.extend_from_slice(&even_protocol);
wire.push(0x7E);
assert_eq!(decode_ppp_frame(&wire, 0), Err(E::PppProtocolMalformed));
}
#[test]
fn ppp_frame_rejects_oversize_info_and_short_frames() {
use G8lS557PacketDataError as E;
let max = vec![0x55u8; S557_PPP_MAX_INFO];
let wire = encode_ppp_frame(S557_PROTOCOL_IPV4, &max, 0).unwrap();
assert_eq!(
wire.len(),
2 + S557_PPP_HEADER_LEN + S557_PPP_MAX_INFO + S557_PPP_FCS_LEN
);
let frame = decode_ppp_frame(&wire, 0).unwrap();
assert_eq!(frame.info.len(), S557_PPP_MAX_INFO);
assert_eq!(frame.fcs_trailer, [0x00, 0x66]);
let stuffed = encode_ppp_frame(S557_PROTOCOL_IPV4, &max, S557_PPP_DEFAULT_ACCM).unwrap();
assert_eq!(stuffed.len(), wire.len() + 3);
assert_eq!(
decode_ppp_frame(&stuffed, S557_PPP_DEFAULT_ACCM).unwrap(),
frame
);
let over = vec![0x55u8; S557_PPP_MAX_INFO + 1];
assert_eq!(
encode_ppp_frame(S557_PROTOCOL_IPV4, &over, S557_PPP_DEFAULT_ACCM),
Err(E::PppInfoOversize)
);
let mut oversized = vec![0xFF, 0x03, 0x00, 0x21];
oversized.extend_from_slice(&over);
oversized.extend_from_slice(&ppp_fcs16_trailer(&oversized.clone()));
let mut oversized_wire = vec![0x7E];
oversized_wire.extend_from_slice(&oversized);
oversized_wire.push(0x7E);
assert_eq!(
decode_ppp_frame(&oversized_wire, 0),
Err(E::PppInfoOversize)
);
let two = [0x7E, 0x00, 0x00, 0x7E];
assert_eq!(decode_ppp_frame(&two, 0), Err(E::PppFrameTooShort));
let mut five = vec![0x7E, 0xFF, 0x03, 0xC0];
five.extend_from_slice(&ppp_fcs16_trailer(&[0xFF, 0x03, 0xC0]));
five.push(0x7E);
assert_eq!(decode_ppp_frame(&five, 0), Err(E::PppFrameTooShort));
let empty_info = encode_ppp_frame(S557_PROTOCOL_IPV4, &[], 0).unwrap();
assert_eq!(decode_ppp_frame(&empty_info, 0).unwrap().info.len(), 0);
}
#[test]
fn lcp_options_parse_mru_and_magic_as_tagged_structures() {
use G8lS557PacketDataError as E;
let info = [
0x01, 0x01, 0x00, 0x0E, 0x01, 0x04, 0x05, 0xDC, 0x05, 0x06, 0xDE, 0xAD, 0xBE, 0xEF,
];
let packet = parse_cp_packet(S557_PROTOCOL_LCP, &info).unwrap();
assert_eq!(packet.protocol, S557_PROTOCOL_LCP);
assert_eq!(packet.code, G8lS557CpCode::ConfigureRequest);
assert_eq!(packet.identifier, 1);
assert_eq!(
packet.options,
vec![
G8lS557CpOption::LcpMru(1500),
G8lS557CpOption::LcpMagic(0xDEAD_BEEF)
]
);
let wire = encode_ppp_frame(S557_PROTOCOL_LCP, &info, S557_PPP_DEFAULT_ACCM).unwrap();
let frame = decode_ppp_frame(&wire, S557_PPP_DEFAULT_ACCM).unwrap();
assert_eq!(frame.fcs_trailer, [0x8B, 0x30]);
assert_eq!(
parse_cp_packet(frame.protocol, &frame.info).unwrap(),
packet
);
let with_unknown = [
0x02, 0x07, 0x00, 0x09, 0x01, 0x04, 0x05, 0xDC, 0x08, 0x02, 0x03,
];
assert_eq!(
parse_cp_packet(S557_PROTOCOL_LCP, &with_unknown[..10]),
Err(E::CpLengthMismatch)
);
let fixed = [0x02, 0x07, 0x00, 0x0A, 0x01, 0x04, 0x05, 0xDC, 0x08, 0x02];
let packet = parse_cp_packet(S557_PROTOCOL_LCP, &fixed).unwrap();
assert_eq!(packet.code, G8lS557CpCode::ConfigureAck);
assert_eq!(
packet.options,
vec![
G8lS557CpOption::LcpMru(1500),
G8lS557CpOption::Unrecognized { kind: 8, length: 2 }
]
);
assert_eq!(
parse_cp_packet(S557_PROTOCOL_LCP, &[0x09, 0x01, 0x00, 0x04])
.unwrap()
.code,
G8lS557CpCode::EchoRequest
);
assert_eq!(
parse_cp_packet(S557_PROTOCOL_LCP, &[0x0B, 0x01, 0x00, 0x04])
.unwrap()
.code,
G8lS557CpCode::DiscardRequest
);
assert_eq!(
parse_cp_packet(S557_PROTOCOL_LCP, &[0x0C, 0x01, 0x00, 0x04]),
Err(E::CpUnknownCode)
);
assert_eq!(
parse_cp_packet(S557_PROTOCOL_LCP, &[0x01, 0x01, 0x00]),
Err(E::CpPacketTooShort)
);
assert_eq!(
parse_cp_packet(S557_PROTOCOL_LCP, &[0x01, 0x01, 0x00, 0x05]),
Err(E::CpLengthMismatch)
);
assert_eq!(
parse_cp_packet(S557_PROTOCOL_LCP, &[0x01, 0x01, 0x00, 0x05, 0x01]),
Err(E::CpOptionLengthInvalid)
);
assert_eq!(
parse_cp_packet(S557_PROTOCOL_LCP, &[0x01, 0x01, 0x00, 0x06, 0x01, 0x01]),
Err(E::CpOptionLengthInvalid)
);
assert_eq!(
parse_cp_packet(S557_PROTOCOL_LCP, &[0x01, 0x01, 0x00, 0x06, 0x01, 0x09]),
Err(E::CpOptionLengthInvalid)
);
assert_eq!(
parse_cp_packet(
S557_PROTOCOL_LCP,
&[0x01, 0x01, 0x00, 0x07, 0x01, 0x03, 0x05]
),
Err(E::CpOptionLengthInvalid)
);
assert_eq!(
parse_cp_packet(
S557_PROTOCOL_LCP,
&[0x01, 0x01, 0x00, 0x09, 0x05, 0x05, 0x00, 0x00, 0x00]
),
Err(E::CpOptionLengthInvalid)
);
assert_eq!(
parse_cp_packet(S557_PROTOCOL_IPV4, &[0x01, 0x01, 0x00, 0x04]),
Err(E::CpProtocolUnsupported)
);
}
#[test]
fn ipcp_ip_address_option_parses_and_length_errors_fail_closed() {
use G8lS557PacketDataError as E;
let packet = parse_cp_packet(S557_PROTOCOL_IPCP, &ipcp_ack_info(0x21, IPV4)).unwrap();
assert_eq!(packet.code, G8lS557CpCode::ConfigureAck);
assert_eq!(packet.identifier, 0x21);
assert_eq!(packet.options, vec![G8lS557CpOption::IpcpIpAddress(IPV4)]);
let mru_in_ipcp = parse_cp_packet(
S557_PROTOCOL_IPCP,
&[0x01, 0x01, 0x00, 0x08, 0x01, 0x04, 0x05, 0xDC],
)
.unwrap();
assert_eq!(
mru_in_ipcp.options,
vec![G8lS557CpOption::Unrecognized { kind: 1, length: 4 }]
);
assert_eq!(
parse_cp_packet(
S557_PROTOCOL_IPCP,
&[0x02, 0x01, 0x00, 0x09, 0x03, 0x05, 0x0A, 0x14, 0x1E]
),
Err(E::CpOptionLengthInvalid)
);
assert_eq!(
parse_cp_packet(
S557_PROTOCOL_IPCP,
&[0x02, 0x01, 0x00, 0x0B, 0x03, 0x07, 0x0A, 0x14, 0x1E, 0x28, 0x00]
),
Err(E::CpOptionLengthInvalid)
);
let wire = ipcp_ack_wire(0x01, IPV4, 0);
assert_eq!(
wire,
[
0x7E, 0xFF, 0x03, 0x80, 0x21, 0x02, 0x01, 0x00, 0x0A, 0x03, 0x06, 0x0A, 0x14, 0x1E,
0x28, 0xEB, 0xC4, 0x7E
]
);
let frame = decode_ppp_frame(&wire, 0).unwrap();
assert_eq!(frame.protocol, S557_PROTOCOL_IPCP);
assert_eq!(
ppp_fcs16(
S557_FCS_INIT,
&[
0xFF,
0x03,
0x80,
0x21,
0x02,
0x01,
0x00,
0x0A,
0x03,
0x06,
0x0A,
0x14,
0x1E,
0x28,
frame.fcs_trailer[0],
frame.fcs_trailer[1]
]
),
S557_FCS_GOOD
);
}
#[test]
fn bring_up_happy_path_publishes_receipt() {
let mut state = G8lS557PacketDataState::default();
assert_eq!(state.receipt(), None);
let G8lS557PacketDataOutcome::Published(receipt) = bring_up(&mut state, 0x11).unwrap() else {
panic!("first S557 publication missing")
};
assert_eq!(receipt.sequence, S557_SEQUENCE);
assert_eq!(receipt.predecessor_sequence, S557_EXPECTED_PREDECESSOR);
assert_eq!(receipt.r1_stage, 3);
assert_eq!(receipt.cid, 1);
assert_eq!(receipt.pdp_type, G8lS557PdpType::Ip);
assert_eq!(receipt.apn_len, 8);
assert_eq!(receipt.apn_label_count, 1);
assert_eq!(receipt.apn_fnv1a, context().apn.fnv1a());
assert_eq!(receipt.activation_state, G8lS557ActivationState::Active);
assert_eq!(receipt.activation_events, 2);
assert_eq!(receipt.pdp_address, G8lS557PdpAddress::V4(IPV4));
assert!(!receipt.has_ipv6_address);
assert_eq!(receipt.ipcp_identifier, 0x11);
assert_eq!(receipt.ipcp_ip_address, IPV4);
assert_eq!(receipt.frame_info_len, 10);
assert_eq!(
receipt.frame_fcs_trailer,
ppp_fcs16_trailer(&{
let mut body = vec![0xFF, 0x03, 0x80, 0x21];
body.extend_from_slice(&ipcp_ack_info(0x11, IPV4));
body
})
);
assert!(!receipt.hardware_present);
assert!(receipt.s540_physical_verdict_retained_red);
assert!(receipt.s543_physical_verdict_retained_red);
assert!(!receipt.automatic_promotion);
assert_eq!(receipt.supported_profile_runtime_observations, 0);
assert_eq!(receipt.physical_observations, 0);
assert!(!receipt.runbook_executed);
let dual = G8lS557PdpContext::define(2, G8lS557PdpType::Ipv4v6, "ims").unwrap();
let mut dual_state = G8lS557PacketDataState::new();
let G8lS557PacketDataOutcome::Published(dual_receipt) =
service_s557_model_packet_data_bring_up(
&mut dual_state,
dual,
&ACTIVATE,
"+CGPADDR: 2,\"10.0.0.2\",\"32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1\"",
&ipcp_ack_wire(0x22, [10, 0, 0, 2], 0),
0,
)
.unwrap()
else {
panic!("dual-stack publication missing")
};
assert!(dual_receipt.has_ipv6_address);
assert_eq!(dual_receipt.pdp_type, G8lS557PdpType::Ipv4v6);
assert_eq!(dual_receipt.cid, 2);
}
#[test]
fn bring_up_rejects_inactive_context_cid_mismatch_and_address_mismatch() {
use G8lS557PacketDataError as E;
let wire = ipcp_ack_wire(0x11, IPV4, S557_PPP_DEFAULT_ACCM);
let accm = S557_PPP_DEFAULT_ACCM;
let mut state = G8lS557PacketDataState::new();
let run = |state: &mut G8lS557PacketDataState,
ctx: G8lS557PdpContext,
events: &[G8lS557ActivationEvent],
line: &str,
wire: &[u8]| {
service_s557_model_packet_data_bring_up(state, ctx, events, line, wire, accm)
};
assert_eq!(
run(&mut state, context(), &ACTIVATE[..1], CGPADDR, &wire),
Err(E::ActivationNotActive)
);
assert_eq!(
run(&mut state, context(), &[], CGPADDR, &wire),
Err(E::ActivationNotActive)
);
assert_eq!(
run(
&mut state,
context(),
&[G8lS557ActivationEvent::ActivateOk],
CGPADDR,
&wire
),
Err(E::ActivationTransitionInvalid)
);
assert_eq!(
run(
&mut state,
context(),
&ACTIVATE,
"+CGPADDR: 2,\"10.20.30.40\"",
&wire
),
Err(E::CgpaddrCidMismatch)
);
assert_eq!(
run(
&mut state,
context(),
&ACTIVATE,
"+CGPADDR: 1,\"10.20.30.40\",\"1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1\"",
&wire
),
Err(E::CgpaddrMalformed)
);
assert_eq!(
run(
&mut state,
context(),
&ACTIVATE,
"+CGPADDR: 1,\"1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1\"",
&wire
),
Err(E::AddressGroupCount)
);
assert_eq!(
run(
&mut state,
context(),
&ACTIVATE,
CGPADDR,
&ipcp_ack_wire(0x11, [10, 20, 30, 41], accm)
),
Err(E::IpcpAddressMismatch)
);
let nak = encode_ppp_frame(
S557_PROTOCOL_IPCP,
&[3, 0x11, 0x00, 0x0A, 3, 6, 10, 20, 30, 40],
accm,
)
.unwrap();
assert_eq!(
run(&mut state, context(), &ACTIVATE, CGPADDR, &nak),
Err(E::IpcpNotConfigureAck)
);
let no_address = encode_ppp_frame(S557_PROTOCOL_IPCP, &[2, 0x11, 0x00, 0x04], accm).unwrap();
assert_eq!(
run(&mut state, context(), &ACTIVATE, CGPADDR, &no_address),
Err(E::IpcpAddressMissing)
);
let lcp = encode_ppp_frame(S557_PROTOCOL_LCP, &[2, 0x11, 0x00, 0x04], accm).unwrap();
assert_eq!(
run(&mut state, context(), &ACTIVATE, CGPADDR, &lcp),
Err(E::CpProtocolUnsupported)
);
let mut bad_fcs = wire.clone();
let last = bad_fcs.len() - 2;
bad_fcs[last] ^= 0x01;
assert_eq!(
run(&mut state, context(), &ACTIVATE, CGPADDR, &bad_fcs),
Err(E::PppBadFcs)
);
let unescaped = ipcp_ack_wire(0x11, IPV4, 0);
assert_eq!(
run(&mut state, context(), &ACTIVATE, CGPADDR, &unescaped),
Err(E::PppUnescapedControl)
);
let mut bad_cid = context();
bad_cid.cid = 0;
assert_eq!(
run(&mut state, bad_cid, &ACTIVATE, CGPADDR, &wire),
Err(E::CidOutOfRange)
);
assert_eq!(state.receipt(), None);
}
snippet sha256: d53eb8b625ad…file sha256: d53eb8b625ad…
03 · Kapı kimlik kaydı
Operations sıra, kimlik ve başlık bağı
tam Operations kaydıL2484–L2542
website/src/lib/operations.ts::g8l-s557-r1-packet-data-pdp-context-ppp-frame-model
{
id: "g8l-s557-r1-packet-data-pdp-context-ppp-frame-model",
date: "2026-08-30",
sequence: 557,
status: "passed",
umbrella_status: "partial",
title: "S557 · R1 modem: paket veri PDP bağlamı ve PPP çerçeve modeli",
summary:
"S557 kaynak/host model kapısı PASS'tir: +CGDCONT PDP bağlam tanımı (cid 1–8, IP/IPV4V6, etiket bazlı APN doğrulaması), tablo güdümlü +CGACT aktivasyon durum makinesi, +CGPADDR adres ayrıştırması ve RFC 1662 PPP/HDLC çerçeve katmanı (0x7E bayrak, 0x7D^0x20 byte stuffing, ACCM, 0x8408/0xFFFF/0xF0B8 FCS-16) ile minimal LCP/IPCP seçenek ayrıştırması saf Rust modeli olarak eklendi. Bring-up servisi bağlamı tanımlar, aktivasyonu Active'e sürer, aynı cid için atanan IPv4 adresini IPCP Configure-Ack çerçevesindeki IP-Address seçeneğiyle eşleştirir; her geçersiz girdi fail-closed reddedilir, exact replay aynı receipt'i korur ve yayın sonrası sapma reddedilir. Focused 18/18 PASS'tir ve bilinen FCS vektörleri (\"123456789\" → 0x6F91 / 6E 90) sabitlenmiştir. S540 ve S543 fiziksel RED immutable kalır; hiçbir modem, UART, PPP karşı ucu veya board yoktur; physical observation=0, RUNBOOK_EXECUTED_IN_S557=NO, Boot-to-UI=false ve R1 acceptance=false'dur. S558 sesli arama durum makinesi modelidir.",
evidence: [
"S557, S556'dan ayrı kaynak modülü, 18-test focused binary, proof, status bloğu ve Operations kaydına sahiptir; kernel ve simulation crate'lerinde kayıtlıdır ancak hiçbir boot, IRQ, scheduler veya driver yoluna bağlanmamıştır.",
"Dar S557 source/host model status=PASS; R1 umbrella=PARTIAL ve S540/S543 physical gate status=RED olarak ayrı tutulur.",
"+CGDCONT modeli cid'i 1..=8 aralığında, PDP tipini IP veya IPV4V6 olarak ve APN'i 1..=63 bayt nokta ayrımlı etiketlerle (alfasayısal veya '-', boş etiket yok, başta/sonda '-' yok) doğrular; AT+CGDCONT=<cid>,\"<tip>\",\"<apn>\" kodlaması ve +CGDCONT: yanıt satırı ayrıştırması aynı doğrulanmış bağlamı verir.",
"+CGACT aktivasyon makinesi Defined/Activating/Active/Deactivating durumları ve ActivateRequested/ActivateOk/ActivateError/DeactivateRequested/DeactivateOk/NetworkDetach olayları üzerinde tablo güdümlüdür; listelenmeyen her çift ActivationTransitionInvalid ile fail-closed döner.",
"+CGPADDR ayrıştırması tırnaklı IPv4 (4 grup) ve 16 gruplu noktalı IPv6 adreslerini kabul eder; 1..=3 rakam dışı grup, 255 üstü oktet, 4 veya 16 dışı grup sayısı ve tırnaksız alan fail-closed reddedilir.",
"PPP/HDLC katmanı 0x7E bayrak, 0x7D kaçış ve 0x20 XOR kullanır; ACCM bit haritasına göre 0x20 altı kontrol baytları kaçışlanır; adres 0xFF, kontrol 0x03 ve çift-yüksek/tek-düşük protokol alanı zorunludur; bilgi alanı 1500 bayt, kaçışsız çerçeve 1506 bayt ile sınırlıdır.",
"FCS-16 polinom 0x8408, başlangıç 0xFFFF, iletimde ones-complement düşük bayt önce ve iyi kalıntı 0xF0B8 ile hesaplanır; bilinen vektörler sabitlenmiştir: \"123456789\" → 0x6F91 / 6E 90, boş → 0xFFFF / 00 00, FF 03 C0 21 01 01 00 04 → 0x4A2E / D1 B5, IPCP FF 03 80 21 01 01 00 0A 03 06 0A 14 1E 28 → 0x4F7D / 82 B0.",
"Çözücü eksik veya gömülü bayrak, 0x7D 0x7E abort dizisi, sondaki kaçış, kaçışsız ACCM kontrol baytı, kısa çerçeve, bozuk FCS, adres/kontrol uyuşmazlığı, bozuk protokol alanı ve aşırı boyut için ayrı fail-closed hatalar üretir.",
"LCP (0xC021) ve IPCP (0x8021) paketleri kod tablosu 1..=11, identifier ve exact uzunluk alanı ile ayrıştırılır; MRU (tip 1, uzunluk 4), Magic-Number (tip 5, uzunluk 6) ve IP-Address (tip 3, uzunluk 6) etiketli yapılar olarak, diğer seçenekler Unrecognized { kind, length } olarak tutulur; 2 altı, paket dışına taşan veya yanlış sabit boyutlu seçenek uzunlukları fail-closed reddedilir.",
"Bring-up servisi bağlamı tanımlar, aktivasyon olaylarını Active'e sürer, +CGPADDR satırındaki cid'i bağlamla eşleştirir, IPCP Configure-Ack çerçevesini verilen ACCM ile çözer ve IP-Address seçeneğinin atanan IPv4 adresine eşit olmasını ister; exact replay Retained ile aynı receipt'i döndürür, yayın sonrası her sapma PublishedStateDrift verir.",
"Hata enum'u 30 sıfırdan farklı ve benzersiz diagnostic code taşır; focused test bunu BTreeSet ile doğrular.",
"Focused target 1 grup / 18 passed / 0 failed / 0 ignored / 0 filtered verdi; test seti kontrat sabitlerini, modül kaydını, unsafe/asm!/write_volatile/crate::uart/crate::arch/spin:: yasağını, exact replay'i ve yayın sonrası sapmayı kapsar.",
"Implementation 27328 B / 201e68b46969133e9053478d5b4174b03db369f0309c00465714644b4ccc604c; focused test 31294 B / d53eb8b625ada8b0aafe8edc2b71ebc808455413c43128bd7bc132d8029ef5ee SHA-256'dır.",
"Proof 5160 B'dır.",
"S540 ve S543 immutable raw ve physical verdict'leri RED olarak byte-exact korunur; automatic promotion=false ve rerun=false'dur; S546 ayrı bekler.",
"S557 sırasında modem, UART open/capture, PPP karşı ucu, SD write/read-back/eject, power transition veya yeni immutable raw üretimi yapılmadı; modül hiçbir üretim çağrı noktasına bağlanmadı.",
"RUNBOOK_EXECUTED_IN_S557=NO; supported-profile runtime observations=0, physical observations=0, hardware present=false, Boot-to-UI physically observed=false ve R1 acceptance=false'dur.",
"S558 sesli arama durum makinesini (dial/ring/connect/hold/release) aynı kaynak/host sınırlarıyla modelleyecektir; modem, UART, SD, power veya fiziksel koşu yetkisi değildir.",
],
commands: [
"CARGO_INCREMENTAL=0 cargo test -p aselsan_microkernel_simulation --test g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s557_r1_packet_data_pdp_context_ppp_frame_model -- --test-threads=1",
],
terminalSessions: [
{
id: "s557-focused",
title: "S557 paket veri PDP/PPP model focused acceptance",
commandLines: [
"CARGO_INCREMENTAL=0 cargo test -p aselsan_microkernel_simulation --test g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s557_r1_packet_data_pdp_context_ppp_frame_model -- --test-threads=1",
],
outputLines: [
"test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s",
"S557 focused=1 group / 18 passed / 0 failed",
"hardware=none physical=0 runbook=NO",
],
exitCode: 0,
outputMode: "complete",
},
],
terminalSessionsNote:
"S557 kaynak/host model PASS'tir; modem, PPP karşı ucu veya fiziksel PASS değildir. S540 ve S543 RED raw ve kararları değişmez.",
limitations: [
"S557 yalnız kaynak/host modelidir; hiçbir donanım/panel/modem/board gözlemi yoktur ve modül hiçbir üretim boot, IRQ, scheduler veya driver yoluna bağlanmamıştır.",
"PPP/HDLC ve LCP/IPCP modeli gerçek bir modem veya PPP karşı ucuyla müzakere edilmemiştir; FCS ve çerçeve vektörleri yalnız host testinde sabitlenmiştir.",
"APN doğrulaması etiket sözdizimiyle sınırlıdır; operatör APN politikası, kimlik doğrulama (PAP/CHAP) ve DNS seçenekleri modellenmemiştir.",
"S540 ve S543 fiziksel RED immutable kalır; otomatik yükseltme yoktur ve S546 ayrı beklemektedir.",
"Boot-to-UI fiziksel olarak gözlenmedi; R1 acceptance false kalır.",
"S558 sesli arama durum makinesi modeli aynı kaynak/host sınırlarında kalacaktır; yeni modem/UART/SD/power koşusu ayrı kapı, açık operatör yetkisi ve yeni immutable raw ister.",
],
},snippet sha256: 34ddfb8febc3…file sha256: 9726dbf00f84…
Focused test komutu
CARGO_INCREMENTAL=0 cargo test -p aselsan_microkernel_simulation --test g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s557_r1_packet_data_pdp_context_ppp_frame_model -- --test-threads=1proof: docs/M8.1-RPi5-G8l-S557-R1-Packet-Data-PDP-Context-PPP-Frame-Model-Proof.md
Registry schema v5 · generator
website/scripts/generate-code-gates.mjs · Tam SHA-256: 3050638b71a684d8f8f947a8a6faa237a17fa8db5dc0db04fb207b668b462af9