nrf_softdevice/ble/
replies.rs

1#[cfg(any(feature = "ble-sec", feature = "ble-gatt-server"))]
2use core::mem::ManuallyDrop;
3
4#[cfg(any(feature = "ble-sec", feature = "ble-gatt-server"))]
5use super::Connection;
6#[cfg(any(feature = "ble-sec", feature = "ble-gatt-server"))]
7use crate::{raw, RawError};
8
9#[cfg(feature = "ble-sec")]
10pub struct PasskeyReply {
11    conn: ManuallyDrop<Connection>,
12}
13
14#[cfg(feature = "ble-sec")]
15impl Drop for PasskeyReply {
16    fn drop(&mut self) {
17        if let Err(_err) = unsafe { self.finalize(None) } {
18            warn!("sd_ble_gap_auth_key_reply err {:?}", _err);
19        }
20    }
21}
22
23#[cfg(feature = "ble-sec")]
24impl PasskeyReply {
25    pub(crate) fn new(conn: Connection) -> Self {
26        Self {
27            conn: ManuallyDrop::new(conn),
28        }
29    }
30
31    pub fn reply(mut self, passkey: Option<&[u8; 6]>) -> Result<(), RawError> {
32        let res = unsafe { self.finalize(passkey) };
33        core::mem::forget(self); // Prevent Drop from finalizing a second time
34        res
35    }
36
37    /// # Safety
38    ///
39    /// This method must be called exactly once
40    unsafe fn finalize(&mut self, passkey: Option<&[u8; 6]>) -> Result<(), RawError> {
41        let res = if let Some(conn_handle) = self.conn.handle() {
42            let ptr = passkey.map(|x| x.as_ptr()).unwrap_or(core::ptr::null());
43            let ret = raw::sd_ble_gap_auth_key_reply(conn_handle, raw::BLE_GAP_AUTH_KEY_TYPE_PASSKEY as u8, ptr);
44            RawError::convert(ret)
45        } else {
46            Err(RawError::InvalidState)
47        };
48
49        // Since conn is ManuallyDrop, we must drop it here
50        ManuallyDrop::drop(&mut self.conn);
51        res
52    }
53}
54
55#[cfg(feature = "ble-sec")]
56pub struct OutOfBandReply {
57    conn: ManuallyDrop<Connection>,
58}
59
60#[cfg(feature = "ble-sec")]
61impl Drop for OutOfBandReply {
62    fn drop(&mut self) {
63        if let Err(_err) = unsafe { self.finalize(None) } {
64            warn!("sd_ble_gap_auth_key_reply err {:?}", _err);
65        }
66    }
67}
68
69#[cfg(feature = "ble-sec")]
70impl OutOfBandReply {
71    pub(crate) fn new(conn: Connection) -> Self {
72        Self {
73            conn: ManuallyDrop::new(conn),
74        }
75    }
76
77    pub fn reply(mut self, oob: Option<&[u8; 16]>) -> Result<(), RawError> {
78        let res = unsafe { self.finalize(oob) };
79        core::mem::forget(self); // Prevent Drop from finalizing a second time
80        res
81    }
82
83    /// # Safety
84    ///
85    /// This method must be called exactly once
86    unsafe fn finalize(&mut self, oob: Option<&[u8; 16]>) -> Result<(), RawError> {
87        let res = if let Some(conn_handle) = self.conn.handle() {
88            let ptr = oob.map(|x| x.as_ptr()).unwrap_or(core::ptr::null());
89            let ret = raw::sd_ble_gap_auth_key_reply(conn_handle, raw::BLE_GAP_AUTH_KEY_TYPE_OOB as u8, ptr);
90            RawError::convert(ret)
91        } else {
92            Err(RawError::InvalidState)
93        };
94
95        // Since conn is ManuallyDrop, we must drop it here
96        ManuallyDrop::drop(&mut self.conn);
97        res
98    }
99}
100
101#[cfg(feature = "ble-gatt-server")]
102const DEFERRED_TYPE_READ: u8 = raw::BLE_GATTS_AUTHORIZE_TYPE_READ as u8;
103#[cfg(feature = "ble-gatt-server")]
104const DEFERRED_TYPE_WRITE: u8 = raw::BLE_GATTS_AUTHORIZE_TYPE_WRITE as u8;
105
106#[cfg(feature = "ble-gatt-server")]
107struct DeferredReply<const DEFERRED_TYPE: u8> {
108    conn: ManuallyDrop<Connection>,
109}
110
111#[cfg(feature = "ble-gatt-server")]
112impl<const DEFERRED_TYPE: u8> Drop for DeferredReply<DEFERRED_TYPE> {
113    fn drop(&mut self) {
114        warn!("DeferredReply<{}> dropped without reply", DEFERRED_TYPE);
115        let res = unsafe { self.finalize(DEFERRED_TYPE, Err(super::GattError::ATTERR_ATTRIBUTE_NOT_FOUND)) };
116
117        if let Err(_err) = res {
118            warn!("sd_ble_gatts_rw_authorize_reply err {:?}", _err);
119        }
120    }
121}
122
123#[cfg(feature = "ble-gatt-server")]
124impl<const DEFERRED_TYPE: u8> DeferredReply<DEFERRED_TYPE> {
125    fn reply(mut self, res: Result<Option<&[u8]>, super::GattError>) -> Result<(), RawError> {
126        let res = unsafe { self.finalize(DEFERRED_TYPE, res) };
127        core::mem::forget(self);
128        res
129    }
130
131    /// # Safety
132    ///
133    /// This method must be called exactly once
134    unsafe fn finalize(
135        &mut self,
136        deferred_type: u8,
137        res: Result<Option<&[u8]>, super::GattError>,
138    ) -> Result<(), RawError> {
139        let (gatt_status, update, p_data, len) = match res {
140            Ok(Some(data)) => (super::GattStatus::SUCCESS, true, data.as_ptr(), data.len()),
141            Ok(None) => (super::GattStatus::SUCCESS, false, core::ptr::null(), 0),
142            Err(err) => (err.to_status(), false, core::ptr::null(), 0),
143        };
144
145        let res = if let Some(handle) = self.conn.handle() {
146            let params = raw::ble_gatts_authorize_params_t {
147                gatt_status: gatt_status.into(),
148                _bitfield_1: raw::ble_gatts_authorize_params_t::new_bitfield_1(u8::from(update)),
149                offset: 0,
150                len: len as u16,
151                p_data,
152            };
153
154            let reply_params = raw::ble_gatts_rw_authorize_reply_params_t {
155                type_: deferred_type,
156                params: raw::ble_gatts_rw_authorize_reply_params_t__bindgen_ty_1 { read: params },
157            };
158
159            let ret = raw::sd_ble_gatts_rw_authorize_reply(handle, &reply_params);
160            RawError::convert(ret)
161        } else {
162            Err(RawError::BleInvalidConnHandle)
163        };
164
165        // Since conn is ManuallyDrop, we must drop it here
166        ManuallyDrop::drop(&mut self.conn);
167        res
168    }
169}
170
171#[cfg(feature = "ble-gatt-server")]
172pub struct DeferredWriteReply(DeferredReply<DEFERRED_TYPE_WRITE>);
173
174#[cfg(feature = "ble-gatt-server")]
175/// Represents an in-progress deferred write request
176impl DeferredWriteReply {
177    pub(crate) fn new(conn: Connection) -> Self {
178        DeferredWriteReply(DeferredReply {
179            conn: ManuallyDrop::new(conn),
180        })
181    }
182
183    pub fn conn(&self) -> &Connection {
184        &self.0.conn
185    }
186
187    pub fn reply(self, res: Result<&[u8], super::GattError>) -> Result<(), RawError> {
188        self.0.reply(res.map(Some))
189    }
190}
191
192#[cfg(feature = "ble-gatt-server")]
193pub struct DeferredReadReply(DeferredReply<DEFERRED_TYPE_READ>);
194
195#[cfg(feature = "ble-gatt-server")]
196/// Represents an in-progress deferred read request
197impl DeferredReadReply {
198    pub(crate) fn new(conn: Connection) -> Self {
199        DeferredReadReply(DeferredReply {
200            conn: ManuallyDrop::new(conn),
201        })
202    }
203
204    pub fn conn(&self) -> &Connection {
205        &self.0.conn
206    }
207
208    /// Finishes the read operation with `res`.
209    ///
210    /// If `res` is `Ok(None)`, the value of the attribute stored by the softdevice will be returned to the central.
211    pub fn reply(self, res: Result<Option<&[u8]>, super::GattError>) -> Result<(), RawError> {
212        self.0.reply(res)
213    }
214}