unlock: route_unlock returns a structured UnlockRoute; ctx carries opts

Replace route_unlock's Option<(name, Vid)> with a structured UnlockRoute
{ Unlocked(name, Unlocked) | Failed(UnlockError) | NoMatch } so a single
dispatch serves every caller: drive-prep wants "did anything unlock", and the
AACS cert route (next) needs the FAILURE REASON to render "missing keys" vs
"host cert rejected" instead of collapsing it to a bare None. Only a genuine
SCSI transport fault still returns Err (abort). UnlockCtx gains an optional
ScanOptions (the cert route's host-cert source), and read_mkb_from_drive now
takes &mut dyn ScsiTransport — both prerequisites for the cert handshake to
become an external freemkv-unlock-aacs unlocker. Drive-prep + CSS callers fold
the new outcome; no behavior change.
This commit is contained in:
Matthew Jackson
2026-06-29 17:18:11 -07:00
parent 326d17c2f4
commit ab8f09645f
5 changed files with 130 additions and 75 deletions
+4 -2
View File
@@ -418,7 +418,7 @@ impl Drive {
);
self.init_ran = true;
let r = match r {
Ok(Some((name, unlocked))) => {
Ok(crate::unlock::UnlockRoute::Unlocked(name, unlocked)) => {
self.unlocker_name = Some(name);
// Stash the OEM Volume ID the firmware unlocker returned for the
// AACS handshake phase (do_handshake reads it via `oem_vid()`).
@@ -448,7 +448,9 @@ impl Drive {
// No unlocker matched, or one matched but only hit a capability
// failure (not firmware-unlockable / no OEM VID): not an error —
// fall through to the OEM host-cert route.
Ok(None) => Ok(()),
Ok(crate::unlock::UnlockRoute::Failed(..) | crate::unlock::UnlockRoute::NoMatch) => {
Ok(())
}
// A genuine transport fault during unlock (UnlockError::Scsi)
// propagates here and aborts init — the bus is dead.
Err(e) => Err(e),