liblmp: Add tests from Bluetooth SIG LMP TestSuite
Test: atest --host liblmp_tests
Change-Id: Ida61973bbed7735e43e38e373d3dc3b39cf24149
diff --git a/tools/rootcanal/lmp/Android.bp b/tools/rootcanal/lmp/Android.bp
index 574b5aa..3f941d2 100644
--- a/tools/rootcanal/lmp/Android.bp
+++ b/tools/rootcanal/lmp/Android.bp
@@ -41,3 +41,22 @@
"lmp_packets.rs",
],
}
+
+rust_test_host {
+ name: "liblmp_tests",
+ crate_name: "lmp",
+ srcs: [
+ "src/lib.rs",
+ ":LmpGeneratedPackets_rust",
+ ],
+ auto_gen_config: true,
+ edition: "2018",
+ proc_macros: ["libnum_derive", "libpaste"],
+ rustlibs: [
+ "libbt_packets",
+ "libbytes",
+ "libnum_traits",
+ "libthiserror",
+ "libpin_utils",
+ ],
+}
diff --git a/tools/rootcanal/lmp/src/procedure/secure_simple_pairing.rs b/tools/rootcanal/lmp/src/procedure/secure_simple_pairing.rs
index 945cbbf..469ceb2 100644
--- a/tools/rootcanal/lmp/src/procedure/secure_simple_pairing.rs
+++ b/tools/rootcanal/lmp/src/procedure/secure_simple_pairing.rs
@@ -618,3 +618,91 @@
Ok(())
}
+
+#[cfg(test)]
+mod tests {
+ use crate::procedure::Context;
+ use crate::test::{sequence, TestContext};
+ // simple pairing is part of authentication procedure
+ use super::super::authentication::initiate;
+ use super::super::authentication::respond;
+
+ #[test]
+ fn initiate_size() {
+ let context = crate::test::TestContext::new();
+ let procedure = super::initiate(&context);
+
+ fn assert_max_size<T>(_value: T, limit: usize) {
+ let type_name = std::any::type_name::<T>();
+ let size = std::mem::size_of::<T>();
+ println!("Size of {}: {}", type_name, size);
+ assert!(size < limit)
+ }
+
+ assert_max_size(procedure, 250);
+ }
+
+ #[test]
+ fn numeric_comparaison_initiator_success() {
+ let context = TestContext::new();
+ let procedure = initiate;
+
+ include!("../../test/SP/BV-06-C.in");
+ }
+
+ #[test]
+ fn numeric_comparaison_responder_success() {
+ let context = TestContext::new();
+ let procedure = respond;
+
+ include!("../../test/SP/BV-07-C.in");
+ }
+
+ #[test]
+ fn numeric_comparaison_initiator_failure_on_initiating_side() {
+ let context = TestContext::new();
+ let procedure = initiate;
+
+ include!("../../test/SP/BV-08-C.in");
+ }
+
+ #[test]
+ fn numeric_comparaison_responder_failure_on_initiating_side() {
+ let context = TestContext::new();
+ let procedure = respond;
+
+ include!("../../test/SP/BV-09-C.in");
+ }
+
+ #[test]
+ fn numeric_comparaison_initiator_failure_on_responding_side() {
+ let context = TestContext::new();
+ let procedure = initiate;
+
+ include!("../../test/SP/BV-10-C.in");
+ }
+
+ #[test]
+ fn numeric_comparaison_responder_failure_on_responding_side() {
+ let context = TestContext::new();
+ let procedure = respond;
+
+ include!("../../test/SP/BV-11-C.in");
+ }
+
+ #[test]
+ fn passkey_entry_initiator_success() {
+ let context = TestContext::new();
+ let procedure = initiate;
+
+ include!("../../test/SP/BV-12-C.in");
+ }
+
+ #[test]
+ fn passkey_entry_responder_success() {
+ let context = TestContext::new();
+ let procedure = respond;
+
+ include!("../../test/SP/BV-13-C.in");
+ }
+}
diff --git a/tools/rootcanal/lmp/src/test/context.rs b/tools/rootcanal/lmp/src/test/context.rs
new file mode 100644
index 0000000..f790bf7
--- /dev/null
+++ b/tools/rootcanal/lmp/src/test/context.rs
@@ -0,0 +1,87 @@
+use std::cell::RefCell;
+use std::collections::VecDeque;
+use std::convert::{TryFrom, TryInto};
+use std::future::Future;
+use std::pin::Pin;
+use std::task::{self, Poll};
+
+use crate::packets::{hci, lmp};
+
+use crate::procedure::Context;
+
+#[derive(Default)]
+pub struct TestContext {
+ pub in_lmp_packets: RefCell<VecDeque<lmp::PacketPacket>>,
+ pub out_lmp_packets: RefCell<VecDeque<lmp::PacketPacket>>,
+ pub hci_events: RefCell<VecDeque<hci::EventPacket>>,
+ pub hci_commands: RefCell<VecDeque<hci::CommandPacket>>,
+}
+
+impl TestContext {
+ pub fn new() -> Self {
+ Default::default()
+ }
+}
+
+impl Context for TestContext {
+ fn poll_hci_command<C: TryFrom<hci::CommandPacket>>(&self) -> Poll<C> {
+ let command =
+ self.hci_commands.borrow().front().and_then(|command| command.clone().try_into().ok());
+
+ if let Some(command) = command {
+ self.hci_commands.borrow_mut().pop_front();
+ Poll::Ready(command)
+ } else {
+ Poll::Pending
+ }
+ }
+
+ fn poll_lmp_packet<P: TryFrom<lmp::PacketPacket>>(&self) -> Poll<P> {
+ let packet =
+ self.in_lmp_packets.borrow().front().and_then(|packet| packet.clone().try_into().ok());
+
+ if let Some(packet) = packet {
+ self.in_lmp_packets.borrow_mut().pop_front();
+ Poll::Ready(packet)
+ } else {
+ Poll::Pending
+ }
+ }
+
+ fn send_hci_event<E: Into<hci::EventPacket>>(&self, event: E) {
+ self.hci_events.borrow_mut().push_back(event.into());
+ }
+
+ fn send_lmp_packet<P: Into<lmp::PacketPacket>>(&self, packet: P) {
+ self.out_lmp_packets.borrow_mut().push_back(packet.into());
+ }
+
+ fn peer_address(&self) -> hci::Address {
+ hci::Address { bytes: [0; 6] }
+ }
+
+ fn peer_handle(&self) -> u16 {
+ 0x42
+ }
+
+ fn peer_extended_features(&self, features_page: u8) -> Option<u64> {
+ if features_page == 1 {
+ Some(1)
+ } else {
+ Some(0)
+ }
+ }
+
+ fn extended_features(&self, features_page: u8) -> u64 {
+ if features_page == 1 {
+ 1
+ } else {
+ 0
+ }
+ }
+}
+
+pub fn poll(future: Pin<&mut impl Future<Output = ()>>) -> Poll<()> {
+ let waker = crate::future::noop_waker();
+ future.poll(&mut task::Context::from_waker(&waker))
+}
diff --git a/tools/rootcanal/lmp/src/test/mod.rs b/tools/rootcanal/lmp/src/test/mod.rs
new file mode 100644
index 0000000..ad790a1
--- /dev/null
+++ b/tools/rootcanal/lmp/src/test/mod.rs
@@ -0,0 +1,5 @@
+mod context;
+mod sequence;
+
+pub(crate) use context::{poll, TestContext};
+pub(crate) use sequence::{sequence, sequence_body};
diff --git a/tools/rootcanal/lmp/src/test/sequence.rs b/tools/rootcanal/lmp/src/test/sequence.rs
new file mode 100644
index 0000000..b9df64e
--- /dev/null
+++ b/tools/rootcanal/lmp/src/test/sequence.rs
@@ -0,0 +1,115 @@
+macro_rules! sequence_body {
+ ($ctx:ident, ) => { None };
+ ($ctx:ident, Lower Tester -> IUT: $packet:ident {
+ $($name:ident: $value:expr),* $(,)?
+ } $($tail:tt)*) => {{
+ use crate::packets::lmp::*;
+
+ let builder = paste! {
+ [<$packet Builder>] {
+ $($name: $value),*
+ }
+ };
+ $ctx.0.in_lmp_packets.borrow_mut().push_back(builder.build().into());
+
+ let poll = crate::test::poll($ctx.1.as_mut());
+
+ assert!($ctx.0.in_lmp_packets.borrow().is_empty(), "{} was not consumed by procedure", stringify!($packet));
+
+ println!("Lower Tester -> IUT: {}", stringify!($packet));
+
+ sequence_body!($ctx, $($tail)*).or(Some(poll))
+ }};
+ ($ctx:ident, Upper Tester -> IUT: $packet:ident {
+ $($name:ident: $value:expr),* $(,)?
+ } $($tail:tt)*) => {{
+ use crate::packets::hci::*;
+
+ let builder = paste! {
+ [<$packet Builder>] {
+ $($name: $value),*
+ }
+ };
+ $ctx.0.hci_commands.borrow_mut().push_back(builder.build().into());
+
+ let poll = crate::test::poll($ctx.1.as_mut());
+
+ assert!($ctx.0.hci_commands.borrow().is_empty(), "{} was not consumed by procedure", stringify!($packet));
+
+ println!("Upper Tester -> IUT: {}", stringify!($packet));
+
+ sequence_body!($ctx, $($tail)*).or(Some(poll))
+ }};
+ ($ctx:ident, IUT -> Upper Tester: $packet:ident {
+ $($name:ident: $expected_value:expr),* $(,)?
+ } $($tail:tt)*) => {{
+ use crate::packets::hci::*;
+
+ paste! {
+ let packet: [<$packet Packet>] = $ctx.0.hci_events.borrow_mut().pop_front().expect("No hci packet").try_into().unwrap();
+ }
+
+ $(
+ let value = paste! { packet.[<get_ $name>]() };
+ assert_eq!(value.clone(), $expected_value);
+ )*
+
+ println!("IUT -> Upper Tester: {}", stringify!($packet));
+
+ sequence_body!($ctx, $($tail)*)
+ }};
+ ($ctx:ident, IUT -> Lower Tester: $packet:ident {
+ $($name:ident: $expected_value:expr),* $(,)?
+ } $($tail:tt)*) => {{
+ use crate::packets::lmp::*;
+
+ paste! {
+ let packet: [<$packet Packet>] = $ctx.0.out_lmp_packets.borrow_mut().pop_front().expect("No lmp packet").try_into().unwrap();
+ }
+
+ $(
+ let value = paste! { packet.[<get_ $name>]() };
+ assert_eq!(value.clone(), $expected_value);
+ )*
+
+ println!("IUT -> Lower Tester: {}", stringify!($packet));
+
+ sequence_body!($ctx, $($tail)*)
+ }};
+ ($ctx:ident, repeat $number:literal times {
+ $($inner:tt)*
+ } $($tail:tt)*) => {{
+ println!("repeat {}", $number);
+ for _ in 0..$number {
+ sequence_body!($ctx, $($inner)*);
+ }
+ println!("endrepeat");
+
+ sequence_body!($ctx, $($tail)*)
+ }};
+ }
+
+macro_rules! sequence {
+ ($procedure_fn:path, $context:path, $($tail:tt)*) => ({
+ use paste::paste;
+ use std::convert::TryInto;
+
+ let procedure = $procedure_fn(&$context);
+
+ use crate::future::pin;
+ pin!(procedure);
+
+ let mut ctx = (&$context, procedure);
+ use crate::test::sequence_body;
+ let last_poll = sequence_body!(ctx, $($tail)*).unwrap();
+
+ assert!(last_poll.is_ready());
+ assert!($context.in_lmp_packets.borrow().is_empty());
+ assert!($context.out_lmp_packets.borrow().is_empty());
+ assert!($context.hci_commands.borrow().is_empty());
+ assert!($context.hci_events.borrow().is_empty());
+ });
+ }
+
+pub(crate) use sequence;
+pub(crate) use sequence_body;
diff --git a/tools/rootcanal/lmp/test/SP/BV-06-C.in b/tools/rootcanal/lmp/test/SP/BV-06-C.in
new file mode 100644
index 0000000..dfe68a9
--- /dev/null
+++ b/tools/rootcanal/lmp/test/SP/BV-06-C.in
@@ -0,0 +1,163 @@
+sequence! { procedure, context,
+ // ACL Connection Established
+ Upper Tester -> IUT: AuthenticationRequested {
+ connection_handle: context.peer_handle()
+ }
+ IUT -> Upper Tester: AuthenticationRequestedStatus {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ }
+ IUT -> Upper Tester: LinkKeyRequest {
+ bd_addr: context.peer_address(),
+ }
+ Upper Tester -> IUT: LinkKeyRequestNegativeReply {
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Upper Tester: LinkKeyRequestNegativeReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Upper Tester: IoCapabilityRequest {
+ bd_addr: context.peer_address(),
+ }
+ Upper Tester -> IUT: IoCapabilityRequestReply {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::DisplayYesNo,
+ oob_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ IUT -> Upper Tester: IoCapabilityRequestReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Lower Tester: IoCapabilityReq {
+ transaction_id: 0,
+ io_capabilities: 0x01,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ Lower Tester -> IUT: IoCapabilityRes {
+ transaction_id: 0,
+ io_capabilities: 0x01,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ IUT -> Upper Tester: IoCapabilityResponse {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::DisplayYesNo,
+ oob_data_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ // Public Key Exchange
+ IUT -> Lower Tester: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ IUT -> Lower Tester: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ Lower Tester -> IUT: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ Lower Tester -> IUT: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ // Authentication Stage 1: Numeric Comparaison Protocol
+ Lower Tester -> IUT: SimplePairingConfirm {
+ transaction_id: 0,
+ commitment_value: [0; 16],
+ }
+ IUT -> Lower Tester: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ Lower Tester -> IUT: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ IUT -> Upper Tester: UserConfirmationRequest { bd_addr: context.peer_address(), numeric_value: 0 }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ Upper Tester -> IUT: UserConfirmationRequestReply { bd_addr: context.peer_address() }
+ IUT -> Upper Tester: UserConfirmationRequestReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ // Authentication Stage 2
+ IUT -> Lower Tester: DhkeyCheck {
+ transaction_id: 0,
+ confirmation_value: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted { transaction_id: 0, accepted_opcode: Opcode::DhkeyCheck }
+ Lower Tester -> IUT: DhkeyCheck {
+ transaction_id: 0,
+ confirmation_value: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted { transaction_id: 0, accepted_opcode: Opcode::DhkeyCheck }
+ IUT -> Upper Tester: SimplePairingComplete {
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ // Link Key Calculation
+ IUT -> Lower Tester: AuRand {
+ transaction_id: 0,
+ random_number: [0; 16],
+ }
+ Lower Tester -> IUT: Sres {
+ transaction_id: 0,
+ authentication_rsp: [0; 4],
+ }
+ Lower Tester -> IUT: AuRand {
+ transaction_id: 0,
+ random_number: [0; 16],
+ }
+ IUT -> Lower Tester: Sres {
+ transaction_id: 0,
+ authentication_rsp: [0; 4],
+ }
+ IUT -> Upper Tester: LinkKeyNotification {
+ bd_addr: context.peer_address(),
+ key_type: KeyType::AuthenticatedP192,
+ link_key: [0; 16],
+ }
+ IUT -> Upper Tester: AuthenticationComplete {
+ status: ErrorCode::Success,
+ connection_handle: context.peer_handle(),
+ }
+}
diff --git a/tools/rootcanal/lmp/test/SP/BV-07-C.in b/tools/rootcanal/lmp/test/SP/BV-07-C.in
new file mode 100644
index 0000000..62913ae
--- /dev/null
+++ b/tools/rootcanal/lmp/test/SP/BV-07-C.in
@@ -0,0 +1,141 @@
+sequence! { procedure, context,
+ // ACL Connection Established
+ Lower Tester -> IUT: IoCapabilityReq {
+ transaction_id: 0,
+ io_capabilities: 0x01,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ IUT -> Upper Tester: IoCapabilityResponse {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::DisplayYesNo,
+ oob_data_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ IUT -> Upper Tester: IoCapabilityRequest {
+ bd_addr: context.peer_address(),
+ }
+ Upper Tester -> IUT: IoCapabilityRequestReply {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::DisplayYesNo,
+ oob_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ IUT -> Upper Tester: IoCapabilityRequestReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Lower Tester: IoCapabilityRes {
+ transaction_id: 0,
+ io_capabilities: 0x01,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ // Public Key Exchange
+ Lower Tester -> IUT: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ Lower Tester -> IUT: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ IUT -> Lower Tester: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ IUT -> Lower Tester: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ // Authentication Stage 1: Numeric Comparaison Protocol
+ IUT -> Lower Tester: SimplePairingConfirm {
+ transaction_id: 0,
+ commitment_value: [0; 16],
+ }
+ Lower Tester -> IUT: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ IUT -> Lower Tester: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ IUT -> Upper Tester: UserConfirmationRequest { bd_addr: context.peer_address(), numeric_value: 0 }
+ Upper Tester -> IUT: UserConfirmationRequestReply { bd_addr: context.peer_address() }
+ IUT -> Upper Tester: UserConfirmationRequestReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ // Authentication Stage 2
+ Lower Tester -> IUT: DhkeyCheck {
+ transaction_id: 0,
+ confirmation_value: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted { transaction_id: 0, accepted_opcode: Opcode::DhkeyCheck }
+ IUT -> Lower Tester: DhkeyCheck {
+ transaction_id: 0,
+ confirmation_value: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted { transaction_id: 0, accepted_opcode: Opcode::DhkeyCheck }
+ IUT -> Upper Tester: SimplePairingComplete {
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ // Link Key Calculation
+ Lower Tester -> IUT: AuRand {
+ transaction_id: 0,
+ random_number: [0; 16],
+ }
+ IUT -> Lower Tester: Sres {
+ transaction_id: 0,
+ authentication_rsp: [0; 4],
+ }
+ IUT -> Lower Tester: AuRand {
+ transaction_id: 0,
+ random_number: [0; 16],
+ }
+ Lower Tester -> IUT: Sres {
+ transaction_id: 0,
+ authentication_rsp: [0; 4],
+ }
+ IUT -> Upper Tester: LinkKeyNotification {
+ bd_addr: context.peer_address(),
+ key_type: KeyType::AuthenticatedP192,
+ link_key: [0; 16],
+ }
+}
diff --git a/tools/rootcanal/lmp/test/SP/BV-08-C.in b/tools/rootcanal/lmp/test/SP/BV-08-C.in
new file mode 100644
index 0000000..2b5fbed
--- /dev/null
+++ b/tools/rootcanal/lmp/test/SP/BV-08-C.in
@@ -0,0 +1,133 @@
+sequence! { procedure, context,
+ // ACL Connection Established
+ Upper Tester -> IUT: AuthenticationRequested {
+ connection_handle: context.peer_handle()
+ }
+ IUT -> Upper Tester: AuthenticationRequestedStatus {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ }
+ IUT -> Upper Tester: LinkKeyRequest {
+ bd_addr: context.peer_address(),
+ }
+ Upper Tester -> IUT: LinkKeyRequestNegativeReply {
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Upper Tester: LinkKeyRequestNegativeReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Upper Tester: IoCapabilityRequest {
+ bd_addr: context.peer_address(),
+ }
+ Upper Tester -> IUT: IoCapabilityRequestReply {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::DisplayYesNo,
+ oob_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ IUT -> Upper Tester: IoCapabilityRequestReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Lower Tester: IoCapabilityReq {
+ transaction_id: 0,
+ io_capabilities: 0x01,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ Lower Tester -> IUT: IoCapabilityRes {
+ transaction_id: 0,
+ io_capabilities: 0x01,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ IUT -> Upper Tester: IoCapabilityResponse {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::DisplayYesNo,
+ oob_data_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ // Public Key Exchange
+ IUT -> Lower Tester: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ IUT -> Lower Tester: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ Lower Tester -> IUT: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ Lower Tester -> IUT: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ // Authentication Stage 1: Numeric Comparaison Protocol
+ Lower Tester -> IUT: SimplePairingConfirm {
+ transaction_id: 0,
+ commitment_value: [0; 16],
+ }
+ IUT -> Lower Tester: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ Lower Tester -> IUT: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ IUT -> Upper Tester: UserConfirmationRequest { bd_addr: context.peer_address(), numeric_value: 0 }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ Upper Tester -> IUT: UserConfirmationRequestNegativeReply { bd_addr: context.peer_address() }
+ IUT -> Upper Tester: UserConfirmationRequestNegativeReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Lower Tester: NumericComparaisonFailed {
+ transaction_id: 0,
+ }
+ IUT -> Upper Tester: SimplePairingComplete {
+ status: ErrorCode::AuthenticationFailure,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Upper Tester: AuthenticationComplete {
+ status: ErrorCode::AuthenticationFailure,
+ connection_handle: context.peer_handle(),
+ }
+}
diff --git a/tools/rootcanal/lmp/test/SP/BV-09-C.in b/tools/rootcanal/lmp/test/SP/BV-09-C.in
new file mode 100644
index 0000000..d0d9a3b
--- /dev/null
+++ b/tools/rootcanal/lmp/test/SP/BV-09-C.in
@@ -0,0 +1,111 @@
+sequence! { procedure, context,
+ // ACL Connection Established
+ Lower Tester -> IUT: IoCapabilityReq {
+ transaction_id: 0,
+ io_capabilities: 0x01,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ IUT -> Upper Tester: IoCapabilityResponse {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::DisplayYesNo,
+ oob_data_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ IUT -> Upper Tester: IoCapabilityRequest {
+ bd_addr: context.peer_address(),
+ }
+ Upper Tester -> IUT: IoCapabilityRequestReply {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::DisplayYesNo,
+ oob_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ IUT -> Upper Tester: IoCapabilityRequestReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Lower Tester: IoCapabilityRes {
+ transaction_id: 0,
+ io_capabilities: 0x01,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ // Public Key Exchange
+ Lower Tester -> IUT: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ Lower Tester -> IUT: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ IUT -> Lower Tester: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ IUT -> Lower Tester: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ // Authentication Stage 1: Numeric Comparaison Protocol
+ IUT -> Lower Tester: SimplePairingConfirm {
+ transaction_id: 0,
+ commitment_value: [0; 16],
+ }
+ Lower Tester -> IUT: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ IUT -> Lower Tester: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ IUT -> Upper Tester: UserConfirmationRequest { bd_addr: context.peer_address(), numeric_value: 0 }
+ Upper Tester -> IUT: UserConfirmationRequestReply { bd_addr: context.peer_address() }
+ IUT -> Upper Tester: UserConfirmationRequestReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ Lower Tester -> IUT: NumericComparaisonFailed {
+ transaction_id: 0,
+ }
+ IUT -> Upper Tester: SimplePairingComplete {
+ status: ErrorCode::AuthenticationFailure,
+ bd_addr: context.peer_address(),
+ }
+}
diff --git a/tools/rootcanal/lmp/test/SP/BV-10-C.in b/tools/rootcanal/lmp/test/SP/BV-10-C.in
new file mode 100644
index 0000000..9d4938f
--- /dev/null
+++ b/tools/rootcanal/lmp/test/SP/BV-10-C.in
@@ -0,0 +1,135 @@
+sequence! { procedure, context,
+ // ACL Connection Established
+ Upper Tester -> IUT: AuthenticationRequested {
+ connection_handle: context.peer_handle()
+ }
+ IUT -> Upper Tester: AuthenticationRequestedStatus {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ }
+ IUT -> Upper Tester: LinkKeyRequest {
+ bd_addr: context.peer_address(),
+ }
+ Upper Tester -> IUT: LinkKeyRequestNegativeReply {
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Upper Tester: LinkKeyRequestNegativeReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Upper Tester: IoCapabilityRequest {
+ bd_addr: context.peer_address(),
+ }
+ Upper Tester -> IUT: IoCapabilityRequestReply {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::DisplayYesNo,
+ oob_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ IUT -> Upper Tester: IoCapabilityRequestReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Lower Tester: IoCapabilityReq {
+ transaction_id: 0,
+ io_capabilities: 0x01,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ Lower Tester -> IUT: IoCapabilityRes {
+ transaction_id: 0,
+ io_capabilities: 0x01,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ IUT -> Upper Tester: IoCapabilityResponse {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::DisplayYesNo,
+ oob_data_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ // Public Key Exchange
+ IUT -> Lower Tester: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ IUT -> Lower Tester: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ Lower Tester -> IUT: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ Lower Tester -> IUT: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ // Authentication Stage 1: Numeric Comparaison Protocol
+ Lower Tester -> IUT: SimplePairingConfirm {
+ transaction_id: 0,
+ commitment_value: [0; 16],
+ }
+ IUT -> Lower Tester: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ Lower Tester -> IUT: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ IUT -> Upper Tester: UserConfirmationRequest { bd_addr: context.peer_address(), numeric_value: 0 }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ Upper Tester -> IUT: UserConfirmationRequestReply { bd_addr: context.peer_address() }
+ IUT -> Upper Tester: UserConfirmationRequestReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Lower Tester: DhkeyCheck {
+ transaction_id: 0,
+ confirmation_value: [0; 16],
+ }
+ Lower Tester -> IUT: NotAccepted { transaction_id: 0, not_accepted_opcode: Opcode::DhkeyCheck, error_code: 0x05 }
+ IUT -> Upper Tester: SimplePairingComplete {
+ status: ErrorCode::AuthenticationFailure,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Upper Tester: AuthenticationComplete {
+ status: ErrorCode::AuthenticationFailure,
+ connection_handle: context.peer_handle(),
+ }
+}
diff --git a/tools/rootcanal/lmp/test/SP/BV-11-C.in b/tools/rootcanal/lmp/test/SP/BV-11-C.in
new file mode 100644
index 0000000..fbd98d2
--- /dev/null
+++ b/tools/rootcanal/lmp/test/SP/BV-11-C.in
@@ -0,0 +1,113 @@
+sequence! { procedure, context,
+ // ACL Connection Established
+ Lower Tester -> IUT: IoCapabilityReq {
+ transaction_id: 0,
+ io_capabilities: 0x01,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ IUT -> Upper Tester: IoCapabilityResponse {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::DisplayYesNo,
+ oob_data_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ IUT -> Upper Tester: IoCapabilityRequest {
+ bd_addr: context.peer_address(),
+ }
+ Upper Tester -> IUT: IoCapabilityRequestReply {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::DisplayYesNo,
+ oob_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ IUT -> Upper Tester: IoCapabilityRequestReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Lower Tester: IoCapabilityRes {
+ transaction_id: 0,
+ io_capabilities: 0x01,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ // Public Key Exchange
+ Lower Tester -> IUT: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ Lower Tester -> IUT: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ IUT -> Lower Tester: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ IUT -> Lower Tester: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ // Authentication Stage 1: Numeric Comparaison Protocol
+ IUT -> Lower Tester: SimplePairingConfirm {
+ transaction_id: 0,
+ commitment_value: [0; 16],
+ }
+ Lower Tester -> IUT: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ IUT -> Lower Tester: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ IUT -> Upper Tester: UserConfirmationRequest { bd_addr: context.peer_address(), numeric_value: 0 }
+ Upper Tester -> IUT: UserConfirmationRequestNegativeReply { bd_addr: context.peer_address() }
+ IUT -> Upper Tester: UserConfirmationRequestNegativeReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ Lower Tester -> IUT: DhkeyCheck {
+ transaction_id: 0,
+ confirmation_value: [0; 16],
+ }
+ IUT -> Lower Tester: NotAccepted { transaction_id: 0, not_accepted_opcode: Opcode::DhkeyCheck }
+ IUT -> Upper Tester: SimplePairingComplete {
+ status: ErrorCode::AuthenticationFailure,
+ bd_addr: context.peer_address(),
+ }
+}
diff --git a/tools/rootcanal/lmp/test/SP/BV-12-C.in b/tools/rootcanal/lmp/test/SP/BV-12-C.in
new file mode 100644
index 0000000..3d9eb6e
--- /dev/null
+++ b/tools/rootcanal/lmp/test/SP/BV-12-C.in
@@ -0,0 +1,174 @@
+sequence! { procedure, context,
+ // ACL Connection Established
+ Upper Tester -> IUT: AuthenticationRequested {
+ connection_handle: context.peer_handle()
+ }
+ IUT -> Upper Tester: AuthenticationRequestedStatus {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ }
+ IUT -> Upper Tester: LinkKeyRequest {
+ bd_addr: context.peer_address(),
+ }
+ Upper Tester -> IUT: LinkKeyRequestNegativeReply {
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Upper Tester: LinkKeyRequestNegativeReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Upper Tester: IoCapabilityRequest {
+ bd_addr: context.peer_address(),
+ }
+ Upper Tester -> IUT: IoCapabilityRequestReply {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::KeyboardOnly,
+ oob_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ IUT -> Upper Tester: IoCapabilityRequestReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Lower Tester: IoCapabilityReq {
+ transaction_id: 0,
+ io_capabilities: 0x02,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ Lower Tester -> IUT: IoCapabilityRes {
+ transaction_id: 0,
+ io_capabilities: 0x00,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ IUT -> Upper Tester: IoCapabilityResponse {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::DisplayOnly,
+ oob_data_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ // Public Key Exchange
+ IUT -> Lower Tester: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ IUT -> Lower Tester: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ Lower Tester -> IUT: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ Lower Tester -> IUT: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ // Authentication Stage 1: Passkey Entry Protocol
+ IUT -> Upper Tester: UserPasskeyRequest {
+ bd_addr: context.peer_address(),
+ }
+ Upper Tester -> IUT: UserPasskeyRequestReply {
+ bd_addr: context.peer_address(),
+ numeric_value: 0,
+ }
+ IUT -> Upper Tester: UserPasskeyRequestReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ repeat 20 times {
+ IUT -> Lower Tester: SimplePairingConfirm {
+ transaction_id: 0,
+ commitment_value: [0; 16],
+ }
+ Lower Tester -> IUT: SimplePairingConfirm {
+ transaction_id: 0,
+ commitment_value: [0; 16],
+ }
+ IUT -> Lower Tester: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ Lower Tester -> IUT: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ }
+ // Authentication Stage 2
+ IUT -> Lower Tester: DhkeyCheck {
+ transaction_id: 0,
+ confirmation_value: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted { transaction_id: 0, accepted_opcode: Opcode::DhkeyCheck }
+ Lower Tester -> IUT: DhkeyCheck {
+ transaction_id: 0,
+ confirmation_value: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted { transaction_id: 0, accepted_opcode: Opcode::DhkeyCheck }
+ IUT -> Upper Tester: SimplePairingComplete {
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ // Link Key Calculation
+ IUT -> Lower Tester: AuRand {
+ transaction_id: 0,
+ random_number: [0; 16],
+ }
+ Lower Tester -> IUT: Sres {
+ transaction_id: 0,
+ authentication_rsp: [0; 4],
+ }
+ Lower Tester -> IUT: AuRand {
+ transaction_id: 0,
+ random_number: [0; 16],
+ }
+ IUT -> Lower Tester: Sres {
+ transaction_id: 0,
+ authentication_rsp: [0; 4],
+ }
+ IUT -> Upper Tester: LinkKeyNotification {
+ bd_addr: context.peer_address(),
+ key_type: KeyType::AuthenticatedP192,
+ link_key: [0; 16],
+ }
+ IUT -> Upper Tester: AuthenticationComplete {
+ status: ErrorCode::Success,
+ connection_handle: context.peer_handle(),
+ }
+}
diff --git a/tools/rootcanal/lmp/test/SP/BV-13-C.in b/tools/rootcanal/lmp/test/SP/BV-13-C.in
new file mode 100644
index 0000000..1449c60
--- /dev/null
+++ b/tools/rootcanal/lmp/test/SP/BV-13-C.in
@@ -0,0 +1,141 @@
+sequence! { procedure, context,
+ // ACL Connection Established
+ Lower Tester -> IUT: IoCapabilityReq {
+ transaction_id: 0,
+ io_capabilities: 0x02,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ IUT -> Upper Tester: IoCapabilityResponse {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::KeyboardOnly,
+ oob_data_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ IUT -> Upper Tester: IoCapabilityRequest {
+ bd_addr: context.peer_address(),
+ }
+ Upper Tester -> IUT: IoCapabilityRequestReply {
+ bd_addr: context.peer_address(),
+ io_capability: IoCapability::DisplayOnly,
+ oob_present: OobDataPresent::NotPresent,
+ authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection,
+ }
+ IUT -> Upper Tester: IoCapabilityRequestReplyComplete {
+ num_hci_command_packets: 1,
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ IUT -> Lower Tester: IoCapabilityRes {
+ transaction_id: 0,
+ io_capabilities: 0x00,
+ oob_authentication_data: 0x00,
+ authentication_requirement: 0x01,
+ }
+ // Public Key Exchange
+ Lower Tester -> IUT: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ Lower Tester -> IUT: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ IUT -> Lower Tester: EncapsulatedHeader {
+ transaction_id: 0,
+ major_type: 1,
+ minor_type: 1,
+ payload_length: 48,
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedHeader,
+ }
+ repeat 3 times {
+ IUT -> Lower Tester: EncapsulatedPayload {
+ transaction_id: 0,
+ data: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::EncapsulatedPayload,
+ }
+ }
+ // Authentication Stage 1: Numeric Comparaison Protocol
+ IUT -> Upper Tester: UserPasskeyNotification { bd_addr: context.peer_address(), passkey: 0 }
+ repeat 20 times {
+ Lower Tester -> IUT: SimplePairingConfirm {
+ transaction_id: 0,
+ commitment_value: [0; 16],
+ }
+ IUT -> Lower Tester: SimplePairingConfirm {
+ transaction_id: 0,
+ commitment_value: [0; 16],
+ }
+ Lower Tester -> IUT: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ IUT -> Lower Tester: SimplePairingNumber {
+ transaction_id: 0,
+ nonce: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted {
+ transaction_id: 0,
+ accepted_opcode: Opcode::SimplePairingNumber,
+ }
+ }
+ // Authentication Stage 2
+ Lower Tester -> IUT: DhkeyCheck {
+ transaction_id: 0,
+ confirmation_value: [0; 16],
+ }
+ IUT -> Lower Tester: Accepted { transaction_id: 0, accepted_opcode: Opcode::DhkeyCheck }
+ IUT -> Lower Tester: DhkeyCheck {
+ transaction_id: 0,
+ confirmation_value: [0; 16],
+ }
+ Lower Tester -> IUT: Accepted { transaction_id: 0, accepted_opcode: Opcode::DhkeyCheck }
+ IUT -> Upper Tester: SimplePairingComplete {
+ status: ErrorCode::Success,
+ bd_addr: context.peer_address(),
+ }
+ // Link Key Calculation
+ Lower Tester -> IUT: AuRand {
+ transaction_id: 0,
+ random_number: [0; 16],
+ }
+ IUT -> Lower Tester: Sres {
+ transaction_id: 0,
+ authentication_rsp: [0; 4],
+ }
+ IUT -> Lower Tester: AuRand {
+ transaction_id: 0,
+ random_number: [0; 16],
+ }
+ Lower Tester -> IUT: Sres {
+ transaction_id: 0,
+ authentication_rsp: [0; 4],
+ }
+ IUT -> Upper Tester: LinkKeyNotification {
+ bd_addr: context.peer_address(),
+ key_type: KeyType::AuthenticatedP192,
+ link_key: [0; 16],
+ }
+}