feat(renaser): Fase 20 — Akasha Over Ether (grafo distribuido)
Tres mensajes y un EtherType propio bastan para extender el grafo de
objetos —direccionado por contenido, ya BLAKE3— a otras maquinas
renaser que escuchen en la misma red de capa-2. Sin TCP, sin IP,
sin DNS.
Crate nueva 'akasha/' (no_std compartido, gemela de 'formato',
excluida del workspace):
- MensajeAkasha enum con SolicitarObjeto(id), ProveedorObjeto(id,
payload), AnunciarRaiz(id).
- Codec: postcard (mismo que ya usa el grafo en disco).
- EtherType: 0x88B5. MAX_PAYLOAD_AKASHA = 1486 (MTU sin fragmentar).
- Helpers componer_frame(src, dst, msg) y analizar_frame(bytes) que
distinguen EtherType ajeno, frame truncado y payload basura.
- 6 pruebas unitarias en verde.
Modulo nuevo 'kernel/src/akasha.rs' con tres oficios:
1. Demuxer (drenar_y_demultiplexar): drena la cola RX del dispositivo
virtio-net y demultiplexa: frames AoE con payload valido los
procesa el respondedor; el resto va a una cola del userspace que
'sys_net_recibir' ahora lee. Frames 0x88B5 con payload
no-postcard (saludo de pregon) se cuentan y tambien viajan al
userspace.
2. Atencion de mensajes (procesar):
- SolicitarObjeto(id): consulta almacen::recuperar; si tenemos el
objeto, respondemos ProveedorObjeto unicast con objeto.serializar()
y re-hashing de defensa en profundidad.
- ProveedorObjeto(id, payload): verifica blake3(payload)==id antes
de absorber con almacen::almacenar.
- AnunciarRaiz(id): si ignoramos el nodo, le solicitamos al emisor.
3. Faro periodico (difundir_raiz cada 5 s): broadcast del hash del
manifiesto actual. Cadencia medida contra reloj::milisegundos(),
no contra los awaits — el interprete wasmi de los apps degrada
la cadencia de EsperaFrame::await a varios cientos de ms, asi
que se mide contra el reloj monotono y los oficios per-fotograma
se enganchan al tic del compositor (cuyo latido es fiable).
Contadores ResumenAkasha (rx/tx por variante, descartados, cola del
usuario) listos para un futuro indicador AoE en la barra de tareas.
Cambios complementarios:
- sys_net_recibir lee de akasha::pop_usuario, no de
drivers::red::recibir_en (que queda #[allow(dead_code)] como
primitiva del driver para diagnostico).
- tarea_red queda corta: envia un ARP al gateway y termina. El
demuxer y el faro viven en el tic del compositor.
Verificacion:
- 'cargo test -p akasha' → 6 pruebas en verde.
- QEMU headless 60 s con -object filter-dump → 14 frames: 11
AnunciarRaiz (Δ promedio 5.86 s sobre 5.00 s de target), 2 ARP
y el pregon hello. Cada AnunciarRaiz lleva el hash del manifiesto
'2f3deadfcc7dae25..' en 33 bytes postcard sobre 47 bytes de frame.
- COM1 vuelca 'akasha :: ANUNCIO emitido :: raiz=2f3deadfcc7dae25..'
en cada disparo.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Generated
+129
@@ -0,0 +1,129 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "akasha"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"postcard",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cobs"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-io"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-io"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
|
||||
|
||||
[[package]]
|
||||
name = "postcard"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
|
||||
dependencies = [
|
||||
"cobs",
|
||||
"embedded-io 0.4.0",
|
||||
"embedded-io 0.6.1",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
@@ -0,0 +1,38 @@
|
||||
# =============================================================================
|
||||
# renaser :: akasha — protocolo Akasha Over Ether (AoE)
|
||||
# -----------------------------------------------------------------------------
|
||||
# Nucleo `#![no_std]` COMPARTIDO: la verdad UNICA del protocolo de red nativo
|
||||
# de renaser. Lo enlaza el kernel bare-metal (target `x86_64-unknown-none`) y,
|
||||
# por ser no_std, lo compila tambien sin friccion el anfitrion `boot` y
|
||||
# cualquier otra pieza que quiera dialogar en el mismo idioma — incluida
|
||||
# alguna futura app del userspace.
|
||||
#
|
||||
# El protocolo extiende el GRAFO de objetos persistentes (Fase 6) sobre una
|
||||
# red Ethernet cruda, sin pasar por TCP/IP. Tres mensajes bastan: solicitar
|
||||
# un objeto por su hash BLAKE3, proveerlo de vuelta, anunciar la raiz actual
|
||||
# del sistema. Se serializa con `postcard` —compacto y deterministico— y
|
||||
# viaja en frames de EtherType experimental `0x88B5`.
|
||||
#
|
||||
# Queda EXCLUIDO del espacio de trabajo (ver el Cargo.toml raiz), como el
|
||||
# kernel y como `formato`: lo consume un paquete bare-metal, asi que fija
|
||||
# sus versiones de forma explicita.
|
||||
# =============================================================================
|
||||
|
||||
[package]
|
||||
name = "akasha"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
authors = ["JL Soltech <gerencia@jlsoltech.com>"]
|
||||
description = "renaser :: protocolo Akasha Over Ether (AoE) — grafo distribuido sobre Ethernet"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
# `serde` aporta los rasgos de (de)serializacion; `postcard` los materializa en
|
||||
# un formato binario compacto, el mismo que ya usa `formato` para el disco.
|
||||
# Asi el grafo habla el mismo idioma en el disco y en el cable.
|
||||
serde = { version = "1", default-features = false, features = ["alloc", "derive"] }
|
||||
postcard = { version = "1", default-features = false, features = ["alloc"] }
|
||||
@@ -0,0 +1,252 @@
|
||||
// =============================================================================
|
||||
// renaser :: akasha — Akasha Over Ether (AoE)
|
||||
// -----------------------------------------------------------------------------
|
||||
// Fase 19 demostro que un app del userspace puede inyectar frames Ethernet
|
||||
// crudos al cable —`pregon` gritando «hola» con su EtherType experimental—,
|
||||
// pero ese saludo era texto plano, sin estructura. La Fase 20 da el siguiente
|
||||
// paso natural: **fundar un protocolo nativo del ecosistema** para que
|
||||
// renaser hable consigo mismo a traves de la red, sin TCP, sin IP, sin las
|
||||
// sobrecargas de cabecera de los años 80.
|
||||
//
|
||||
// AoE viaja DIRECTAMENTE sobre Ethernet (`EtherType = 0x88B5`, rango
|
||||
// experimental reservado por IEEE para uso local). Cada frame transporta un
|
||||
// `MensajeAkasha` serializado con `postcard` —el mismo codec que ya usa
|
||||
// `formato` para el grafo en disco—. Tres mensajes bastan:
|
||||
//
|
||||
// 1. `SolicitarObjeto(id)` — pide un nodo del grafo por su hash BLAKE3.
|
||||
// 2. `ProveedorObjeto(id, d)` — responde con el payload binario del nodo.
|
||||
// 3. `AnunciarRaiz(id)` — difunde el hash de la raiz del sistema.
|
||||
//
|
||||
// Con esto basta para extender el grafo de objetos —direccionado por
|
||||
// contenido, inmutable, ya BLAKE3— a OTRAS maquinas renaser que escuchen en
|
||||
// la misma red de capa-2. El receptor de un `AnunciarRaiz` puede comparar
|
||||
// hashes, descubrir que le falta un nodo, pedirlo con `SolicitarObjeto` y
|
||||
// ensamblar el grafo del par. El grafo deja de ser una propiedad LOCAL del
|
||||
// disco y se vuelve una propiedad DISTRIBUIDA del cable.
|
||||
//
|
||||
// Esta crate es la unica verdad del protocolo. Es un nucleo `#![no_std]` —el
|
||||
// kernel bare-metal la enlaza—; cualquier app, daemon u orquestador que
|
||||
// hable AoE consume estos mismos tipos. Ningun otro modulo redefine ni un
|
||||
// byte del trazado del frame.
|
||||
// =============================================================================
|
||||
|
||||
#![no_std]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// =============================================================================
|
||||
// Constantes del protocolo en el cable
|
||||
// =============================================================================
|
||||
|
||||
/// EtherType de AoE, rango experimental reservado por IEEE para uso local
|
||||
/// (0x88B5/0x88B6). renaser elige el primero. Cualquier frame del cable que
|
||||
/// no porte este EtherType NO es Akasha, y se entrega al userspace.
|
||||
pub const ETHER_TYPE_AKASHA: u16 = 0x88B5;
|
||||
|
||||
/// Tamaño de la cabecera Ethernet, en bytes (dst + src + ethertype).
|
||||
pub const CABECERA_ETHERNET: usize = 14;
|
||||
|
||||
/// Maximo del payload AoE serializado, en bytes. Acotado para que el frame
|
||||
/// completo (cabecera + payload) no exceda una MTU Ethernet sin VLAN
|
||||
/// (1500 - 14 = 1486) y se transmita SIN fragmentar. Si un mensaje no cabe,
|
||||
/// el llamante debe partirlo en varios objetos del grafo y referirse a ellos.
|
||||
pub const MAX_PAYLOAD_AKASHA: usize = 1486;
|
||||
|
||||
/// MAC de broadcast — la difunde todo Ethernet, equivalente a `255.255.255.255`
|
||||
/// en IPv4 pero en capa-2 pura.
|
||||
pub const MAC_BROADCAST: [u8; 6] = [0xff; 6];
|
||||
|
||||
/// El identificador de un objeto del grafo: el hash BLAKE3 de su forma
|
||||
/// serializada. En un almacen direccionado por contenido, la identidad ES el
|
||||
/// contenido. Coincide byte a byte con `formato::Hash` —AoE habla el mismo
|
||||
/// idioma de identidad que el grafo en disco—.
|
||||
pub type ObjectId = [u8; 32];
|
||||
|
||||
/// Una direccion MAC, en seis bytes.
|
||||
pub type Mac = [u8; 6];
|
||||
|
||||
// =============================================================================
|
||||
// El mensaje
|
||||
// =============================================================================
|
||||
|
||||
/// Un mensaje AoE — la unidad de protocolo que viaja en un frame de
|
||||
/// `ETHER_TYPE_AKASHA`. Tres variantes bastan para fundar un grafo distribuido:
|
||||
///
|
||||
/// - `SolicitarObjeto` pregunta por un objeto identificado por su hash.
|
||||
/// - `ProveedorObjeto` responde con el payload binario del objeto. El
|
||||
/// receptor recompone el `formato::Objeto` aplicando su deserializador a
|
||||
/// `payload` y verificando que `blake3(payload) == id`.
|
||||
/// - `AnunciarRaiz` difunde el hash de la raiz —el ancla del sistema
|
||||
/// actual—. Sirve como faro: quien escuche y carezca de ese nodo en su
|
||||
/// grafo local puede iniciar una solicitud.
|
||||
///
|
||||
/// La codificacion `postcard` es estable y compacta: un `SolicitarObjeto`
|
||||
/// ocupa 33 bytes (1 de variante + 32 de hash) en el cable.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum MensajeAkasha {
|
||||
/// Solicito el objeto identificado por este hash.
|
||||
SolicitarObjeto(ObjectId),
|
||||
/// Aqui esta el payload binario del objeto identificado por este hash.
|
||||
/// El payload es la forma serializada `postcard` de un `formato::Objeto`,
|
||||
/// y el receptor DEBE verificar que `blake3(payload) == id` antes de
|
||||
/// confiar en el contenido.
|
||||
ProveedorObjeto(ObjectId, Vec<u8>),
|
||||
/// Difundo el hash de mi raiz actual — quien me escuche y le falte este
|
||||
/// nodo en su grafo local puede pedirmelo.
|
||||
AnunciarRaiz(ObjectId),
|
||||
}
|
||||
|
||||
/// El motivo por el que un frame AoE no se pudo componer o analizar.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum ErrorAkasha {
|
||||
/// El payload serializado excede `MAX_PAYLOAD_AKASHA`.
|
||||
PayloadDemasiadoLargo,
|
||||
/// El frame en el cable es mas corto que la cabecera Ethernet.
|
||||
FrameDemasiadoCorto,
|
||||
/// El EtherType del frame no es `ETHER_TYPE_AKASHA`.
|
||||
EtherTypeAjeno,
|
||||
/// `postcard` no supo deserializar el payload (basura, version distinta,
|
||||
/// otro protocolo experimental ajeno).
|
||||
PayloadInvalido,
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Composicion y analisis de frames
|
||||
// =============================================================================
|
||||
|
||||
/// Compone un frame Ethernet completo —cabecera (14 bytes) + payload AoE
|
||||
/// (`postcard(mensaje)`)— listo para entregar al driver. El llamante elige el
|
||||
/// destino (`MAC_BROADCAST` para difundir) y firma el frame con su propia
|
||||
/// MAC. Devuelve el frame completo, o un error si el mensaje serializado
|
||||
/// excede `MAX_PAYLOAD_AKASHA`.
|
||||
pub fn componer_frame(
|
||||
src: Mac,
|
||||
dst: Mac,
|
||||
mensaje: &MensajeAkasha,
|
||||
) -> Result<Vec<u8>, ErrorAkasha> {
|
||||
let payload =
|
||||
postcard::to_allocvec(mensaje).map_err(|_| ErrorAkasha::PayloadDemasiadoLargo)?;
|
||||
if payload.len() > MAX_PAYLOAD_AKASHA {
|
||||
return Err(ErrorAkasha::PayloadDemasiadoLargo);
|
||||
}
|
||||
let mut frame = Vec::with_capacity(CABECERA_ETHERNET + payload.len());
|
||||
frame.extend_from_slice(&dst);
|
||||
frame.extend_from_slice(&src);
|
||||
frame.extend_from_slice(ÐER_TYPE_AKASHA.to_be_bytes());
|
||||
frame.extend_from_slice(&payload);
|
||||
Ok(frame)
|
||||
}
|
||||
|
||||
/// Analiza un frame Ethernet entrante. Si su EtherType es `ETHER_TYPE_AKASHA`
|
||||
/// y el payload deserializa como un `MensajeAkasha`, devuelve la MAC de origen
|
||||
/// y el mensaje. En cualquier otro caso —EtherType ajeno, frame truncado,
|
||||
/// `postcard` no le encuentra sentido al payload— devuelve un `ErrorAkasha`
|
||||
/// que distingue el motivo: el llamante puede entonces decidir si lo entrega
|
||||
/// al userspace (otro protocolo) o lo descarta (basura).
|
||||
pub fn analizar_frame(frame: &[u8]) -> Result<(Mac, MensajeAkasha), ErrorAkasha> {
|
||||
if frame.len() < CABECERA_ETHERNET {
|
||||
return Err(ErrorAkasha::FrameDemasiadoCorto);
|
||||
}
|
||||
let etype = u16::from_be_bytes([frame[12], frame[13]]);
|
||||
if etype != ETHER_TYPE_AKASHA {
|
||||
return Err(ErrorAkasha::EtherTypeAjeno);
|
||||
}
|
||||
let mut src: Mac = [0; 6];
|
||||
src.copy_from_slice(&frame[6..12]);
|
||||
let payload = &frame[CABECERA_ETHERNET..];
|
||||
let mensaje: MensajeAkasha =
|
||||
postcard::from_bytes(payload).map_err(|_| ErrorAkasha::PayloadInvalido)?;
|
||||
Ok((src, mensaje))
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Pruebas
|
||||
// =============================================================================
|
||||
|
||||
#[cfg(test)]
|
||||
mod pruebas {
|
||||
use super::*;
|
||||
use alloc::vec;
|
||||
|
||||
const MAC_A: Mac = [0x52, 0x54, 0x00, 0x12, 0x34, 0x56];
|
||||
const MAC_B: Mac = [0x52, 0x54, 0x00, 0xAB, 0xCD, 0xEF];
|
||||
const HASH_X: ObjectId = [0x11; 32];
|
||||
|
||||
#[test]
|
||||
fn componer_y_analizar_solicitud_es_simetrico() {
|
||||
let msg = MensajeAkasha::SolicitarObjeto(HASH_X);
|
||||
let frame = componer_frame(MAC_A, MAC_B, &msg).unwrap();
|
||||
// Cabecera: dst + src + ethertype.
|
||||
assert_eq!(&frame[0..6], &MAC_B);
|
||||
assert_eq!(&frame[6..12], &MAC_A);
|
||||
assert_eq!(&frame[12..14], ÐER_TYPE_AKASHA.to_be_bytes());
|
||||
let (src, rec) = analizar_frame(&frame).unwrap();
|
||||
assert_eq!(src, MAC_A);
|
||||
match rec {
|
||||
MensajeAkasha::SolicitarObjeto(id) => assert_eq!(id, HASH_X),
|
||||
otro => panic!("variante inesperada: {otro:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn anuncio_de_raiz_viaja_compacto() {
|
||||
let frame =
|
||||
componer_frame(MAC_A, MAC_BROADCAST, &MensajeAkasha::AnunciarRaiz(HASH_X))
|
||||
.unwrap();
|
||||
// 14 cabecera + 1 byte variante + 32 hash = 47 bytes en el cable.
|
||||
assert_eq!(frame.len(), 47);
|
||||
assert_eq!(&frame[0..6], &MAC_BROADCAST);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn proveedor_lleva_payload_arbitrario() {
|
||||
let payload = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
|
||||
let msg = MensajeAkasha::ProveedorObjeto(HASH_X, payload.clone());
|
||||
let frame = componer_frame(MAC_A, MAC_B, &msg).unwrap();
|
||||
let (_, rec) = analizar_frame(&frame).unwrap();
|
||||
match rec {
|
||||
MensajeAkasha::ProveedorObjeto(id, p) => {
|
||||
assert_eq!(id, HASH_X);
|
||||
assert_eq!(p, payload);
|
||||
}
|
||||
otro => panic!("variante inesperada: {otro:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frame_demasiado_corto_se_distingue() {
|
||||
assert!(matches!(
|
||||
analizar_frame(&[0u8; 8]),
|
||||
Err(ErrorAkasha::FrameDemasiadoCorto)
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ethertype_ajeno_se_distingue() {
|
||||
// Cabecera valida pero EtherType de IPv4 (0x0800).
|
||||
let mut frame = [0u8; CABECERA_ETHERNET];
|
||||
frame[12] = 0x08;
|
||||
frame[13] = 0x00;
|
||||
assert!(matches!(
|
||||
analizar_frame(&frame),
|
||||
Err(ErrorAkasha::EtherTypeAjeno)
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn payload_invalido_se_distingue() {
|
||||
// EtherType correcto, pero el payload es basura para postcard.
|
||||
let mut frame = [0u8; CABECERA_ETHERNET + 4];
|
||||
frame[12..14].copy_from_slice(ÐER_TYPE_AKASHA.to_be_bytes());
|
||||
frame[14..].copy_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]);
|
||||
assert!(matches!(
|
||||
analizar_frame(&frame),
|
||||
Err(ErrorAkasha::PayloadInvalido)
|
||||
));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user