driver_lab_rust/server.rs
1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! FIDL server for the `fuchsia.driver.lab` wire contract, bridging the
6//! host-facing protocol to the host-testable core logic.
7
8use crate::fuchsia_backends::LiveBackend;
9use fidl_fuchsia_driver_lab as flab;
10use fuchsia_async::ScopeHandle;
11use futures::{FutureExt as _, TryStreamExt};
12use lab_proxy_core::access_policy::{AccessClass, AccessRule, Denial, WritePrecondition};
13use lab_proxy_core::audit_ring::{AuditRecord, AuditRing, Decision, OpStatus};
14use lab_proxy_core::executor::{
15 ClockOpError, Executor, GpioReadError, GpioWriteError, I2cTransferError, PollError, ReadError,
16 ResetOpError, SequenceItem as CoreSequenceItem, SerialOpError, SnapshotError, SnapshotItem,
17 SpiTransmitError, WriteError,
18};
19use lab_proxy_core::hardware_backend::Clock;
20use lab_proxy_core::interrupt::InterruptManager;
21use lab_proxy_core::session::{OpenError, ProxyIdentity, RunContext, SessionManager, SessionMode};
22use std::sync::{Arc, Mutex};
23
24fn fidl_to_core_sequence_item(item: &flab::SequenceItem) -> Option<CoreSequenceItem> {
25 match item {
26 flab::SequenceItem::Read32(read) => {
27 Some(CoreSequenceItem::Read32 { resource: read.resource, offset: read.offset })
28 }
29 flab::SequenceItem::Write32(write) => Some(CoreSequenceItem::Write32 {
30 resource: write.resource,
31 offset: write.offset,
32 value: write.value,
33 write_mask: write.write_mask,
34 precondition: write
35 .precondition
36 .as_ref()
37 .map(|p| WritePrecondition { expected: p.expected, mask: p.mask }),
38 readback: write.readback,
39 }),
40 flab::SequenceItem::Poll32(poll) => Some(CoreSequenceItem::Poll32 {
41 resource: poll.resource,
42 offset: poll.offset,
43 expected: poll.expected,
44 mask: poll.mask,
45 interval_ns: poll.interval_ns,
46 timeout_ns: poll.timeout_ns,
47 }),
48 flab::SequenceItem::DelayNs(delay) => Some(CoreSequenceItem::DelayNs(*delay)),
49 flab::SequenceItem::Barrier(_) => Some(CoreSequenceItem::Barrier),
50 flab::SequenceItem::GpioRead(read) => {
51 Some(CoreSequenceItem::GpioRead { resource: read.resource })
52 }
53 flab::SequenceItem::GpioWrite(write) => {
54 Some(CoreSequenceItem::GpioWrite { resource: write.resource, value: write.value })
55 }
56 flab::SequenceItem::I2cTransfer(transfer) => Some(CoreSequenceItem::I2cTransfer {
57 resource: transfer.resource,
58 write_data: transfer.write_data.clone(),
59 read_length: transfer.read_length,
60 }),
61 flab::SequenceItem::SpiTransmit(transmit) => Some(CoreSequenceItem::SpiTransmit {
62 resource: transmit.resource,
63 tx_data: transmit.tx_data.clone(),
64 }),
65 _ => None,
66 }
67}
68
69/// Wire-contract version served by this driver.
70pub const PROTOCOL_MAJOR: u32 = 1;
71/// Wire-contract minor version.
72pub const PROTOCOL_MINOR: u32 = 0;
73
74/// Clock backed by zx monotonic time.
75#[derive(Debug, Default)]
76pub struct ZxClock;
77
78impl Clock for ZxClock {
79 fn now_ns(&mut self) -> i64 {
80 zx::MonotonicInstant::get().into_nanos()
81 }
82}
83
84impl lab_proxy_core::hardware_backend::Timer for ZxClock {
85 async fn sleep(&mut self, duration_ns: i64) {
86 if duration_ns > 0 {
87 fuchsia_async::Timer::new(zx::MonotonicInstant::after(zx::Duration::from_nanos(
88 duration_ns,
89 )))
90 .await;
91 }
92 }
93}
94
95/// Shared proxy state behind one lock and cancellation token.
96#[derive(Debug)]
97pub struct ProxyState {
98 /// Session lifecycle and per-session policy.
99 pub sessions: SessionManager,
100 /// The shared read-path executor over the acquired MMIO mappings.
101 pub executor: Executor<LiveBackend, ZxClock>,
102 /// The instance audit ring.
103 pub audit: AuditRing,
104 /// Per-resource description digests, reported by `Describe` for
105 /// persistent grant matching.
106 pub resource_digests: std::collections::BTreeMap<u32, String>,
107 /// Interrupt manager coordinating interrupt observations.
108 pub interrupts: InterruptManager,
109 /// Structured configuration bounds.
110 pub config: lab_proxy_core::config::ProxyConfig,
111}
112
113/// Handle to the shared proxy state and cancellation token.
114pub struct SharedStateData {
115 pub inner: Mutex<ProxyState>,
116 pub abort_token: std::sync::atomic::AtomicBool,
117}
118
119pub type SharedState = Arc<SharedStateData>;
120
121fn now_ns() -> i64 {
122 zx::MonotonicInstant::get().into_nanos()
123}
124
125fn denial_to_fidl(denial: Denial) -> flab::OperationError {
126 match denial {
127 Denial::UnknownResource => flab::OperationError::UnknownResource,
128 Denial::UnsupportedWidth => flab::OperationError::UnsupportedWidth,
129 Denial::UnsupportedAccessClass => flab::OperationError::UnsupportedAccessClass,
130 Denial::Misaligned => flab::OperationError::Misaligned,
131 Denial::OffsetOverflow => flab::OperationError::OffsetOverflow,
132 Denial::OutOfLogicalBounds => flab::OperationError::OutOfLogicalBounds,
133 Denial::OutOfMappedBounds => flab::OperationError::OutOfMappedBounds,
134 Denial::NotPermittedByCeiling => flab::OperationError::NotPermittedByCeiling,
135 Denial::HardDenied => flab::OperationError::HardDenied,
136 Denial::UnknownReadsNotPermitted => flab::OperationError::UnknownReadsNotPermitted,
137 Denial::PollNotPermitted => flab::OperationError::PollNotPermitted,
138 Denial::NotInAllowlist => flab::OperationError::NotInAllowlist,
139 Denial::LimitExceeded => flab::OperationError::LimitExceeded,
140 Denial::StaleIdentity => flab::OperationError::StaleIdentity,
141 Denial::MutationLeaseContention => flab::OperationError::MutationLeaseContention,
142 Denial::NotAccepting => flab::OperationError::NotAccepting,
143 Denial::UnsupportedExpectation => flab::OperationError::UnsupportedExpectation,
144 Denial::PreconditionFailed => flab::OperationError::PreconditionFailed,
145 Denial::MissingPrecondition => flab::OperationError::MissingPrecondition,
146 Denial::Timeout => flab::OperationError::Timeout,
147 Denial::ReadOnlySession => flab::OperationError::ReadOnlySession,
148 Denial::WriteNotPermitted => flab::OperationError::WriteNotPermitted,
149 Denial::UnsupportedMethod => flab::OperationError::UnsupportedMethod,
150 Denial::TransferTooLarge => flab::OperationError::TransferTooLarge,
151 }
152}
153
154fn open_error_to_fidl(error: &OpenError) -> flab::OpenSessionError {
155 match error {
156 OpenError::NotAccepting => flab::OpenSessionError::NotAccepting,
157 OpenError::StaleBootId => flab::OpenSessionError::StaleBootId,
158 OpenError::StaleProxyGeneration => flab::OpenSessionError::StaleProxyGeneration,
159 OpenError::StaleResourceDigest => flab::OpenSessionError::StaleResourceDigest,
160 OpenError::StalePolicyDigest => flab::OpenSessionError::StalePolicyDigest,
161 OpenError::RejectedAllowlist { .. } => flab::OpenSessionError::RejectedAllowlist,
162 OpenError::MutationLeaseHeld | OpenError::MutationNotPermitted => {
163 flab::OpenSessionError::MutationLeaseHeld
164 }
165 OpenError::UnsupportedExpectation => flab::OpenSessionError::UnsupportedExpectation,
166 }
167}
168
169fn open_error_denial(error: &OpenError) -> Denial {
170 match error {
171 OpenError::NotAccepting => Denial::NotAccepting,
172 OpenError::StaleBootId
173 | OpenError::StaleProxyGeneration
174 | OpenError::StaleResourceDigest
175 | OpenError::StalePolicyDigest => Denial::StaleIdentity,
176 OpenError::RejectedAllowlist { denial, .. } => *denial,
177 OpenError::MutationLeaseHeld => Denial::MutationLeaseContention,
178 OpenError::MutationNotPermitted => Denial::NotPermittedByCeiling,
179 OpenError::UnsupportedExpectation => Denial::UnsupportedExpectation,
180 }
181}
182
183fn describe(state: &SharedState) -> flab::ProxyDescription {
184 let state = state.inner.lock().unwrap();
185 let identity = state.sessions.identity();
186 let resources: Vec<flab::ResourceDescription> = state
187 .sessions
188 .resources()
189 .iter()
190 .map(|(id, resource)| flab::ResourceDescription {
191 id: Some(*id),
192 name: Some(resource.name.clone()),
193 kind: Some(match resource.kind {
194 lab_proxy_core::access_policy::ResourceKind::Mmio => flab::ResourceKind::Mmio,
195 lab_proxy_core::access_policy::ResourceKind::Gpio => flab::ResourceKind::Gpio,
196 lab_proxy_core::access_policy::ResourceKind::I2c => flab::ResourceKind::I2C,
197 lab_proxy_core::access_policy::ResourceKind::Spi => flab::ResourceKind::Spi,
198 lab_proxy_core::access_policy::ResourceKind::Interrupt => {
199 flab::ResourceKind::Interrupt
200 }
201 lab_proxy_core::access_policy::ResourceKind::Clock => flab::ResourceKind::Clock,
202 lab_proxy_core::access_policy::ResourceKind::Reset => flab::ResourceKind::Reset,
203 lab_proxy_core::access_policy::ResourceKind::Serial => flab::ResourceKind::Serial,
204 }),
205 logical_size: Some(resource.logical_size),
206 digest: state.resource_digests.get(id).cloned(),
207 ..Default::default()
208 })
209 .collect();
210 flab::ProxyDescription {
211 protocol_major: Some(PROTOCOL_MAJOR),
212 protocol_minor: Some(PROTOCOL_MINOR),
213 proxy_generation: Some(identity.proxy_generation),
214 boot_id: Some(identity.boot_id.clone()),
215 resource_digest: Some(identity.resource_digest.clone()),
216 policy_digest: Some(identity.policy_digest.clone()),
217 resources: Some(resources),
218 max_snapshot_items: Some(state.executor.limits().max_snapshot_items as u32),
219 audit_capacity: Some(state.audit.capacity() as u64),
220 // Phase 1 never activates takeover; node_moniker and
221 // topology_generation stay absent until the proxy binds to a
222 // real node.
223 takeover: Some(flab::TakeoverState::NotActive),
224 ..Default::default()
225 }
226}
227
228fn open_session(
229 state: &SharedState,
230 context: flab::RunContext,
231 mode: flab::SessionMode,
232 expectations: flab::Expectations,
233 allowlist: Vec<flab::AccessRule>,
234) -> Result<u64, OpenError> {
235 let context = RunContext {
236 run_id: context.run_id.unwrap_or_default(),
237 case_id: context.case_id.unwrap_or_default(),
238 plan_digest: context.plan_digest.unwrap_or_default(),
239 host_tool_version: context.host_tool_version.unwrap_or_default(),
240 };
241 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
242 let mut state = state.inner.lock().unwrap();
243 state.audit.append(AuditRecord {
244 session: None,
245 resource: None,
246 operation: "open_session",
247 offset: None,
248 decision: Decision::Denied(Denial::NotAccepting),
249 status: OpStatus::Rejected,
250 value: None,
251 timestamp_ns: now_ns(),
252 run_id: Some(context.run_id),
253 item_index: None,
254 });
255 return Err(OpenError::NotAccepting);
256 }
257 let mode = match mode {
258 flab::SessionMode::ReadOnly => SessionMode::ReadOnly,
259 flab::SessionMode::Mutating => SessionMode::Mutating,
260 };
261 // Reserved phase 2 expectations fail closed rather than being
262 // silently ignored.
263 if expectations.topology_generation.is_some() || expectations.bound_driver_url.is_some() {
264 let mut state = state.inner.lock().unwrap();
265 state.audit.append(AuditRecord {
266 session: None,
267 resource: None,
268 operation: "open_session",
269 offset: None,
270 decision: Decision::Denied(Denial::UnsupportedExpectation),
271 status: OpStatus::Rejected,
272 value: None,
273 timestamp_ns: now_ns(),
274 run_id: Some(context.run_id),
275 item_index: None,
276 });
277 return Err(OpenError::UnsupportedExpectation);
278 }
279 // A required expectation the host omitted can never match the real
280 // identity, so absence falls through to the per-field stale check.
281 let expectations = ProxyIdentity {
282 boot_id: expectations.boot_id.unwrap_or_default(),
283 proxy_generation: expectations.proxy_generation.unwrap_or_default(),
284 resource_digest: expectations.resource_digest.unwrap_or_default(),
285 policy_digest: expectations.policy_digest.unwrap_or_default(),
286 };
287 let rules: Vec<AccessRule> = allowlist
288 .iter()
289 .map(|rule| AccessRule {
290 resource: rule.resource,
291 offset: rule.offset,
292 width: rule.width,
293 class: match rule.class {
294 flab::AccessClass::ReadOnce => AccessClass::ReadOnce,
295 flab::AccessClass::Snapshot => AccessClass::Snapshot,
296 flab::AccessClass::Write => AccessClass::Write,
297 flab::AccessClass::Poll => AccessClass::Poll,
298 flab::AccessClass::Sequence => AccessClass::Sequence,
299 flab::AccessClass::Protocol => AccessClass::Protocol,
300 flab::AccessClass::Interrupt => AccessClass::Interrupt,
301 },
302 })
303 .collect();
304
305 let mut state = state.inner.lock().unwrap();
306 let run_id = context.run_id.clone();
307 let result = state.sessions.open_session(context, mode, &expectations, rules);
308 let record = match &result {
309 Ok(id) => AuditRecord {
310 session: Some(*id),
311 resource: None,
312 operation: "open_session",
313 offset: None,
314 decision: Decision::Allowed,
315 status: OpStatus::Ok,
316 value: None,
317 timestamp_ns: now_ns(),
318 run_id: Some(run_id),
319 item_index: None,
320 },
321 Err(error) => {
322 // A rejected allowlist records the first offending rule, as
323 // the wire contract documents.
324 let (resource, offset) = match error {
325 OpenError::RejectedAllowlist { rule, .. } => {
326 (Some(rule.resource), Some(rule.offset))
327 }
328 _ => (None, None),
329 };
330 AuditRecord {
331 session: None,
332 resource,
333 operation: "open_session",
334 offset,
335 decision: Decision::Denied(open_error_denial(error)),
336 status: OpStatus::Rejected,
337 value: None,
338 timestamp_ns: now_ns(),
339 run_id: Some(run_id),
340 item_index: None,
341 }
342 }
343 };
344 state.audit.append(record);
345 if let Ok(id) = &result {
346 if mode == SessionMode::Mutating {
347 let mut q_record = AuditRecord::lifecycle("quiesce_engaged", now_ns());
348 q_record.session = Some(*id);
349 state.audit.append(q_record);
350 }
351 }
352 result
353}
354
355/// Serves one `Proxy` connection, spawning a task per opened
356/// session on `scope`.
357pub async fn serve_proxy(
358 state: SharedState,
359 scope: ScopeHandle,
360 mut stream: flab::Proxy_RequestStream,
361) {
362 while let Ok(Some(request)) = stream.try_next().await {
363 match request {
364 flab::Proxy_Request::Describe { responder } => {
365 let description = describe(&state);
366 let _ = responder.send(&description);
367 }
368 flab::Proxy_Request::OpenSession {
369 context,
370 mode,
371 expectations,
372 allowlist,
373 session,
374 responder,
375 } => match open_session(&state, context, mode, expectations, allowlist) {
376 Ok(id) => {
377 scope.spawn(serve_session(
378 state.clone(),
379 id,
380 session.into_stream(),
381 scope.clone(),
382 ));
383 let _ = responder.send(Ok(id));
384 }
385 Err(error) => {
386 let _ = responder.send(Err(open_error_to_fidl(&error)));
387 }
388 },
389 flab::Proxy_Request::_UnknownMethod { .. } => {}
390 }
391 }
392}
393
394async fn serve_session(
395 state: SharedState,
396 id: u64,
397 mut stream: flab::SessionRequestStream,
398 scope: ScopeHandle,
399) {
400 while let Ok(Some(request)) = stream.try_next().await {
401 match request {
402 flab::SessionRequest::Read32 { resource, offset, responder } => {
403 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
404 let _ = responder.send(Err(flab::OperationError::NotAccepting));
405 continue;
406 }
407 let result = {
408 let guard = &mut *state.inner.lock().unwrap();
409 let ProxyState { sessions, executor, audit, .. } = guard;
410 let check = match sessions.session(id) {
411 None => Err(flab::OperationError::StaleIdentity),
412 Some(session) => session
413 .policy
414 .check_read32(resource, offset, AccessClass::ReadOnce)
415 .map_err(denial_to_fidl),
416 };
417 match check {
418 Err(flab::OperationError::StaleIdentity) => {
419 Err(flab::OperationError::StaleIdentity)
420 }
421 Err(_) => {
422 let session = sessions.session(id).unwrap();
423 executor
424 .read32(&session.policy, audit, id, resource, offset)
425 .map(|outcome| {
426 (outcome.value, outcome.audit_seq, outcome.timestamp_ns)
427 })
428 .map_err(|error| match error {
429 ReadError::Denied { denial, .. } => denial_to_fidl(denial),
430 ReadError::Backend { .. } => flab::OperationError::BackendFault,
431 })
432 }
433 Ok(()) => {
434 let now = now_ns();
435 match sessions.check_access(id, AccessClass::ReadOnce, now) {
436 Err(denial) => {
437 let record = AuditRecord {
438 session: Some(id),
439 resource: Some(resource),
440 operation: "read32",
441 offset: Some(offset),
442 decision: Decision::Denied(denial),
443 status: OpStatus::Rejected,
444 value: None,
445 timestamp_ns: now,
446 run_id: None,
447 item_index: None,
448 };
449 audit.append(record);
450 Err(denial_to_fidl(denial))
451 }
452 Ok(()) => {
453 let session = sessions.session(id).unwrap();
454 executor
455 .read32(&session.policy, audit, id, resource, offset)
456 .map(|outcome| {
457 (outcome.value, outcome.audit_seq, outcome.timestamp_ns)
458 })
459 .map_err(|error| match error {
460 ReadError::Denied { denial, .. } => {
461 denial_to_fidl(denial)
462 }
463 ReadError::Backend { .. } => {
464 flab::OperationError::BackendFault
465 }
466 })
467 }
468 }
469 }
470 }
471 };
472 let _ = responder.send(result);
473 }
474 flab::SessionRequest::Snapshot { items, responder } => {
475 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
476 let _ = responder.send(Err(flab::OperationError::NotAccepting));
477 continue;
478 }
479 let items: Vec<SnapshotItem> = items
480 .iter()
481 .map(|item| SnapshotItem { resource: item.resource, offset: item.offset })
482 .collect();
483 let result = {
484 let guard = &mut *state.inner.lock().unwrap();
485 let ProxyState { sessions, executor, audit, .. } = guard;
486 if sessions.session(id).is_none() {
487 Err(flab::OperationError::StaleIdentity)
488 } else {
489 let now = now_ns();
490 match sessions.check_access(id, AccessClass::Snapshot, now) {
491 Err(denial) => {
492 let record = AuditRecord {
493 session: Some(id),
494 resource: None,
495 operation: "snapshot",
496 offset: None,
497 decision: Decision::Denied(denial),
498 status: OpStatus::Rejected,
499 value: None,
500 timestamp_ns: now,
501 run_id: None,
502 item_index: None,
503 };
504 audit.append(record);
505 Err(denial_to_fidl(denial))
506 }
507 Ok(()) => {
508 let session = sessions.session(id).unwrap();
509 executor
510 .snapshot(&session.policy, audit, id, &items)
511 .map(|outcome| {
512 let results: Vec<flab::SnapshotItemResult> = outcome
513 .results
514 .iter()
515 .map(|result| flab::SnapshotItemResult {
516 item: flab::SnapshotItem {
517 resource: result.item.resource,
518 offset: result.item.offset,
519 },
520 ok: result.value.is_ok(),
521 value: result.value.unwrap_or(0),
522 audit_seq: result.audit_seq,
523 timestamp_ns: result.timestamp_ns,
524 })
525 .collect();
526 (results, outcome.complete)
527 })
528 .map_err(|error| match error {
529 SnapshotError::TooManyItems { .. } => {
530 flab::OperationError::LimitExceeded
531 }
532 SnapshotError::Rejected { denial, .. } => {
533 denial_to_fidl(denial)
534 }
535 })
536 }
537 }
538 }
539 };
540 let _ = responder.send(
541 result
542 .as_ref()
543 .map(|(results, complete)| (results.as_slice(), *complete))
544 .map_err(|error| *error),
545 );
546 }
547 flab::SessionRequest::Write32 {
548 resource,
549 offset,
550 value,
551 write_mask,
552 precondition,
553 readback,
554 responder,
555 } => {
556 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
557 let _ = responder.send(Err(flab::OperationError::NotAccepting));
558 continue;
559 }
560 let precondition =
561 precondition.map(|p| WritePrecondition { expected: p.expected, mask: p.mask });
562 let result = {
563 let guard = &mut *state.inner.lock().unwrap();
564 let ProxyState { sessions, executor, audit, .. } = guard;
565 let check = match sessions.session(id) {
566 None => Err(flab::OperationError::StaleIdentity),
567 Some(session) => session
568 .policy
569 .check_write32(resource, offset, write_mask, precondition.as_ref())
570 .map_err(denial_to_fidl),
571 };
572 match check {
573 Err(flab::OperationError::StaleIdentity) => {
574 Err(flab::OperationError::StaleIdentity)
575 }
576 Err(_) => {
577 let session = sessions.session(id).unwrap();
578 executor
579 .write32(
580 &session.policy,
581 audit,
582 id,
583 resource,
584 offset,
585 value,
586 write_mask,
587 precondition,
588 readback,
589 )
590 .map(|outcome| {
591 (
592 outcome.readback_value,
593 outcome.audit_seq,
594 outcome.timestamp_ns,
595 )
596 })
597 .map_err(|error| match error {
598 WriteError::Denied { denial, .. } => denial_to_fidl(denial),
599 WriteError::Backend { .. } => {
600 flab::OperationError::BackendFault
601 }
602 })
603 }
604 Ok(_) => {
605 let now = now_ns();
606 match sessions.check_access(id, AccessClass::Write, now) {
607 Err(denial) => {
608 let record = AuditRecord {
609 session: Some(id),
610 resource: Some(resource),
611 operation: "write32",
612 offset: Some(offset),
613 decision: Decision::Denied(denial),
614 status: OpStatus::Rejected,
615 value: None,
616 timestamp_ns: now,
617 run_id: None,
618 item_index: None,
619 };
620 audit.append(record);
621 Err(denial_to_fidl(denial))
622 }
623 Ok(()) => {
624 let session = sessions.session(id).unwrap();
625 executor
626 .write32(
627 &session.policy,
628 audit,
629 id,
630 resource,
631 offset,
632 value,
633 write_mask,
634 precondition,
635 readback,
636 )
637 .map(|outcome| {
638 (
639 outcome.readback_value,
640 outcome.audit_seq,
641 outcome.timestamp_ns,
642 )
643 })
644 .map_err(|error| match error {
645 WriteError::Denied { denial, .. } => {
646 denial_to_fidl(denial)
647 }
648 WriteError::Backend { .. } => {
649 flab::OperationError::BackendFault
650 }
651 })
652 }
653 }
654 }
655 }
656 };
657 let _ = responder.send(result);
658 }
659 flab::SessionRequest::Poll32 {
660 resource,
661 offset,
662 expected,
663 mask,
664 interval_ns,
665 timeout_ns,
666 responder,
667 } => {
668 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
669 let _ = responder.send(Err(flab::OperationError::NotAccepting));
670 continue;
671 }
672 let start_ts = now_ns();
673 let deadline = start_ts.saturating_add(timeout_ns);
674
675 // Initial lock: validate session and policy.
676 let initial_check = {
677 let guard = &mut *state.inner.lock().unwrap();
678 let ProxyState { sessions, audit, .. } = guard;
679 match sessions.session(id) {
680 None => Err(flab::OperationError::StaleIdentity),
681 Some(session) => {
682 match session.policy.check_poll32(
683 resource,
684 offset,
685 mask,
686 interval_ns,
687 timeout_ns,
688 ) {
689 Ok(()) => {
690 if let Err(denial) = sessions.check_deadline(id, timeout_ns) {
691 let record = AuditRecord {
692 session: Some(id),
693 resource: Some(resource),
694 operation: "poll32",
695 offset: Some(offset),
696 decision: Decision::Denied(denial),
697 status: OpStatus::Rejected,
698 value: None,
699 timestamp_ns: now_ns(),
700 run_id: None,
701 item_index: None,
702 };
703 audit.append(record);
704 Err(denial_to_fidl(denial))
705 } else if let Err(denial) =
706 sessions.check_access(id, AccessClass::Poll, now_ns())
707 {
708 let record = AuditRecord {
709 session: Some(id),
710 resource: Some(resource),
711 operation: "poll32",
712 offset: Some(offset),
713 decision: Decision::Denied(denial),
714 status: OpStatus::Rejected,
715 value: None,
716 timestamp_ns: now_ns(),
717 run_id: None,
718 item_index: None,
719 };
720 audit.append(record);
721 Err(denial_to_fidl(denial))
722 } else {
723 Ok(())
724 }
725 }
726 Err(denial) => {
727 let record = AuditRecord {
728 session: Some(id),
729 resource: Some(resource),
730 operation: "poll32",
731 offset: Some(offset),
732 decision: Decision::Denied(denial),
733 status: OpStatus::Rejected,
734 value: None,
735 timestamp_ns: now_ns(),
736 run_id: None,
737 item_index: None,
738 };
739 audit.append(record);
740 Err(denial_to_fidl(denial))
741 }
742 }
743 }
744 }
745 };
746
747 if let Err(err) = initial_check {
748 let _ = responder.send(Err(err));
749 continue;
750 }
751
752 let mut last_val = None;
753 let poll_res = loop {
754 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
755 break Err(flab::OperationError::NotAccepting);
756 }
757 // Lock to perform one read step
758 let step_res = {
759 let guard = &mut *state.inner.lock().unwrap();
760 let ProxyState { sessions, executor, audit, .. } = guard;
761 match sessions.session(id) {
762 None => Err(flab::OperationError::StaleIdentity),
763 Some(_) => match executor
764 .poll32_read_step(audit, id, resource, offset, expected, mask, None)
765 {
766 Ok(Ok(outcome)) => Ok(Some(outcome)),
767 Ok(Err(val)) => {
768 last_val = Some(val);
769 Ok(None)
770 }
771 Err(PollError::Denied { denial, .. }) => {
772 Err(denial_to_fidl(denial))
773 }
774 Err(PollError::Backend { .. }) => {
775 Err(flab::OperationError::BackendFault)
776 }
777 },
778 }
779 };
780
781 match step_res {
782 Err(err) => break Err(err),
783 Ok(Some(outcome)) => {
784 break Ok((outcome.value, outcome.audit_seq, outcome.timestamp_ns));
785 }
786 Ok(None) => {
787 let now = now_ns();
788 if now >= deadline {
789 let guard = &mut *state.inner.lock().unwrap();
790 let ProxyState { sessions, executor, audit, .. } = guard;
791 if sessions.session(id).is_none() {
792 break Err(flab::OperationError::StaleIdentity);
793 } else {
794 executor.poll32_timeout(
795 audit, id, resource, offset, last_val, None,
796 );
797 break Err(flab::OperationError::Timeout);
798 }
799 }
800 let sleep_dur = if interval_ns > 0 {
801 let rem = deadline.saturating_sub(now);
802 interval_ns.min(rem)
803 } else {
804 0
805 };
806 if sleep_dur > 0 {
807 fuchsia_async::Timer::new(zx::MonotonicInstant::after(
808 zx::Duration::from_nanos(sleep_dur),
809 ))
810 .await;
811 } else {
812 fuchsia_async::Timer::new(zx::MonotonicInstant::after(
813 zx::Duration::from_nanos(1000),
814 ))
815 .await;
816 }
817 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
818 break Err(flab::OperationError::NotAccepting);
819 }
820 }
821 }
822 };
823
824 let _ = responder.send(poll_res);
825 }
826 flab::SessionRequest::ExecuteSequence { items, responder } => {
827 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
828 let _ = responder.send(Err(flab::OperationError::NotAccepting));
829 continue;
830 }
831 let mut core_items = Vec::with_capacity(items.len());
832 let mut unknown_item_index = None;
833 for (idx, item) in items.iter().enumerate() {
834 match fidl_to_core_sequence_item(item) {
835 Some(core_item) => core_items.push(core_item),
836 None => {
837 unknown_item_index = Some(idx);
838 break;
839 }
840 }
841 }
842
843 // Initial lock: whole-sequence prevalidation
844 let prevalidation = {
845 let guard = &mut *state.inner.lock().unwrap();
846 let ProxyState { sessions, executor, audit, .. } = guard;
847 match sessions.session(id) {
848 None => Err(flab::OperationError::StaleIdentity),
849 Some(session) => {
850 if let Some(idx) = unknown_item_index {
851 let record = AuditRecord {
852 session: Some(id),
853 resource: None,
854 operation: "sequence",
855 offset: None,
856 decision: Decision::Denied(Denial::UnsupportedAccessClass),
857 status: OpStatus::Rejected,
858 value: None,
859 timestamp_ns: now_ns(),
860 run_id: None,
861 item_index: Some(idx as u32),
862 };
863 audit.append(record);
864 Err(flab::OperationError::UnsupportedAccessClass)
865 } else if core_items.len() > executor.limits().max_sequence_items {
866 let record = AuditRecord {
867 session: Some(id),
868 resource: None,
869 operation: "sequence",
870 offset: None,
871 decision: Decision::Denied(Denial::LimitExceeded),
872 status: OpStatus::Rejected,
873 value: None,
874 timestamp_ns: now_ns(),
875 run_id: None,
876 item_index: None,
877 };
878 audit.append(record);
879 Err(flab::OperationError::LimitExceeded)
880 } else {
881 match executor.prevalidate_sequence(&session.policy, &core_items) {
882 Ok(()) => {
883 let now = now_ns();
884 match sessions.check_access(id, AccessClass::Sequence, now)
885 {
886 Err(denial) => {
887 let record = AuditRecord {
888 session: Some(id),
889 resource: None,
890 operation: "sequence",
891 offset: None,
892 decision: Decision::Denied(denial),
893 status: OpStatus::Rejected,
894 value: None,
895 timestamp_ns: now,
896 run_id: None,
897 item_index: None,
898 };
899 audit.append(record);
900 Err(denial_to_fidl(denial))
901 }
902 Ok(()) => Ok(()),
903 }
904 }
905 Err((idx, denial)) => {
906 let record = AuditRecord {
907 session: Some(id),
908 resource: None,
909 operation: "sequence",
910 offset: None,
911 decision: Decision::Denied(denial),
912 status: OpStatus::Rejected,
913 value: None,
914 timestamp_ns: now_ns(),
915 run_id: None,
916 item_index: Some(idx as u32),
917 };
918 audit.append(record);
919 Err(denial_to_fidl(denial))
920 }
921 }
922 }
923 }
924 }
925 };
926
927 if let Err(err) = prevalidation {
928 let _ = responder.send(Err(err));
929 continue;
930 }
931
932 // Sequence execution loop
933 let seq_start_ts = now_ns();
934 let mut results = Vec::with_capacity(core_items.len());
935 let mut complete = true;
936
937 for (index, item) in core_items.iter().enumerate() {
938 let idx = index as u32;
939
940 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
941 results.push(flab::SequenceItemResult {
942 index: idx,
943 ok: false,
944 outcome: flab::SequenceItemOutcome::Error(
945 flab::OperationError::NotAccepting,
946 ),
947 });
948 complete = false;
949 break;
950 }
951
952 let max_sequence_duration = {
953 let guard = state.inner.lock().unwrap();
954 guard.config.max_sequence_duration_ns as i64
955 };
956 if now_ns().saturating_sub(seq_start_ts) > max_sequence_duration {
957 let guard = &mut *state.inner.lock().unwrap();
958 let ProxyState { audit, .. } = guard;
959 let record = AuditRecord {
960 session: Some(id),
961 resource: None,
962 operation: "sequence",
963 offset: None,
964 decision: Decision::Denied(Denial::Timeout),
965 status: OpStatus::Rejected,
966 value: None,
967 timestamp_ns: now_ns(),
968 run_id: None,
969 item_index: Some(idx),
970 };
971 audit.append(record);
972 results.push(flab::SequenceItemResult {
973 index: idx,
974 ok: false,
975 outcome: flab::SequenceItemOutcome::Error(
976 flab::OperationError::Timeout,
977 ),
978 });
979 complete = false;
980 break;
981 }
982
983 match item {
984 CoreSequenceItem::Read32 { resource, offset } => {
985 let step = {
986 let guard = &mut *state.inner.lock().unwrap();
987 let ProxyState { sessions, executor, audit, .. } = guard;
988 match sessions.session(id) {
989 None => Err(flab::OperationError::StaleIdentity),
990 Some(session) => match executor.read32_internal(
991 &session.policy,
992 audit,
993 id,
994 *resource,
995 *offset,
996 Some(idx),
997 ) {
998 Ok(outcome) => Ok(flab::SequenceItemResult {
999 index: idx,
1000 ok: true,
1001 outcome: flab::SequenceItemOutcome::Read32(
1002 flab::ReadResult {
1003 value: outcome.value,
1004 audit_seq: outcome.audit_seq,
1005 timestamp_ns: outcome.timestamp_ns,
1006 },
1007 ),
1008 }),
1009 Err(ReadError::Denied { denial, .. }) => {
1010 Err(denial_to_fidl(denial))
1011 }
1012 Err(ReadError::Backend { .. }) => {
1013 Err(flab::OperationError::BackendFault)
1014 }
1015 },
1016 }
1017 };
1018 match step {
1019 Ok(res) => results.push(res),
1020 Err(err) => {
1021 results.push(flab::SequenceItemResult {
1022 index: idx,
1023 ok: false,
1024 outcome: flab::SequenceItemOutcome::Error(err),
1025 });
1026 complete = false;
1027 break;
1028 }
1029 }
1030 }
1031 CoreSequenceItem::Write32 {
1032 resource,
1033 offset,
1034 value,
1035 write_mask,
1036 precondition,
1037 readback,
1038 } => {
1039 let step = {
1040 let guard = &mut *state.inner.lock().unwrap();
1041 let ProxyState { sessions, executor, audit, .. } = guard;
1042 match sessions.session(id) {
1043 None => Err(flab::OperationError::StaleIdentity),
1044 Some(session) => match executor.write32_internal(
1045 &session.policy,
1046 audit,
1047 id,
1048 *resource,
1049 *offset,
1050 *value,
1051 *write_mask,
1052 *precondition,
1053 *readback,
1054 Some(idx),
1055 ) {
1056 Ok(outcome) => Ok(flab::SequenceItemResult {
1057 index: idx,
1058 ok: true,
1059 outcome: flab::SequenceItemOutcome::Write32(
1060 flab::WriteResult {
1061 readback_value: outcome.readback_value,
1062 audit_seq: outcome.audit_seq,
1063 timestamp_ns: outcome.timestamp_ns,
1064 },
1065 ),
1066 }),
1067 Err(WriteError::Denied { denial, .. }) => {
1068 Err(denial_to_fidl(denial))
1069 }
1070 Err(WriteError::Backend { .. }) => {
1071 Err(flab::OperationError::BackendFault)
1072 }
1073 },
1074 }
1075 };
1076 match step {
1077 Ok(res) => results.push(res),
1078 Err(err) => {
1079 results.push(flab::SequenceItemResult {
1080 index: idx,
1081 ok: false,
1082 outcome: flab::SequenceItemOutcome::Error(err),
1083 });
1084 complete = false;
1085 break;
1086 }
1087 }
1088 }
1089 CoreSequenceItem::Barrier => {
1090 let step = {
1091 let guard = &mut *state.inner.lock().unwrap();
1092 let ProxyState { sessions, executor, audit, .. } = guard;
1093 match sessions.session(id) {
1094 None => Err(flab::OperationError::StaleIdentity),
1095 Some(_) => {
1096 let ts = now_ns();
1097 executor.barrier();
1098 let record = AuditRecord {
1099 session: Some(id),
1100 resource: None,
1101 operation: "barrier",
1102 offset: None,
1103 decision: Decision::Allowed,
1104 status: OpStatus::Ok,
1105 value: None,
1106 timestamp_ns: ts,
1107 run_id: None,
1108 item_index: Some(idx),
1109 };
1110 audit.append(record);
1111 Ok(flab::SequenceItemResult {
1112 index: idx,
1113 ok: true,
1114 outcome: flab::SequenceItemOutcome::Barrier(
1115 flab::Barrier,
1116 ),
1117 })
1118 }
1119 }
1120 };
1121 match step {
1122 Ok(res) => results.push(res),
1123 Err(err) => {
1124 results.push(flab::SequenceItemResult {
1125 index: idx,
1126 ok: false,
1127 outcome: flab::SequenceItemOutcome::Error(err),
1128 });
1129 complete = false;
1130 break;
1131 }
1132 }
1133 }
1134 CoreSequenceItem::DelayNs(delay_ns) => {
1135 if *delay_ns > 0 {
1136 fuchsia_async::Timer::new(zx::MonotonicInstant::after(
1137 zx::Duration::from_nanos(*delay_ns),
1138 ))
1139 .await;
1140 }
1141 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1142 results.push(flab::SequenceItemResult {
1143 index: idx,
1144 ok: false,
1145 outcome: flab::SequenceItemOutcome::Error(
1146 flab::OperationError::NotAccepting,
1147 ),
1148 });
1149 complete = false;
1150 break;
1151 }
1152 let step = {
1153 let guard = &mut *state.inner.lock().unwrap();
1154 let ProxyState { sessions, audit, .. } = guard;
1155 match sessions.session(id) {
1156 None => Err(flab::OperationError::StaleIdentity),
1157 Some(_) => {
1158 let ts = now_ns();
1159 let record = AuditRecord {
1160 session: Some(id),
1161 resource: None,
1162 operation: "delay",
1163 offset: None,
1164 decision: Decision::Allowed,
1165 status: OpStatus::Ok,
1166 value: None,
1167 timestamp_ns: ts,
1168 run_id: None,
1169 item_index: Some(idx),
1170 };
1171 audit.append(record);
1172 Ok(flab::SequenceItemResult {
1173 index: idx,
1174 ok: true,
1175 outcome: flab::SequenceItemOutcome::DelayNs(
1176 flab::DelayNs,
1177 ),
1178 })
1179 }
1180 }
1181 };
1182 match step {
1183 Ok(res) => results.push(res),
1184 Err(err) => {
1185 results.push(flab::SequenceItemResult {
1186 index: idx,
1187 ok: false,
1188 outcome: flab::SequenceItemOutcome::Error(err),
1189 });
1190 complete = false;
1191 break;
1192 }
1193 }
1194 }
1195 CoreSequenceItem::Poll32 {
1196 resource,
1197 offset,
1198 expected,
1199 mask,
1200 interval_ns,
1201 timeout_ns,
1202 } => {
1203 let start_ts = now_ns();
1204 let deadline = start_ts.saturating_add(*timeout_ns);
1205 let mut last_val = None;
1206 let poll_res = loop {
1207 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1208 break Err(flab::OperationError::NotAccepting);
1209 }
1210 if now_ns().saturating_sub(seq_start_ts) > max_sequence_duration {
1211 let guard = &mut *state.inner.lock().unwrap();
1212 let ProxyState { sessions, executor, audit, .. } = guard;
1213 if sessions.session(id).is_none() {
1214 break Err(flab::OperationError::StaleIdentity);
1215 } else {
1216 executor.poll32_timeout(
1217 audit,
1218 id,
1219 *resource,
1220 *offset,
1221 last_val,
1222 Some(idx),
1223 );
1224 break Err(flab::OperationError::Timeout);
1225 }
1226 }
1227 let step = {
1228 let guard = &mut *state.inner.lock().unwrap();
1229 let ProxyState { sessions, executor, audit, .. } = guard;
1230 match sessions.session(id) {
1231 None => Err(flab::OperationError::StaleIdentity),
1232 Some(_) => match executor.poll32_read_step(
1233 audit,
1234 id,
1235 *resource,
1236 *offset,
1237 *expected,
1238 *mask,
1239 Some(idx),
1240 ) {
1241 Ok(Ok(outcome)) => Ok(Some(outcome)),
1242 Ok(Err(val)) => {
1243 last_val = Some(val);
1244 Ok(None)
1245 }
1246 Err(PollError::Denied { denial, .. }) => {
1247 Err(denial_to_fidl(denial))
1248 }
1249 Err(PollError::Backend { .. }) => {
1250 Err(flab::OperationError::BackendFault)
1251 }
1252 },
1253 }
1254 };
1255 match step {
1256 Err(err) => break Err(err),
1257 Ok(Some(outcome)) => {
1258 break Ok(flab::SequenceItemResult {
1259 index: idx,
1260 ok: true,
1261 outcome: flab::SequenceItemOutcome::Poll32(
1262 flab::PollResult {
1263 value: outcome.value,
1264 audit_seq: outcome.audit_seq,
1265 timestamp_ns: outcome.timestamp_ns,
1266 },
1267 ),
1268 });
1269 }
1270 Ok(None) => {
1271 let now = now_ns();
1272 if now >= deadline {
1273 let guard = &mut *state.inner.lock().unwrap();
1274 let ProxyState { sessions, executor, audit, .. } =
1275 guard;
1276 if sessions.session(id).is_none() {
1277 break Err(flab::OperationError::StaleIdentity);
1278 } else {
1279 executor.poll32_timeout(
1280 audit,
1281 id,
1282 *resource,
1283 *offset,
1284 last_val,
1285 Some(idx),
1286 );
1287 break Err(flab::OperationError::Timeout);
1288 }
1289 }
1290 let sleep_dur = if *interval_ns > 0 {
1291 let rem = deadline.saturating_sub(now);
1292 (*interval_ns).min(rem)
1293 } else {
1294 0
1295 };
1296 if sleep_dur > 0 {
1297 fuchsia_async::Timer::new(zx::MonotonicInstant::after(
1298 zx::Duration::from_nanos(sleep_dur),
1299 ))
1300 .await;
1301 } else {
1302 fuchsia_async::Timer::new(zx::MonotonicInstant::after(
1303 zx::Duration::from_nanos(1000),
1304 ))
1305 .await;
1306 }
1307 if state
1308 .abort_token
1309 .load(std::sync::atomic::Ordering::SeqCst)
1310 {
1311 break Err(flab::OperationError::NotAccepting);
1312 }
1313 }
1314 }
1315 };
1316 match poll_res {
1317 Ok(res) => results.push(res),
1318 Err(err) => {
1319 results.push(flab::SequenceItemResult {
1320 index: idx,
1321 ok: false,
1322 outcome: flab::SequenceItemOutcome::Error(err),
1323 });
1324 complete = false;
1325 break;
1326 }
1327 }
1328 }
1329 CoreSequenceItem::GpioRead { resource } => {
1330 let step = {
1331 let guard = &mut *state.inner.lock().unwrap();
1332 let ProxyState { sessions, executor, audit, .. } = guard;
1333 match sessions.session(id) {
1334 None => Err(flab::OperationError::StaleIdentity),
1335 Some(session) => match executor.gpio_read_internal(
1336 &session.policy,
1337 audit,
1338 id,
1339 *resource,
1340 Some(idx),
1341 ) {
1342 Ok(outcome) => Ok(flab::SequenceItemResult {
1343 index: idx,
1344 ok: true,
1345 outcome: flab::SequenceItemOutcome::GpioRead(
1346 flab::GpioReadResult {
1347 value: outcome.value,
1348 audit_seq: outcome.audit_seq,
1349 timestamp_ns: outcome.timestamp_ns,
1350 },
1351 ),
1352 }),
1353 Err(GpioReadError::Denied { denial, .. }) => {
1354 Err(denial_to_fidl(denial))
1355 }
1356 Err(GpioReadError::Backend { .. }) => {
1357 Err(flab::OperationError::BackendFault)
1358 }
1359 },
1360 }
1361 };
1362 match step {
1363 Ok(res) => results.push(res),
1364 Err(err) => {
1365 results.push(flab::SequenceItemResult {
1366 index: idx,
1367 ok: false,
1368 outcome: flab::SequenceItemOutcome::Error(err),
1369 });
1370 complete = false;
1371 break;
1372 }
1373 }
1374 }
1375 CoreSequenceItem::GpioWrite { resource, value } => {
1376 let step = {
1377 let guard = &mut *state.inner.lock().unwrap();
1378 let ProxyState { sessions, executor, audit, .. } = guard;
1379 match sessions.session(id) {
1380 None => Err(flab::OperationError::StaleIdentity),
1381 Some(session) => match executor.gpio_write_internal(
1382 &session.policy,
1383 audit,
1384 id,
1385 *resource,
1386 *value,
1387 Some(idx),
1388 ) {
1389 Ok(outcome) => Ok(flab::SequenceItemResult {
1390 index: idx,
1391 ok: true,
1392 outcome: flab::SequenceItemOutcome::GpioWrite(
1393 flab::GpioWriteResult {
1394 audit_seq: outcome.audit_seq,
1395 timestamp_ns: outcome.timestamp_ns,
1396 },
1397 ),
1398 }),
1399 Err(GpioWriteError::Denied { denial, .. }) => {
1400 Err(denial_to_fidl(denial))
1401 }
1402 Err(GpioWriteError::Backend { .. }) => {
1403 Err(flab::OperationError::BackendFault)
1404 }
1405 },
1406 }
1407 };
1408 match step {
1409 Ok(res) => results.push(res),
1410 Err(err) => {
1411 results.push(flab::SequenceItemResult {
1412 index: idx,
1413 ok: false,
1414 outcome: flab::SequenceItemOutcome::Error(err),
1415 });
1416 complete = false;
1417 break;
1418 }
1419 }
1420 }
1421 CoreSequenceItem::I2cTransfer { resource, write_data, read_length } => {
1422 let step = {
1423 let guard = &mut *state.inner.lock().unwrap();
1424 let ProxyState { sessions, executor, audit, .. } = guard;
1425 match sessions.session(id) {
1426 None => Err(flab::OperationError::StaleIdentity),
1427 Some(session) => match executor.i2c_transfer_internal(
1428 &session.policy,
1429 audit,
1430 id,
1431 *resource,
1432 write_data,
1433 *read_length,
1434 Some(idx),
1435 ) {
1436 Ok(outcome) => Ok(flab::SequenceItemResult {
1437 index: idx,
1438 ok: true,
1439 outcome: flab::SequenceItemOutcome::I2cTransfer(
1440 flab::I2cTransferResult {
1441 read_data: outcome.read_data,
1442 audit_seq: outcome.audit_seq,
1443 timestamp_ns: outcome.timestamp_ns,
1444 },
1445 ),
1446 }),
1447 Err(I2cTransferError::Denied { denial, .. }) => {
1448 Err(denial_to_fidl(denial))
1449 }
1450 Err(I2cTransferError::Backend { .. }) => {
1451 Err(flab::OperationError::BackendFault)
1452 }
1453 },
1454 }
1455 };
1456 match step {
1457 Ok(res) => results.push(res),
1458 Err(err) => {
1459 results.push(flab::SequenceItemResult {
1460 index: idx,
1461 ok: false,
1462 outcome: flab::SequenceItemOutcome::Error(err),
1463 });
1464 complete = false;
1465 break;
1466 }
1467 }
1468 }
1469 CoreSequenceItem::SpiTransmit { resource, tx_data } => {
1470 let step = {
1471 let guard = &mut *state.inner.lock().unwrap();
1472 let ProxyState { sessions, executor, audit, .. } = guard;
1473 match sessions.session(id) {
1474 None => Err(flab::OperationError::StaleIdentity),
1475 Some(session) => match executor.spi_transmit_internal(
1476 &session.policy,
1477 audit,
1478 id,
1479 *resource,
1480 tx_data,
1481 Some(idx),
1482 ) {
1483 Ok(outcome) => Ok(flab::SequenceItemResult {
1484 index: idx,
1485 ok: true,
1486 outcome: flab::SequenceItemOutcome::SpiTransmit(
1487 flab::SpiTransmitResult {
1488 rx_data: outcome.rx_data,
1489 audit_seq: outcome.audit_seq,
1490 timestamp_ns: outcome.timestamp_ns,
1491 },
1492 ),
1493 }),
1494 Err(SpiTransmitError::Denied { denial, .. }) => {
1495 Err(denial_to_fidl(denial))
1496 }
1497 Err(SpiTransmitError::Backend { .. }) => {
1498 Err(flab::OperationError::BackendFault)
1499 }
1500 },
1501 }
1502 };
1503 match step {
1504 Ok(res) => results.push(res),
1505 Err(err) => {
1506 results.push(flab::SequenceItemResult {
1507 index: idx,
1508 ok: false,
1509 outcome: flab::SequenceItemOutcome::Error(err),
1510 });
1511 complete = false;
1512 break;
1513 }
1514 }
1515 }
1516 }
1517 }
1518
1519 let _ = responder.send(Ok((results.as_slice(), complete)));
1520 }
1521 flab::SessionRequest::ReadAudit { cursor, limit, responder } => {
1522 let (page, boot_id, proxy_generation) = {
1523 let state = state.inner.lock().unwrap();
1524 let limit = (limit.min(flab::MAX_AUDIT_PAGE_ENTRIES)) as usize;
1525 let identity = state.sessions.identity();
1526 (
1527 state.audit.read(cursor, limit),
1528 identity.boot_id.clone(),
1529 identity.proxy_generation,
1530 )
1531 };
1532 let entries: Vec<flab::AuditEntry> = page
1533 .entries
1534 .iter()
1535 .map(|entry| flab::AuditEntry {
1536 seq: Some(entry.seq),
1537 session: entry.record.session,
1538 resource: entry.record.resource,
1539 operation: Some(entry.record.operation.to_string()),
1540 offset: entry.record.offset,
1541 decision: Some(match entry.record.decision {
1542 Decision::Allowed => flab::AuditDecision::Allowed,
1543 Decision::Denied(_) => flab::AuditDecision::Denied,
1544 }),
1545 denial: match entry.record.decision {
1546 Decision::Allowed => None,
1547 Decision::Denied(denial) => Some(denial_to_fidl(denial)),
1548 },
1549 status: Some(match entry.record.status {
1550 OpStatus::Ok => flab::AuditStatus::Ok,
1551 OpStatus::Rejected => flab::AuditStatus::Rejected,
1552 OpStatus::BackendFault => flab::AuditStatus::BackendFault,
1553 }),
1554 value: entry.record.value,
1555 timestamp_ns: Some(entry.record.timestamp_ns),
1556 run_id: entry.record.run_id.clone(),
1557 item_index: entry.record.item_index,
1558 proxy_generation: Some(proxy_generation),
1559 boot_id: Some(boot_id.clone()),
1560 ..Default::default()
1561 })
1562 .collect();
1563 let _ = responder.send(
1564 &entries,
1565 page.oldest_retained.is_some(),
1566 page.oldest_retained.unwrap_or(0),
1567 page.next_cursor,
1568 );
1569 }
1570 flab::SessionRequest::GpioRead { resource, responder } => {
1571 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1572 let _ = responder.send(Err(flab::OperationError::NotAccepting));
1573 continue;
1574 }
1575 let result = {
1576 let guard = &mut *state.inner.lock().unwrap();
1577 let ProxyState { sessions, executor, audit, .. } = guard;
1578 let check = match sessions.session(id) {
1579 None => Err(flab::OperationError::StaleIdentity),
1580 Some(session) => {
1581 session.policy.check_gpio_read(resource).map_err(denial_to_fidl)
1582 }
1583 };
1584 match check {
1585 Err(flab::OperationError::StaleIdentity) => {
1586 Err(flab::OperationError::StaleIdentity)
1587 }
1588 Err(_) => {
1589 let session = sessions.session(id).unwrap();
1590 executor
1591 .gpio_read(&session.policy, audit, id, resource)
1592 .map(|outcome| {
1593 (outcome.value, outcome.audit_seq, outcome.timestamp_ns)
1594 })
1595 .map_err(|error| match error {
1596 GpioReadError::Denied { denial, .. } => denial_to_fidl(denial),
1597 GpioReadError::Backend { .. } => {
1598 flab::OperationError::BackendFault
1599 }
1600 })
1601 }
1602 Ok(_) => {
1603 let now = now_ns();
1604 match sessions.check_access(id, AccessClass::Protocol, now) {
1605 Err(denial) => {
1606 let record = AuditRecord {
1607 session: Some(id),
1608 resource: Some(resource),
1609 operation: "gpio_read",
1610 offset: None,
1611 decision: Decision::Denied(denial),
1612 status: OpStatus::Rejected,
1613 value: None,
1614 timestamp_ns: now,
1615 run_id: None,
1616 item_index: None,
1617 };
1618 audit.append(record);
1619 Err(denial_to_fidl(denial))
1620 }
1621 Ok(()) => {
1622 let session = sessions.session(id).unwrap();
1623 executor
1624 .gpio_read(&session.policy, audit, id, resource)
1625 .map(|outcome| {
1626 (outcome.value, outcome.audit_seq, outcome.timestamp_ns)
1627 })
1628 .map_err(|error| match error {
1629 GpioReadError::Denied { denial, .. } => {
1630 denial_to_fidl(denial)
1631 }
1632 GpioReadError::Backend { .. } => {
1633 flab::OperationError::BackendFault
1634 }
1635 })
1636 }
1637 }
1638 }
1639 }
1640 };
1641 let _ = responder.send(result);
1642 }
1643 flab::SessionRequest::GpioWrite { resource, value, responder } => {
1644 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1645 let _ = responder.send(Err(flab::OperationError::NotAccepting));
1646 continue;
1647 }
1648 let result = {
1649 let guard = &mut *state.inner.lock().unwrap();
1650 let ProxyState { sessions, executor, audit, .. } = guard;
1651 let check = match sessions.session(id) {
1652 None => Err(flab::OperationError::StaleIdentity),
1653 Some(session) => {
1654 session.policy.check_gpio_write(resource).map_err(denial_to_fidl)
1655 }
1656 };
1657 match check {
1658 Err(flab::OperationError::StaleIdentity) => {
1659 Err(flab::OperationError::StaleIdentity)
1660 }
1661 Err(_) => {
1662 let session = sessions.session(id).unwrap();
1663 executor
1664 .gpio_write(&session.policy, audit, id, resource, value)
1665 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
1666 .map_err(|error| match error {
1667 GpioWriteError::Denied { denial, .. } => denial_to_fidl(denial),
1668 GpioWriteError::Backend { .. } => {
1669 flab::OperationError::BackendFault
1670 }
1671 })
1672 }
1673 Ok(_) => {
1674 let now = now_ns();
1675 match sessions.check_access(id, AccessClass::Protocol, now) {
1676 Err(denial) => {
1677 let record = AuditRecord {
1678 session: Some(id),
1679 resource: Some(resource),
1680 operation: "gpio_write",
1681 offset: None,
1682 decision: Decision::Denied(denial),
1683 status: OpStatus::Rejected,
1684 value: None,
1685 timestamp_ns: now,
1686 run_id: None,
1687 item_index: None,
1688 };
1689 audit.append(record);
1690 Err(denial_to_fidl(denial))
1691 }
1692 Ok(()) => {
1693 let session = sessions.session(id).unwrap();
1694 executor
1695 .gpio_write(&session.policy, audit, id, resource, value)
1696 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
1697 .map_err(|error| match error {
1698 GpioWriteError::Denied { denial, .. } => {
1699 denial_to_fidl(denial)
1700 }
1701 GpioWriteError::Backend { .. } => {
1702 flab::OperationError::BackendFault
1703 }
1704 })
1705 }
1706 }
1707 }
1708 }
1709 };
1710 let _ = responder.send(result);
1711 }
1712 flab::SessionRequest::I2cTransfer { resource, write_data, read_length, responder } => {
1713 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1714 let _ = responder.send(Err(flab::OperationError::NotAccepting));
1715 continue;
1716 }
1717 let result = {
1718 let guard = &mut *state.inner.lock().unwrap();
1719 let ProxyState { sessions, executor, audit, .. } = guard;
1720 let check = match sessions.session(id) {
1721 None => Err(flab::OperationError::StaleIdentity),
1722 Some(session) => session
1723 .policy
1724 .check_i2c_transfer(resource, write_data.len(), read_length as usize)
1725 .map_err(denial_to_fidl),
1726 };
1727 match check {
1728 Err(flab::OperationError::StaleIdentity) => {
1729 Err(flab::OperationError::StaleIdentity)
1730 }
1731 Err(_) => {
1732 let session = sessions.session(id).unwrap();
1733 executor
1734 .i2c_transfer(
1735 &session.policy,
1736 audit,
1737 id,
1738 resource,
1739 &write_data,
1740 read_length,
1741 )
1742 .map(|outcome| {
1743 (outcome.read_data, outcome.audit_seq, outcome.timestamp_ns)
1744 })
1745 .map_err(|error| match error {
1746 I2cTransferError::Denied { denial, .. } => {
1747 denial_to_fidl(denial)
1748 }
1749 I2cTransferError::Backend { .. } => {
1750 flab::OperationError::BackendFault
1751 }
1752 })
1753 }
1754 Ok(_) => {
1755 let now = now_ns();
1756 match sessions.check_access(id, AccessClass::Protocol, now) {
1757 Err(denial) => {
1758 let record = AuditRecord {
1759 session: Some(id),
1760 resource: Some(resource),
1761 operation: "i2c_transfer",
1762 offset: None,
1763 decision: Decision::Denied(denial),
1764 status: OpStatus::Rejected,
1765 value: None,
1766 timestamp_ns: now,
1767 run_id: None,
1768 item_index: None,
1769 };
1770 audit.append(record);
1771 Err(denial_to_fidl(denial))
1772 }
1773 Ok(()) => {
1774 let session = sessions.session(id).unwrap();
1775 executor
1776 .i2c_transfer(
1777 &session.policy,
1778 audit,
1779 id,
1780 resource,
1781 &write_data,
1782 read_length,
1783 )
1784 .map(|outcome| {
1785 (
1786 outcome.read_data,
1787 outcome.audit_seq,
1788 outcome.timestamp_ns,
1789 )
1790 })
1791 .map_err(|error| match error {
1792 I2cTransferError::Denied { denial, .. } => {
1793 denial_to_fidl(denial)
1794 }
1795 I2cTransferError::Backend { .. } => {
1796 flab::OperationError::BackendFault
1797 }
1798 })
1799 }
1800 }
1801 }
1802 }
1803 };
1804 let _ = responder.send(
1805 result
1806 .as_ref()
1807 .map(|(data, seq, ts)| (data.as_slice(), *seq, *ts))
1808 .map_err(|err| *err),
1809 );
1810 }
1811 flab::SessionRequest::SpiTransmit { resource, tx_data, responder } => {
1812 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1813 let _ = responder.send(Err(flab::OperationError::NotAccepting));
1814 continue;
1815 }
1816 let result = {
1817 let guard = &mut *state.inner.lock().unwrap();
1818 let ProxyState { sessions, executor, audit, .. } = guard;
1819 let check = match sessions.session(id) {
1820 None => Err(flab::OperationError::StaleIdentity),
1821 Some(session) => session
1822 .policy
1823 .check_spi_transmit(resource, tx_data.len())
1824 .map_err(denial_to_fidl),
1825 };
1826 match check {
1827 Err(flab::OperationError::StaleIdentity) => {
1828 Err(flab::OperationError::StaleIdentity)
1829 }
1830 Err(_) => {
1831 let session = sessions.session(id).unwrap();
1832 executor
1833 .spi_transmit(&session.policy, audit, id, resource, &tx_data)
1834 .map(|outcome| {
1835 (outcome.rx_data, outcome.audit_seq, outcome.timestamp_ns)
1836 })
1837 .map_err(|error| match error {
1838 SpiTransmitError::Denied { denial, .. } => {
1839 denial_to_fidl(denial)
1840 }
1841 SpiTransmitError::Backend { .. } => {
1842 flab::OperationError::BackendFault
1843 }
1844 })
1845 }
1846 Ok(_) => {
1847 let now = now_ns();
1848 match sessions.check_access(id, AccessClass::Protocol, now) {
1849 Err(denial) => {
1850 let record = AuditRecord {
1851 session: Some(id),
1852 resource: Some(resource),
1853 operation: "spi_transmit",
1854 offset: None,
1855 decision: Decision::Denied(denial),
1856 status: OpStatus::Rejected,
1857 value: None,
1858 timestamp_ns: now,
1859 run_id: None,
1860 item_index: None,
1861 };
1862 audit.append(record);
1863 Err(denial_to_fidl(denial))
1864 }
1865 Ok(()) => {
1866 let session = sessions.session(id).unwrap();
1867 executor
1868 .spi_transmit(
1869 &session.policy,
1870 audit,
1871 id,
1872 resource,
1873 &tx_data,
1874 )
1875 .map(|outcome| {
1876 (
1877 outcome.rx_data,
1878 outcome.audit_seq,
1879 outcome.timestamp_ns,
1880 )
1881 })
1882 .map_err(|error| match error {
1883 SpiTransmitError::Denied { denial, .. } => {
1884 denial_to_fidl(denial)
1885 }
1886 SpiTransmitError::Backend { .. } => {
1887 flab::OperationError::BackendFault
1888 }
1889 })
1890 }
1891 }
1892 }
1893 }
1894 };
1895 let _ = responder.send(
1896 result
1897 .as_ref()
1898 .map(|(data, seq, ts)| (data.as_slice(), *seq, *ts))
1899 .map_err(|err| *err),
1900 );
1901 }
1902 flab::SessionRequest::OpenGpio { resource, endpoint, responder } => {
1903 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1904 let _ = responder.send(Err(flab::OperationError::NotAccepting));
1905 continue;
1906 }
1907 let check = {
1908 let guard = state.inner.lock().unwrap();
1909 match guard.sessions.session(id) {
1910 None => Err(flab::OperationError::StaleIdentity),
1911 Some(session) => match session.policy.resource(resource) {
1912 None => Err(flab::OperationError::UnknownResource),
1913 Some(res) => {
1914 if res.kind != lab_proxy_core::access_policy::ResourceKind::Gpio {
1915 Err(flab::OperationError::UnsupportedMethod)
1916 } else {
1917 Ok(())
1918 }
1919 }
1920 },
1921 }
1922 };
1923 match check {
1924 Ok(()) => {
1925 scope.spawn(serve_gpio_endpoint(
1926 state.clone(),
1927 id,
1928 resource,
1929 endpoint.into_stream(),
1930 ));
1931 let _ = responder.send(Ok(()));
1932 }
1933 Err(err) => {
1934 let _ = responder.send(Err(err));
1935 }
1936 }
1937 }
1938 flab::SessionRequest::OpenI2c { resource, endpoint, responder } => {
1939 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1940 let _ = responder.send(Err(flab::OperationError::NotAccepting));
1941 continue;
1942 }
1943 let check = {
1944 let guard = state.inner.lock().unwrap();
1945 match guard.sessions.session(id) {
1946 None => Err(flab::OperationError::StaleIdentity),
1947 Some(session) => match session.policy.resource(resource) {
1948 None => Err(flab::OperationError::UnknownResource),
1949 Some(res) => {
1950 if res.kind != lab_proxy_core::access_policy::ResourceKind::I2c {
1951 Err(flab::OperationError::UnsupportedMethod)
1952 } else {
1953 Ok(())
1954 }
1955 }
1956 },
1957 }
1958 };
1959 match check {
1960 Ok(()) => {
1961 scope.spawn(serve_i2c_endpoint(
1962 state.clone(),
1963 id,
1964 resource,
1965 endpoint.into_stream(),
1966 ));
1967 let _ = responder.send(Ok(()));
1968 }
1969 Err(err) => {
1970 let _ = responder.send(Err(err));
1971 }
1972 }
1973 }
1974 flab::SessionRequest::OpenSpi { resource, endpoint, responder } => {
1975 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1976 let _ = responder.send(Err(flab::OperationError::NotAccepting));
1977 continue;
1978 }
1979 let check = {
1980 let guard = state.inner.lock().unwrap();
1981 match guard.sessions.session(id) {
1982 None => Err(flab::OperationError::StaleIdentity),
1983 Some(session) => match session.policy.resource(resource) {
1984 None => Err(flab::OperationError::UnknownResource),
1985 Some(res) => {
1986 if res.kind != lab_proxy_core::access_policy::ResourceKind::Spi {
1987 Err(flab::OperationError::UnsupportedMethod)
1988 } else {
1989 Ok(())
1990 }
1991 }
1992 },
1993 }
1994 };
1995 match check {
1996 Ok(()) => {
1997 scope.spawn(serve_spi_endpoint(
1998 state.clone(),
1999 id,
2000 resource,
2001 endpoint.into_stream(),
2002 ));
2003 let _ = responder.send(Ok(()));
2004 }
2005 Err(err) => {
2006 let _ = responder.send(Err(err));
2007 }
2008 }
2009 }
2010 flab::SessionRequest::WaitForInterrupt {
2011 resource,
2012 after_sequence,
2013 timeout_ns,
2014 responder,
2015 } => {
2016 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2017 let _ = responder.send(Err(flab::OperationError::NotAccepting));
2018 continue;
2019 }
2020
2021 let (tx, rx) = futures::channel::oneshot::channel();
2022
2023 let wait_init = {
2024 let mut guard = state.inner.lock().unwrap();
2025 let ProxyState { sessions, interrupts, audit, .. } = &mut *guard;
2026 match sessions.session(id) {
2027 None => Err(flab::OperationError::StaleIdentity),
2028 Some(session) => match session.policy.check_interrupt(resource) {
2029 Err(denial) => {
2030 let record = AuditRecord {
2031 session: Some(id),
2032 resource: Some(resource),
2033 operation: "wait_for_interrupt",
2034 offset: None,
2035 decision: Decision::Denied(denial),
2036 status: OpStatus::Rejected,
2037 value: None,
2038 timestamp_ns: now_ns(),
2039 run_id: None,
2040 item_index: None,
2041 };
2042 audit.append(record);
2043 Err(denial_to_fidl(denial))
2044 }
2045 Ok(()) => {
2046 if let Err(denial) = sessions.check_deadline(id, timeout_ns) {
2047 let record = AuditRecord {
2048 session: Some(id),
2049 resource: Some(resource),
2050 operation: "wait_for_interrupt",
2051 offset: None,
2052 decision: Decision::Denied(denial),
2053 status: OpStatus::Rejected,
2054 value: None,
2055 timestamp_ns: now_ns(),
2056 run_id: None,
2057 item_index: None,
2058 };
2059 audit.append(record);
2060 Err(denial_to_fidl(denial))
2061 } else if let Err(denial) =
2062 sessions.check_access(id, AccessClass::Interrupt, now_ns())
2063 {
2064 let record = AuditRecord {
2065 session: Some(id),
2066 resource: Some(resource),
2067 operation: "wait_for_interrupt",
2068 offset: None,
2069 decision: Decision::Denied(denial),
2070 status: OpStatus::Rejected,
2071 value: None,
2072 timestamp_ns: now_ns(),
2073 run_id: None,
2074 item_index: None,
2075 };
2076 audit.append(record);
2077 Err(denial_to_fidl(denial))
2078 } else {
2079 match interrupts.wait_for_interrupt(
2080 resource,
2081 after_sequence,
2082 Box::new(move |event| {
2083 let _ = tx.send(event);
2084 }),
2085 ) {
2086 Ok(Some(event)) => Ok(Some(event)),
2087 Ok(None) => Ok(None),
2088 Err(denial) => {
2089 let record = AuditRecord {
2090 session: Some(id),
2091 resource: Some(resource),
2092 operation: "wait_for_interrupt",
2093 offset: None,
2094 decision: Decision::Denied(denial),
2095 status: OpStatus::Rejected,
2096 value: None,
2097 timestamp_ns: now_ns(),
2098 run_id: None,
2099 item_index: None,
2100 };
2101 audit.append(record);
2102 Err(denial_to_fidl(denial))
2103 }
2104 }
2105 }
2106 }
2107 },
2108 }
2109 };
2110
2111 let event_result = match wait_init {
2112 Err(err) => Err(err),
2113 Ok(Some(event)) => Ok(event),
2114 Ok(None) => {
2115 if timeout_ns <= 0 {
2116 Err(flab::OperationError::Timeout)
2117 } else {
2118 futures::select! {
2119 res = rx.fuse() => {
2120 match res {
2121 Ok(event) => Ok(event),
2122 Err(_) => Err(flab::OperationError::NotAccepting),
2123 }
2124 }
2125 _ = fuchsia_async::Timer::new(zx::MonotonicInstant::after(
2126 zx::Duration::from_nanos(timeout_ns),
2127 )).fuse() => {
2128 Err(flab::OperationError::Timeout)
2129 }
2130 }
2131 }
2132 }
2133 };
2134
2135 let fidl_res = match event_result {
2136 Ok(event) => {
2137 let mut guard = state.inner.lock().unwrap();
2138 let record = AuditRecord {
2139 session: Some(id),
2140 resource: Some(resource),
2141 operation: "wait_for_interrupt",
2142 offset: None,
2143 decision: Decision::Allowed,
2144 status: OpStatus::Ok,
2145 value: Some(event.count as u32),
2146 timestamp_ns: event.timestamp_ns,
2147 run_id: None,
2148 item_index: None,
2149 };
2150 guard.audit.append(record);
2151 Ok((
2152 event.resource,
2153 event.sequence,
2154 event.count,
2155 event.timestamp_ns,
2156 event.coalesced_count,
2157 ))
2158 }
2159 Err(err) => {
2160 if err == flab::OperationError::Timeout {
2161 let mut guard = state.inner.lock().unwrap();
2162 let record = AuditRecord {
2163 session: Some(id),
2164 resource: Some(resource),
2165 operation: "wait_for_interrupt",
2166 offset: None,
2167 decision: Decision::Denied(Denial::Timeout),
2168 status: OpStatus::Rejected,
2169 value: None,
2170 timestamp_ns: now_ns(),
2171 run_id: None,
2172 item_index: None,
2173 };
2174 guard.audit.append(record);
2175 }
2176 Err(err)
2177 }
2178 };
2179
2180 let _ = responder.send(fidl_res);
2181 }
2182 flab::SessionRequest::ClockEnable { resource, responder } => {
2183 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2184 let _ = responder.send(Err(flab::OperationError::NotAccepting));
2185 continue;
2186 }
2187 let result = {
2188 let guard = &mut *state.inner.lock().unwrap();
2189 let ProxyState { sessions, executor, audit, .. } = guard;
2190 let check = match sessions.session(id) {
2191 None => Err(flab::OperationError::StaleIdentity),
2192 Some(session) => {
2193 session.policy.check_clock_enable(resource).map_err(denial_to_fidl)
2194 }
2195 };
2196 match check {
2197 Err(flab::OperationError::StaleIdentity) => {
2198 Err(flab::OperationError::StaleIdentity)
2199 }
2200 Err(_) => {
2201 let session = sessions.session(id).unwrap();
2202 executor
2203 .clock_enable(&session.policy, audit, id, resource)
2204 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2205 .map_err(|error| match error {
2206 ClockOpError::Denied { denial, .. } => denial_to_fidl(denial),
2207 ClockOpError::Backend { .. } => {
2208 flab::OperationError::BackendFault
2209 }
2210 })
2211 }
2212 Ok(_) => {
2213 let now = now_ns();
2214 match sessions.check_access(id, AccessClass::Protocol, now) {
2215 Err(denial) => {
2216 let record = AuditRecord {
2217 session: Some(id),
2218 resource: Some(resource),
2219 operation: "clock_enable",
2220 offset: None,
2221 decision: Decision::Denied(denial),
2222 status: OpStatus::Rejected,
2223 value: None,
2224 timestamp_ns: now,
2225 run_id: None,
2226 item_index: None,
2227 };
2228 audit.append(record);
2229 Err(denial_to_fidl(denial))
2230 }
2231 Ok(()) => {
2232 let session = sessions.session(id).unwrap();
2233 executor
2234 .clock_enable(&session.policy, audit, id, resource)
2235 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2236 .map_err(|error| match error {
2237 ClockOpError::Denied { denial, .. } => {
2238 denial_to_fidl(denial)
2239 }
2240 ClockOpError::Backend { .. } => {
2241 flab::OperationError::BackendFault
2242 }
2243 })
2244 }
2245 }
2246 }
2247 }
2248 };
2249 let _ = responder.send(result);
2250 }
2251 flab::SessionRequest::ClockDisable { resource, responder } => {
2252 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2253 let _ = responder.send(Err(flab::OperationError::NotAccepting));
2254 continue;
2255 }
2256 let result = {
2257 let guard = &mut *state.inner.lock().unwrap();
2258 let ProxyState { sessions, executor, audit, .. } = guard;
2259 let check = match sessions.session(id) {
2260 None => Err(flab::OperationError::StaleIdentity),
2261 Some(session) => {
2262 session.policy.check_clock_disable(resource).map_err(denial_to_fidl)
2263 }
2264 };
2265 match check {
2266 Err(flab::OperationError::StaleIdentity) => {
2267 Err(flab::OperationError::StaleIdentity)
2268 }
2269 Err(_) => {
2270 let session = sessions.session(id).unwrap();
2271 executor
2272 .clock_disable(&session.policy, audit, id, resource)
2273 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2274 .map_err(|error| match error {
2275 ClockOpError::Denied { denial, .. } => denial_to_fidl(denial),
2276 ClockOpError::Backend { .. } => {
2277 flab::OperationError::BackendFault
2278 }
2279 })
2280 }
2281 Ok(_) => {
2282 let now = now_ns();
2283 match sessions.check_access(id, AccessClass::Protocol, now) {
2284 Err(denial) => {
2285 let record = AuditRecord {
2286 session: Some(id),
2287 resource: Some(resource),
2288 operation: "clock_disable",
2289 offset: None,
2290 decision: Decision::Denied(denial),
2291 status: OpStatus::Rejected,
2292 value: None,
2293 timestamp_ns: now,
2294 run_id: None,
2295 item_index: None,
2296 };
2297 audit.append(record);
2298 Err(denial_to_fidl(denial))
2299 }
2300 Ok(()) => {
2301 let session = sessions.session(id).unwrap();
2302 executor
2303 .clock_disable(&session.policy, audit, id, resource)
2304 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2305 .map_err(|error| match error {
2306 ClockOpError::Denied { denial, .. } => {
2307 denial_to_fidl(denial)
2308 }
2309 ClockOpError::Backend { .. } => {
2310 flab::OperationError::BackendFault
2311 }
2312 })
2313 }
2314 }
2315 }
2316 }
2317 };
2318 let _ = responder.send(result);
2319 }
2320 flab::SessionRequest::ClockIsEnabled { resource, responder } => {
2321 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2322 let _ = responder.send(Err(flab::OperationError::NotAccepting));
2323 continue;
2324 }
2325 let result = {
2326 let guard = &mut *state.inner.lock().unwrap();
2327 let ProxyState { sessions, executor, audit, .. } = guard;
2328 let check = match sessions.session(id) {
2329 None => Err(flab::OperationError::StaleIdentity),
2330 Some(session) => {
2331 session.policy.check_clock_is_enabled(resource).map_err(denial_to_fidl)
2332 }
2333 };
2334 match check {
2335 Err(flab::OperationError::StaleIdentity) => {
2336 Err(flab::OperationError::StaleIdentity)
2337 }
2338 Err(_) => {
2339 let session = sessions.session(id).unwrap();
2340 executor
2341 .clock_is_enabled(&session.policy, audit, id, resource)
2342 .map(|outcome| {
2343 (outcome.enabled, outcome.audit_seq, outcome.timestamp_ns)
2344 })
2345 .map_err(|error| match error {
2346 ClockOpError::Denied { denial, .. } => denial_to_fidl(denial),
2347 ClockOpError::Backend { .. } => {
2348 flab::OperationError::BackendFault
2349 }
2350 })
2351 }
2352 Ok(_) => {
2353 let now = now_ns();
2354 match sessions.check_access(id, AccessClass::Protocol, now) {
2355 Err(denial) => {
2356 let record = AuditRecord {
2357 session: Some(id),
2358 resource: Some(resource),
2359 operation: "clock_is_enabled",
2360 offset: None,
2361 decision: Decision::Denied(denial),
2362 status: OpStatus::Rejected,
2363 value: None,
2364 timestamp_ns: now,
2365 run_id: None,
2366 item_index: None,
2367 };
2368 audit.append(record);
2369 Err(denial_to_fidl(denial))
2370 }
2371 Ok(()) => {
2372 let session = sessions.session(id).unwrap();
2373 executor
2374 .clock_is_enabled(&session.policy, audit, id, resource)
2375 .map(|outcome| {
2376 (
2377 outcome.enabled,
2378 outcome.audit_seq,
2379 outcome.timestamp_ns,
2380 )
2381 })
2382 .map_err(|error| match error {
2383 ClockOpError::Denied { denial, .. } => {
2384 denial_to_fidl(denial)
2385 }
2386 ClockOpError::Backend { .. } => {
2387 flab::OperationError::BackendFault
2388 }
2389 })
2390 }
2391 }
2392 }
2393 }
2394 };
2395 let _ = responder.send(result);
2396 }
2397 flab::SessionRequest::ClockSetRate { resource, hz, responder } => {
2398 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2399 let _ = responder.send(Err(flab::OperationError::NotAccepting));
2400 continue;
2401 }
2402 let result = {
2403 let guard = &mut *state.inner.lock().unwrap();
2404 let ProxyState { sessions, executor, audit, .. } = guard;
2405 let check = match sessions.session(id) {
2406 None => Err(flab::OperationError::StaleIdentity),
2407 Some(session) => {
2408 session.policy.check_clock_set_rate(resource).map_err(denial_to_fidl)
2409 }
2410 };
2411 match check {
2412 Err(flab::OperationError::StaleIdentity) => {
2413 Err(flab::OperationError::StaleIdentity)
2414 }
2415 Err(_) => {
2416 let session = sessions.session(id).unwrap();
2417 executor
2418 .clock_set_rate(&session.policy, audit, id, resource, hz)
2419 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2420 .map_err(|error| match error {
2421 ClockOpError::Denied { denial, .. } => denial_to_fidl(denial),
2422 ClockOpError::Backend { .. } => {
2423 flab::OperationError::BackendFault
2424 }
2425 })
2426 }
2427 Ok(_) => {
2428 let now = now_ns();
2429 match sessions.check_access(id, AccessClass::Protocol, now) {
2430 Err(denial) => {
2431 let record = AuditRecord {
2432 session: Some(id),
2433 resource: Some(resource),
2434 operation: "clock_set_rate",
2435 offset: None,
2436 decision: Decision::Denied(denial),
2437 status: OpStatus::Rejected,
2438 value: None,
2439 timestamp_ns: now,
2440 run_id: None,
2441 item_index: None,
2442 };
2443 audit.append(record);
2444 Err(denial_to_fidl(denial))
2445 }
2446 Ok(()) => {
2447 let session = sessions.session(id).unwrap();
2448 executor
2449 .clock_set_rate(&session.policy, audit, id, resource, hz)
2450 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2451 .map_err(|error| match error {
2452 ClockOpError::Denied { denial, .. } => {
2453 denial_to_fidl(denial)
2454 }
2455 ClockOpError::Backend { .. } => {
2456 flab::OperationError::BackendFault
2457 }
2458 })
2459 }
2460 }
2461 }
2462 }
2463 };
2464 let _ = responder.send(result);
2465 }
2466 flab::SessionRequest::ClockQueryRate { resource, hz_in, responder } => {
2467 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2468 let _ = responder.send(Err(flab::OperationError::NotAccepting));
2469 continue;
2470 }
2471 let result = {
2472 let guard = &mut *state.inner.lock().unwrap();
2473 let ProxyState { sessions, executor, audit, .. } = guard;
2474 let check = match sessions.session(id) {
2475 None => Err(flab::OperationError::StaleIdentity),
2476 Some(session) => {
2477 session.policy.check_clock_query_rate(resource).map_err(denial_to_fidl)
2478 }
2479 };
2480 match check {
2481 Err(flab::OperationError::StaleIdentity) => {
2482 Err(flab::OperationError::StaleIdentity)
2483 }
2484 Err(_) => {
2485 let session = sessions.session(id).unwrap();
2486 executor
2487 .clock_query_rate(&session.policy, audit, id, resource, hz_in)
2488 .map(|outcome| {
2489 (outcome.hz_out, outcome.audit_seq, outcome.timestamp_ns)
2490 })
2491 .map_err(|error| match error {
2492 ClockOpError::Denied { denial, .. } => denial_to_fidl(denial),
2493 ClockOpError::Backend { .. } => {
2494 flab::OperationError::BackendFault
2495 }
2496 })
2497 }
2498 Ok(_) => {
2499 let now = now_ns();
2500 match sessions.check_access(id, AccessClass::Protocol, now) {
2501 Err(denial) => {
2502 let record = AuditRecord {
2503 session: Some(id),
2504 resource: Some(resource),
2505 operation: "clock_query_rate",
2506 offset: None,
2507 decision: Decision::Denied(denial),
2508 status: OpStatus::Rejected,
2509 value: None,
2510 timestamp_ns: now,
2511 run_id: None,
2512 item_index: None,
2513 };
2514 audit.append(record);
2515 Err(denial_to_fidl(denial))
2516 }
2517 Ok(()) => {
2518 let session = sessions.session(id).unwrap();
2519 executor
2520 .clock_query_rate(
2521 &session.policy,
2522 audit,
2523 id,
2524 resource,
2525 hz_in,
2526 )
2527 .map(|outcome| {
2528 (
2529 outcome.hz_out,
2530 outcome.audit_seq,
2531 outcome.timestamp_ns,
2532 )
2533 })
2534 .map_err(|error| match error {
2535 ClockOpError::Denied { denial, .. } => {
2536 denial_to_fidl(denial)
2537 }
2538 ClockOpError::Backend { .. } => {
2539 flab::OperationError::BackendFault
2540 }
2541 })
2542 }
2543 }
2544 }
2545 }
2546 };
2547 let _ = responder.send(result);
2548 }
2549 flab::SessionRequest::ClockGetRate { resource, responder } => {
2550 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2551 let _ = responder.send(Err(flab::OperationError::NotAccepting));
2552 continue;
2553 }
2554 let result = {
2555 let guard = &mut *state.inner.lock().unwrap();
2556 let ProxyState { sessions, executor, audit, .. } = guard;
2557 let check = match sessions.session(id) {
2558 None => Err(flab::OperationError::StaleIdentity),
2559 Some(session) => {
2560 session.policy.check_clock_get_rate(resource).map_err(denial_to_fidl)
2561 }
2562 };
2563 match check {
2564 Err(flab::OperationError::StaleIdentity) => {
2565 Err(flab::OperationError::StaleIdentity)
2566 }
2567 Err(_) => {
2568 let session = sessions.session(id).unwrap();
2569 executor
2570 .clock_get_rate(&session.policy, audit, id, resource)
2571 .map(|outcome| {
2572 (outcome.hz, outcome.audit_seq, outcome.timestamp_ns)
2573 })
2574 .map_err(|error| match error {
2575 ClockOpError::Denied { denial, .. } => denial_to_fidl(denial),
2576 ClockOpError::Backend { .. } => {
2577 flab::OperationError::BackendFault
2578 }
2579 })
2580 }
2581 Ok(_) => {
2582 let now = now_ns();
2583 match sessions.check_access(id, AccessClass::Protocol, now) {
2584 Err(denial) => {
2585 let record = AuditRecord {
2586 session: Some(id),
2587 resource: Some(resource),
2588 operation: "clock_get_rate",
2589 offset: None,
2590 decision: Decision::Denied(denial),
2591 status: OpStatus::Rejected,
2592 value: None,
2593 timestamp_ns: now,
2594 run_id: None,
2595 item_index: None,
2596 };
2597 audit.append(record);
2598 Err(denial_to_fidl(denial))
2599 }
2600 Ok(()) => {
2601 let session = sessions.session(id).unwrap();
2602 executor
2603 .clock_get_rate(&session.policy, audit, id, resource)
2604 .map(|outcome| {
2605 (outcome.hz, outcome.audit_seq, outcome.timestamp_ns)
2606 })
2607 .map_err(|error| match error {
2608 ClockOpError::Denied { denial, .. } => {
2609 denial_to_fidl(denial)
2610 }
2611 ClockOpError::Backend { .. } => {
2612 flab::OperationError::BackendFault
2613 }
2614 })
2615 }
2616 }
2617 }
2618 }
2619 };
2620 let _ = responder.send(result);
2621 }
2622 flab::SessionRequest::ResetAssert { resource, responder } => {
2623 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2624 let _ = responder.send(Err(flab::OperationError::NotAccepting));
2625 continue;
2626 }
2627 let result = {
2628 let guard = &mut *state.inner.lock().unwrap();
2629 let ProxyState { sessions, executor, audit, .. } = guard;
2630 let check = match sessions.session(id) {
2631 None => Err(flab::OperationError::StaleIdentity),
2632 Some(session) => {
2633 session.policy.check_reset_assert(resource).map_err(denial_to_fidl)
2634 }
2635 };
2636 match check {
2637 Err(flab::OperationError::StaleIdentity) => {
2638 Err(flab::OperationError::StaleIdentity)
2639 }
2640 Err(_) => {
2641 let session = sessions.session(id).unwrap();
2642 executor
2643 .reset_assert(&session.policy, audit, id, resource)
2644 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2645 .map_err(|error| match error {
2646 ResetOpError::Denied { denial, .. } => denial_to_fidl(denial),
2647 ResetOpError::Backend { .. } => {
2648 flab::OperationError::BackendFault
2649 }
2650 })
2651 }
2652 Ok(_) => {
2653 let now = now_ns();
2654 match sessions.check_access(id, AccessClass::Protocol, now) {
2655 Err(denial) => {
2656 let record = AuditRecord {
2657 session: Some(id),
2658 resource: Some(resource),
2659 operation: "reset_assert",
2660 offset: None,
2661 decision: Decision::Denied(denial),
2662 status: OpStatus::Rejected,
2663 value: None,
2664 timestamp_ns: now,
2665 run_id: None,
2666 item_index: None,
2667 };
2668 audit.append(record);
2669 Err(denial_to_fidl(denial))
2670 }
2671 Ok(()) => {
2672 let session = sessions.session(id).unwrap();
2673 executor
2674 .reset_assert(&session.policy, audit, id, resource)
2675 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2676 .map_err(|error| match error {
2677 ResetOpError::Denied { denial, .. } => {
2678 denial_to_fidl(denial)
2679 }
2680 ResetOpError::Backend { .. } => {
2681 flab::OperationError::BackendFault
2682 }
2683 })
2684 }
2685 }
2686 }
2687 }
2688 };
2689 let _ = responder.send(result);
2690 }
2691 flab::SessionRequest::ResetDeassert { resource, responder } => {
2692 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2693 let _ = responder.send(Err(flab::OperationError::NotAccepting));
2694 continue;
2695 }
2696 let result = {
2697 let guard = &mut *state.inner.lock().unwrap();
2698 let ProxyState { sessions, executor, audit, .. } = guard;
2699 let check = match sessions.session(id) {
2700 None => Err(flab::OperationError::StaleIdentity),
2701 Some(session) => {
2702 session.policy.check_reset_deassert(resource).map_err(denial_to_fidl)
2703 }
2704 };
2705 match check {
2706 Err(flab::OperationError::StaleIdentity) => {
2707 Err(flab::OperationError::StaleIdentity)
2708 }
2709 Err(_) => {
2710 let session = sessions.session(id).unwrap();
2711 executor
2712 .reset_deassert(&session.policy, audit, id, resource)
2713 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2714 .map_err(|error| match error {
2715 ResetOpError::Denied { denial, .. } => denial_to_fidl(denial),
2716 ResetOpError::Backend { .. } => {
2717 flab::OperationError::BackendFault
2718 }
2719 })
2720 }
2721 Ok(_) => {
2722 let now = now_ns();
2723 match sessions.check_access(id, AccessClass::Protocol, now) {
2724 Err(denial) => {
2725 let record = AuditRecord {
2726 session: Some(id),
2727 resource: Some(resource),
2728 operation: "reset_deassert",
2729 offset: None,
2730 decision: Decision::Denied(denial),
2731 status: OpStatus::Rejected,
2732 value: None,
2733 timestamp_ns: now,
2734 run_id: None,
2735 item_index: None,
2736 };
2737 audit.append(record);
2738 Err(denial_to_fidl(denial))
2739 }
2740 Ok(()) => {
2741 let session = sessions.session(id).unwrap();
2742 executor
2743 .reset_deassert(&session.policy, audit, id, resource)
2744 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2745 .map_err(|error| match error {
2746 ResetOpError::Denied { denial, .. } => {
2747 denial_to_fidl(denial)
2748 }
2749 ResetOpError::Backend { .. } => {
2750 flab::OperationError::BackendFault
2751 }
2752 })
2753 }
2754 }
2755 }
2756 }
2757 };
2758 let _ = responder.send(result);
2759 }
2760 flab::SessionRequest::ResetToggle { resource, responder } => {
2761 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2762 let _ = responder.send(Err(flab::OperationError::NotAccepting));
2763 continue;
2764 }
2765 let result = {
2766 let guard = &mut *state.inner.lock().unwrap();
2767 let ProxyState { sessions, executor, audit, .. } = guard;
2768 let check = match sessions.session(id) {
2769 None => Err(flab::OperationError::StaleIdentity),
2770 Some(session) => {
2771 session.policy.check_reset_toggle(resource).map_err(denial_to_fidl)
2772 }
2773 };
2774 match check {
2775 Err(flab::OperationError::StaleIdentity) => {
2776 Err(flab::OperationError::StaleIdentity)
2777 }
2778 Err(_) => {
2779 let session = sessions.session(id).unwrap();
2780 executor
2781 .reset_toggle(&session.policy, audit, id, resource)
2782 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2783 .map_err(|error| match error {
2784 ResetOpError::Denied { denial, .. } => denial_to_fidl(denial),
2785 ResetOpError::Backend { .. } => {
2786 flab::OperationError::BackendFault
2787 }
2788 })
2789 }
2790 Ok(_) => {
2791 let now = now_ns();
2792 match sessions.check_access(id, AccessClass::Protocol, now) {
2793 Err(denial) => {
2794 let record = AuditRecord {
2795 session: Some(id),
2796 resource: Some(resource),
2797 operation: "reset_toggle",
2798 offset: None,
2799 decision: Decision::Denied(denial),
2800 status: OpStatus::Rejected,
2801 value: None,
2802 timestamp_ns: now,
2803 run_id: None,
2804 item_index: None,
2805 };
2806 audit.append(record);
2807 Err(denial_to_fidl(denial))
2808 }
2809 Ok(()) => {
2810 let session = sessions.session(id).unwrap();
2811 executor
2812 .reset_toggle(&session.policy, audit, id, resource)
2813 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2814 .map_err(|error| match error {
2815 ResetOpError::Denied { denial, .. } => {
2816 denial_to_fidl(denial)
2817 }
2818 ResetOpError::Backend { .. } => {
2819 flab::OperationError::BackendFault
2820 }
2821 })
2822 }
2823 }
2824 }
2825 }
2826 };
2827 let _ = responder.send(result);
2828 }
2829 flab::SessionRequest::ResetStatus { resource, responder } => {
2830 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2831 let _ = responder.send(Err(flab::OperationError::NotAccepting));
2832 continue;
2833 }
2834 let result = {
2835 let guard = &mut *state.inner.lock().unwrap();
2836 let ProxyState { sessions, executor, audit, .. } = guard;
2837 let check = match sessions.session(id) {
2838 None => Err(flab::OperationError::StaleIdentity),
2839 Some(session) => {
2840 session.policy.check_reset_status(resource).map_err(denial_to_fidl)
2841 }
2842 };
2843 match check {
2844 Err(flab::OperationError::StaleIdentity) => {
2845 Err(flab::OperationError::StaleIdentity)
2846 }
2847 Err(_) => {
2848 let session = sessions.session(id).unwrap();
2849 executor
2850 .reset_status(&session.policy, audit, id, resource)
2851 .map(|outcome| {
2852 (outcome.asserted, outcome.audit_seq, outcome.timestamp_ns)
2853 })
2854 .map_err(|error| match error {
2855 ResetOpError::Denied { denial, .. } => denial_to_fidl(denial),
2856 ResetOpError::Backend { .. } => {
2857 flab::OperationError::BackendFault
2858 }
2859 })
2860 }
2861 Ok(_) => {
2862 let now = now_ns();
2863 match sessions.check_access(id, AccessClass::Protocol, now) {
2864 Err(denial) => {
2865 let record = AuditRecord {
2866 session: Some(id),
2867 resource: Some(resource),
2868 operation: "reset_status",
2869 offset: None,
2870 decision: Decision::Denied(denial),
2871 status: OpStatus::Rejected,
2872 value: None,
2873 timestamp_ns: now,
2874 run_id: None,
2875 item_index: None,
2876 };
2877 audit.append(record);
2878 Err(denial_to_fidl(denial))
2879 }
2880 Ok(()) => {
2881 let session = sessions.session(id).unwrap();
2882 executor
2883 .reset_status(&session.policy, audit, id, resource)
2884 .map(|outcome| {
2885 (
2886 outcome.asserted,
2887 outcome.audit_seq,
2888 outcome.timestamp_ns,
2889 )
2890 })
2891 .map_err(|error| match error {
2892 ResetOpError::Denied { denial, .. } => {
2893 denial_to_fidl(denial)
2894 }
2895 ResetOpError::Backend { .. } => {
2896 flab::OperationError::BackendFault
2897 }
2898 })
2899 }
2900 }
2901 }
2902 }
2903 };
2904 let _ = responder.send(result);
2905 }
2906 flab::SessionRequest::SerialRead { resource, responder } => {
2907 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2908 let _ = responder.send(Err(flab::OperationError::NotAccepting));
2909 continue;
2910 }
2911 let result = {
2912 let guard = &mut *state.inner.lock().unwrap();
2913 let ProxyState { sessions, executor, audit, .. } = guard;
2914 let check = match sessions.session(id) {
2915 None => Err(flab::OperationError::StaleIdentity),
2916 Some(session) => {
2917 session.policy.check_serial_read(resource).map_err(denial_to_fidl)
2918 }
2919 };
2920 match check {
2921 Err(flab::OperationError::StaleIdentity) => {
2922 Err(flab::OperationError::StaleIdentity)
2923 }
2924 Err(_) => {
2925 let session = sessions.session(id).unwrap();
2926 executor
2927 .serial_read(&session.policy, audit, id, resource)
2928 .map(|outcome| {
2929 (outcome.data, outcome.audit_seq, outcome.timestamp_ns)
2930 })
2931 .map_err(|error| match error {
2932 SerialOpError::Denied { denial, .. } => denial_to_fidl(denial),
2933 SerialOpError::Backend { .. } => {
2934 flab::OperationError::BackendFault
2935 }
2936 })
2937 }
2938 Ok(_) => {
2939 let now = now_ns();
2940 match sessions.check_access(id, AccessClass::Protocol, now) {
2941 Err(denial) => {
2942 let record = AuditRecord {
2943 session: Some(id),
2944 resource: Some(resource),
2945 operation: "serial_read",
2946 offset: None,
2947 decision: Decision::Denied(denial),
2948 status: OpStatus::Rejected,
2949 value: None,
2950 timestamp_ns: now,
2951 run_id: None,
2952 item_index: None,
2953 };
2954 audit.append(record);
2955 Err(denial_to_fidl(denial))
2956 }
2957 Ok(()) => {
2958 let session = sessions.session(id).unwrap();
2959 executor
2960 .serial_read(&session.policy, audit, id, resource)
2961 .map(|outcome| {
2962 (outcome.data, outcome.audit_seq, outcome.timestamp_ns)
2963 })
2964 .map_err(|error| match error {
2965 SerialOpError::Denied { denial, .. } => {
2966 denial_to_fidl(denial)
2967 }
2968 SerialOpError::Backend { .. } => {
2969 flab::OperationError::BackendFault
2970 }
2971 })
2972 }
2973 }
2974 }
2975 }
2976 };
2977 let _ = responder.send(
2978 result
2979 .as_ref()
2980 .map(|(data, seq, ts)| (data.as_slice(), *seq, *ts))
2981 .map_err(|err| *err),
2982 );
2983 }
2984 flab::SessionRequest::SerialWrite { resource, data, responder } => {
2985 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2986 let _ = responder.send(Err(flab::OperationError::NotAccepting));
2987 continue;
2988 }
2989 let result = {
2990 let guard = &mut *state.inner.lock().unwrap();
2991 let ProxyState { sessions, executor, audit, .. } = guard;
2992 let check = match sessions.session(id) {
2993 None => Err(flab::OperationError::StaleIdentity),
2994 Some(session) => session
2995 .policy
2996 .check_serial_write(resource, data.len())
2997 .map_err(denial_to_fidl),
2998 };
2999 match check {
3000 Err(flab::OperationError::StaleIdentity) => {
3001 Err(flab::OperationError::StaleIdentity)
3002 }
3003 Err(_) => {
3004 let session = sessions.session(id).unwrap();
3005 executor
3006 .serial_write(&session.policy, audit, id, resource, &data)
3007 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
3008 .map_err(|error| match error {
3009 SerialOpError::Denied { denial, .. } => denial_to_fidl(denial),
3010 SerialOpError::Backend { .. } => {
3011 flab::OperationError::BackendFault
3012 }
3013 })
3014 }
3015 Ok(_) => {
3016 let now = now_ns();
3017 match sessions.check_access(id, AccessClass::Protocol, now) {
3018 Err(denial) => {
3019 let record = AuditRecord {
3020 session: Some(id),
3021 resource: Some(resource),
3022 operation: "serial_write",
3023 offset: None,
3024 decision: Decision::Denied(denial),
3025 status: OpStatus::Rejected,
3026 value: None,
3027 timestamp_ns: now,
3028 run_id: None,
3029 item_index: None,
3030 };
3031 audit.append(record);
3032 Err(denial_to_fidl(denial))
3033 }
3034 Ok(()) => {
3035 let session = sessions.session(id).unwrap();
3036 executor
3037 .serial_write(&session.policy, audit, id, resource, &data)
3038 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
3039 .map_err(|error| match error {
3040 SerialOpError::Denied { denial, .. } => {
3041 denial_to_fidl(denial)
3042 }
3043 SerialOpError::Backend { .. } => {
3044 flab::OperationError::BackendFault
3045 }
3046 })
3047 }
3048 }
3049 }
3050 }
3051 };
3052 let _ = responder.send(result);
3053 }
3054 flab::SessionRequest::_UnknownMethod { .. } => {}
3055 }
3056 }
3057
3058 // Channel closed: close the session, release the mutation lease, and
3059 // audit the closure.
3060 let mut state = state.inner.lock().unwrap();
3061 state.interrupts.cancel_waiters();
3062 let was_mutating =
3063 state.sessions.session(id).map(|s| s.mode == SessionMode::Mutating).unwrap_or(false);
3064 if state.sessions.close_session(id) {
3065 if was_mutating {
3066 let mut q_record = AuditRecord::lifecycle("quiesce_released", now_ns());
3067 q_record.session = Some(id);
3068 state.audit.append(q_record);
3069 }
3070 let mut record = AuditRecord::lifecycle("session_closed", now_ns());
3071 record.session = Some(id);
3072 state.audit.append(record);
3073 }
3074}
3075
3076async fn serve_gpio_endpoint(
3077 state: SharedState,
3078 session_id: u64,
3079 resource: u32,
3080 mut stream: flab::GpioEndpointRequestStream,
3081) {
3082 while let Ok(Some(request)) = stream.try_next().await {
3083 match request {
3084 flab::GpioEndpointRequest::Read { responder } => {
3085 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
3086 let _ = responder.send(Err(flab::OperationError::NotAccepting));
3087 continue;
3088 }
3089 let result = {
3090 let guard = &mut *state.inner.lock().unwrap();
3091 let ProxyState { sessions, executor, audit, .. } = guard;
3092 let check = match sessions.session(session_id) {
3093 None => Err(flab::OperationError::StaleIdentity),
3094 Some(session) => {
3095 session.policy.check_gpio_read(resource).map_err(denial_to_fidl)
3096 }
3097 };
3098 match check {
3099 Err(flab::OperationError::StaleIdentity) => {
3100 Err(flab::OperationError::StaleIdentity)
3101 }
3102 Err(_) => {
3103 let session = sessions.session(session_id).unwrap();
3104 executor
3105 .gpio_read(&session.policy, audit, session_id, resource)
3106 .map(|outcome| {
3107 (outcome.value, outcome.audit_seq, outcome.timestamp_ns)
3108 })
3109 .map_err(|error| match error {
3110 GpioReadError::Denied { denial, .. } => denial_to_fidl(denial),
3111 GpioReadError::Backend { .. } => {
3112 flab::OperationError::BackendFault
3113 }
3114 })
3115 }
3116 Ok(_) => {
3117 let now = now_ns();
3118 match sessions.check_access(session_id, AccessClass::Protocol, now) {
3119 Err(denial) => {
3120 let record = AuditRecord {
3121 session: Some(session_id),
3122 resource: Some(resource),
3123 operation: "gpio_read",
3124 offset: None,
3125 decision: Decision::Denied(denial),
3126 status: OpStatus::Rejected,
3127 value: None,
3128 timestamp_ns: now,
3129 run_id: None,
3130 item_index: None,
3131 };
3132 audit.append(record);
3133 Err(denial_to_fidl(denial))
3134 }
3135 Ok(()) => {
3136 let session = sessions.session(session_id).unwrap();
3137 executor
3138 .gpio_read(&session.policy, audit, session_id, resource)
3139 .map(|outcome| {
3140 (outcome.value, outcome.audit_seq, outcome.timestamp_ns)
3141 })
3142 .map_err(|error| match error {
3143 GpioReadError::Denied { denial, .. } => {
3144 denial_to_fidl(denial)
3145 }
3146 GpioReadError::Backend { .. } => {
3147 flab::OperationError::BackendFault
3148 }
3149 })
3150 }
3151 }
3152 }
3153 }
3154 };
3155 let _ = responder.send(result);
3156 }
3157 flab::GpioEndpointRequest::Write { value, responder } => {
3158 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
3159 let _ = responder.send(Err(flab::OperationError::NotAccepting));
3160 continue;
3161 }
3162 let result = {
3163 let guard = &mut *state.inner.lock().unwrap();
3164 let ProxyState { sessions, executor, audit, .. } = guard;
3165 let check = match sessions.session(session_id) {
3166 None => Err(flab::OperationError::StaleIdentity),
3167 Some(session) => {
3168 session.policy.check_gpio_write(resource).map_err(denial_to_fidl)
3169 }
3170 };
3171 match check {
3172 Err(flab::OperationError::StaleIdentity) => {
3173 Err(flab::OperationError::StaleIdentity)
3174 }
3175 Err(_) => {
3176 let session = sessions.session(session_id).unwrap();
3177 executor
3178 .gpio_write(&session.policy, audit, session_id, resource, value)
3179 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
3180 .map_err(|error| match error {
3181 GpioWriteError::Denied { denial, .. } => denial_to_fidl(denial),
3182 GpioWriteError::Backend { .. } => {
3183 flab::OperationError::BackendFault
3184 }
3185 })
3186 }
3187 Ok(_) => {
3188 let now = now_ns();
3189 match sessions.check_access(session_id, AccessClass::Protocol, now) {
3190 Err(denial) => {
3191 let record = AuditRecord {
3192 session: Some(session_id),
3193 resource: Some(resource),
3194 operation: "gpio_write",
3195 offset: None,
3196 decision: Decision::Denied(denial),
3197 status: OpStatus::Rejected,
3198 value: None,
3199 timestamp_ns: now,
3200 run_id: None,
3201 item_index: None,
3202 };
3203 audit.append(record);
3204 Err(denial_to_fidl(denial))
3205 }
3206 Ok(()) => {
3207 let session = sessions.session(session_id).unwrap();
3208 executor
3209 .gpio_write(
3210 &session.policy,
3211 audit,
3212 session_id,
3213 resource,
3214 value,
3215 )
3216 .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
3217 .map_err(|error| match error {
3218 GpioWriteError::Denied { denial, .. } => {
3219 denial_to_fidl(denial)
3220 }
3221 GpioWriteError::Backend { .. } => {
3222 flab::OperationError::BackendFault
3223 }
3224 })
3225 }
3226 }
3227 }
3228 }
3229 };
3230 let _ = responder.send(result);
3231 }
3232 flab::GpioEndpointRequest::_UnknownMethod { .. } => {}
3233 }
3234 }
3235}
3236
3237async fn serve_i2c_endpoint(
3238 state: SharedState,
3239 session_id: u64,
3240 resource: u32,
3241 mut stream: flab::I2cEndpointRequestStream,
3242) {
3243 while let Ok(Some(request)) = stream.try_next().await {
3244 match request {
3245 flab::I2cEndpointRequest::Transfer { write_data, read_length, responder } => {
3246 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
3247 let _ = responder.send(Err(flab::OperationError::NotAccepting));
3248 continue;
3249 }
3250 let result = {
3251 let guard = &mut *state.inner.lock().unwrap();
3252 let ProxyState { sessions, executor, audit, .. } = guard;
3253 let check = match sessions.session(session_id) {
3254 None => Err(flab::OperationError::StaleIdentity),
3255 Some(session) => session
3256 .policy
3257 .check_i2c_transfer(resource, write_data.len(), read_length as usize)
3258 .map_err(denial_to_fidl),
3259 };
3260 match check {
3261 Err(flab::OperationError::StaleIdentity) => {
3262 Err(flab::OperationError::StaleIdentity)
3263 }
3264 Err(_) => {
3265 let session = sessions.session(session_id).unwrap();
3266 executor
3267 .i2c_transfer(
3268 &session.policy,
3269 audit,
3270 session_id,
3271 resource,
3272 &write_data,
3273 read_length,
3274 )
3275 .map(|outcome| {
3276 (outcome.read_data, outcome.audit_seq, outcome.timestamp_ns)
3277 })
3278 .map_err(|error| match error {
3279 I2cTransferError::Denied { denial, .. } => {
3280 denial_to_fidl(denial)
3281 }
3282 I2cTransferError::Backend { .. } => {
3283 flab::OperationError::BackendFault
3284 }
3285 })
3286 }
3287 Ok(_) => {
3288 let now = now_ns();
3289 match sessions.check_access(session_id, AccessClass::Protocol, now) {
3290 Err(denial) => {
3291 let record = AuditRecord {
3292 session: Some(session_id),
3293 resource: Some(resource),
3294 operation: "i2c_transfer",
3295 offset: None,
3296 decision: Decision::Denied(denial),
3297 status: OpStatus::Rejected,
3298 value: None,
3299 timestamp_ns: now,
3300 run_id: None,
3301 item_index: None,
3302 };
3303 audit.append(record);
3304 Err(denial_to_fidl(denial))
3305 }
3306 Ok(()) => {
3307 let session = sessions.session(session_id).unwrap();
3308 executor
3309 .i2c_transfer(
3310 &session.policy,
3311 audit,
3312 session_id,
3313 resource,
3314 &write_data,
3315 read_length,
3316 )
3317 .map(|outcome| {
3318 (
3319 outcome.read_data,
3320 outcome.audit_seq,
3321 outcome.timestamp_ns,
3322 )
3323 })
3324 .map_err(|error| match error {
3325 I2cTransferError::Denied { denial, .. } => {
3326 denial_to_fidl(denial)
3327 }
3328 I2cTransferError::Backend { .. } => {
3329 flab::OperationError::BackendFault
3330 }
3331 })
3332 }
3333 }
3334 }
3335 }
3336 };
3337 let _ = responder.send(
3338 result
3339 .as_ref()
3340 .map(|(data, seq, ts)| (data.as_slice(), *seq, *ts))
3341 .map_err(|err| *err),
3342 );
3343 }
3344 flab::I2cEndpointRequest::_UnknownMethod { .. } => {}
3345 }
3346 }
3347}
3348
3349async fn serve_spi_endpoint(
3350 state: SharedState,
3351 session_id: u64,
3352 resource: u32,
3353 mut stream: flab::SpiEndpointRequestStream,
3354) {
3355 while let Ok(Some(request)) = stream.try_next().await {
3356 match request {
3357 flab::SpiEndpointRequest::Transmit { tx_data, responder } => {
3358 if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
3359 let _ = responder.send(Err(flab::OperationError::NotAccepting));
3360 continue;
3361 }
3362 let result = {
3363 let guard = &mut *state.inner.lock().unwrap();
3364 let ProxyState { sessions, executor, audit, .. } = guard;
3365 let check = match sessions.session(session_id) {
3366 None => Err(flab::OperationError::StaleIdentity),
3367 Some(session) => session
3368 .policy
3369 .check_spi_transmit(resource, tx_data.len())
3370 .map_err(denial_to_fidl),
3371 };
3372 match check {
3373 Err(flab::OperationError::StaleIdentity) => {
3374 Err(flab::OperationError::StaleIdentity)
3375 }
3376 Err(_) => {
3377 let session = sessions.session(session_id).unwrap();
3378 executor
3379 .spi_transmit(
3380 &session.policy,
3381 audit,
3382 session_id,
3383 resource,
3384 &tx_data,
3385 )
3386 .map(|outcome| {
3387 (outcome.rx_data, outcome.audit_seq, outcome.timestamp_ns)
3388 })
3389 .map_err(|error| match error {
3390 SpiTransmitError::Denied { denial, .. } => {
3391 denial_to_fidl(denial)
3392 }
3393 SpiTransmitError::Backend { .. } => {
3394 flab::OperationError::BackendFault
3395 }
3396 })
3397 }
3398 Ok(_) => {
3399 let now = now_ns();
3400 match sessions.check_access(session_id, AccessClass::Protocol, now) {
3401 Err(denial) => {
3402 let record = AuditRecord {
3403 session: Some(session_id),
3404 resource: Some(resource),
3405 operation: "spi_transmit",
3406 offset: None,
3407 decision: Decision::Denied(denial),
3408 status: OpStatus::Rejected,
3409 value: None,
3410 timestamp_ns: now,
3411 run_id: None,
3412 item_index: None,
3413 };
3414 audit.append(record);
3415 Err(denial_to_fidl(denial))
3416 }
3417 Ok(()) => {
3418 let session = sessions.session(session_id).unwrap();
3419 executor
3420 .spi_transmit(
3421 &session.policy,
3422 audit,
3423 session_id,
3424 resource,
3425 &tx_data,
3426 )
3427 .map(|outcome| {
3428 (
3429 outcome.rx_data,
3430 outcome.audit_seq,
3431 outcome.timestamp_ns,
3432 )
3433 })
3434 .map_err(|error| match error {
3435 SpiTransmitError::Denied { denial, .. } => {
3436 denial_to_fidl(denial)
3437 }
3438 SpiTransmitError::Backend { .. } => {
3439 flab::OperationError::BackendFault
3440 }
3441 })
3442 }
3443 }
3444 }
3445 }
3446 };
3447 let _ = responder.send(
3448 result
3449 .as_ref()
3450 .map(|(data, seq, ts)| (data.as_slice(), *seq, *ts))
3451 .map_err(|err| *err),
3452 );
3453 }
3454 flab::SpiEndpointRequest::_UnknownMethod { .. } => {}
3455 }
3456 }
3457}