Skip to main content

acex_server/
server.rs

1// region: Imports
2
3use acex_core::Vec;
4use acex_proto::uds::UdsFrame;
5use acex_sim::clock::{Duration, Instant};
6use acex_sim::io::NodeAddress;
7use acex_uds::ext::UdsFrameExt;
8use acex_uds::message::service::UdsServiceRequest;
9use acex_uds::message::{DiagnosticSessionType, ServiceIdentifier};
10
11use crate::config::{periodic, ServerConfig, SessionConfig};
12use crate::handler::ServerHandler;
13use crate::nrc::NrcError;
14use crate::security_provider::SecurityProvider;
15
16// endregion: Imports
17
18// region: ServerError
19
20#[derive(Debug)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22pub enum ServerError<E: NrcError> {
23    Handler(E),
24    Codec(acex_uds::error::UdsError),
25    OutboxFull,
26}
27
28// endregion: ServerError
29
30// region: SessionState
31
32#[derive(Debug, Clone)]
33#[cfg_attr(feature = "defmt", derive(defmt::Format))]
34pub struct SessionState {
35    session_type: u8,
36    last_rx: Instant,
37    security_level: u8,
38}
39
40impl PartialEq for SessionState {
41    fn eq(&self, other: &Self) -> bool {
42        self.session_type == other.session_type
43            && self.security_level == other.security_level
44    }
45}
46
47impl SessionState {
48    fn new(session_type: u8) -> Self {
49        Self {
50            session_type,
51            last_rx: Instant::ZERO,
52            security_level: 0,
53        }
54    }
55
56    pub const fn is_default(&self) -> bool {
57        self.session_type == 0x01
58    }
59
60    pub const fn is_programming(&self) -> bool {
61        self.session_type == 0x02
62    }
63
64    pub const fn is_extended(&self) -> bool {
65        self.session_type == 0x03
66    }
67
68    pub const fn get_session_type(&self) -> u8 {
69        self.session_type
70    }
71
72    pub const fn get_last_rx(&self) -> Instant {
73        self.last_rx
74    }
75
76    pub const fn get_security_level(&self) -> u8 {
77        self.security_level
78    }
79}
80
81// endregion: SessionState
82
83// region: SecurityState
84
85#[derive(Debug, Clone)]
86#[cfg_attr(all(feature = "defmt", not(feature = "alloc")), derive(defmt::Format))]
87struct SecurityState<const MAX_SEED: usize, const MAX_SECURITY_LEVELS: usize> {
88    pending_seed: Vec<u8, MAX_SEED>,
89    pending_level: u8,
90    failed_attempts: Vec<(u8, u8), MAX_SECURITY_LEVELS>,
91    lockout_until: Vec<(u8, Instant), MAX_SECURITY_LEVELS>,
92}
93
94impl<
95    const MAX_SEED: usize,
96    const MAX_SECURITY_LEVELS: usize
97> SecurityState<
98    MAX_SEED,
99    MAX_SECURITY_LEVELS
100> {
101    fn new() -> Self {
102        Self {
103            pending_seed: Vec::new(),
104            pending_level: 0,
105            failed_attempts: Vec::new(),
106            lockout_until: Vec::new(),
107        }
108    }
109
110    fn is_locked(&self, level: u8, now: Instant) -> bool {
111        self.lockout_until
112            .iter()
113            .find(|(l, _)| *l == level)
114            .map(|(_, until)| now < *until)
115            .unwrap_or(false)
116    }
117
118    fn failed_count(&self, level: u8) -> u8 {
119        self.failed_attempts
120            .iter()
121            .find(|(l, _)| *l == level)
122            .map(|(_, c)| *c)
123            .unwrap_or(0)
124    }
125
126    fn increment_failed(&mut self, level: u8) {
127        if let Some(e) = self.failed_attempts.iter_mut().find(|(l, _)| *l == level) {
128            e.1 = e.1.saturating_add(1);
129        } else {
130            #[cfg(all(feature = "defmt", not(feature = "alloc")))]
131            defmt::unwrap!(self.failed_attempts.push((level, 1))); // unlikely
132
133            #[cfg(feature = "alloc")]
134            self.failed_attempts.push((level, 1));
135        }
136    }
137
138    fn reset_failed(&mut self, level: u8) {
139        if let Some(e) = self.failed_attempts.iter_mut().find(|(l, _)| *l == level) {
140            e.1 = 0;
141        }
142    }
143
144    fn set_lockout(&mut self, level: u8, until: Instant) {
145        if let Some(e) = self.lockout_until.iter_mut().find(|(l, _)| *l == level) {
146            e.1 = until;
147        } else {
148            #[cfg(all(feature = "defmt", not(feature = "alloc")))]
149            defmt::unwrap!(self.lockout_until.push((level, until))); // unlikely
150
151            #[cfg(feature = "alloc")]
152            self.lockout_until.push((level, until));
153        }
154    }
155
156    fn clear_pending(&mut self) {
157        self.pending_seed.clear();
158        self.pending_level = 0;
159    }
160
161    fn reset(&mut self) {
162        self.lockout_until.clear();
163        self.pending_seed.clear();
164        self.failed_attempts.clear();
165        self.pending_level = 0 ;
166    }
167}
168
169// endregion: SecurityState
170
171// region: PeriodicEntry / PeriodicState
172
173#[derive(Debug, Clone)]
174#[cfg_attr(feature = "defmt", derive(defmt::Format))]
175struct PeriodicEntry {
176    did: u16,
177    interval: Duration,
178    next_tx: Instant,
179    client: NodeAddress,
180}
181
182#[derive(Debug)]
183#[cfg_attr(all(feature = "defmt", not(feature = "alloc")), derive(defmt::Format))]
184struct PeriodicState<const MAX_PERIODIC: usize> {
185    entries: Vec<PeriodicEntry, MAX_PERIODIC>,
186}
187
188impl<const MAX_PERIODIC: usize> PeriodicState<MAX_PERIODIC> {
189    fn new() -> Self {
190        Self {
191            entries: Vec::new(),
192        }
193    }
194
195    fn register(&mut self, did: u16, interval: Duration, client: NodeAddress, now: Instant) {
196        if let Some(e) = self
197            .entries
198            .iter_mut()
199            .find(|e| e.did == did && e.client == client)
200        {
201            e.interval = interval;
202            e.next_tx = now + interval;
203            return;
204        }
205
206        #[cfg(feature = "defmt")]
207        defmt::unwrap!(self.entries.push(PeriodicEntry {
208            did,
209            interval,
210            next_tx: now + interval,
211            client,
212        }));
213
214        #[cfg(not(feature = "defmt"))]
215        let _ = self.entries.push(PeriodicEntry {
216            did,
217            interval,
218            next_tx: now + interval,
219            client,
220        });
221    }
222
223    fn cancel(&mut self, did: u16, client: &NodeAddress) {
224        self.entries
225            .retain(|e| !(e.did == did && &e.client == client));
226    }
227
228    fn collect_due(&self, now: Instant, out: &mut Vec<(u16, NodeAddress), MAX_PERIODIC>) {
229        for e in self.entries.iter().filter(|e| now >= e.next_tx) {
230            #[cfg(feature = "defmt")]
231            defmt::unwrap!(out.push((e.did, e.client.clone())));
232
233            #[cfg(not(feature = "defmt"))]
234            let _ = out.push((e.did, e.client.clone()));
235        }
236    }
237
238    fn advance(&mut self, did: u16, client: &NodeAddress, now: Instant) {
239        if let Some(e) = self
240            .entries
241            .iter_mut()
242            .find(|e| e.did == did && &e.client == client)
243        {
244            e.next_tx = now + e.interval;
245        }
246    }
247}
248
249// endregion: PeriodicEntry / PeriodicState
250
251// region: UdsServer
252
253/// Stateful UDS ECU server state machine.
254///
255/// Receives raw UDS frames via [`handle`], uses [`UdsFrameExt`] for
256/// protocol-level decisions (SID dispatch, suppress bit, sub-function),
257/// and decodes typed messages only where structured field access is needed.
258///
259/// All timing is driven by [`tick`] - no blocking, no hardware timers,
260/// no OS calls. Suitable for direct use as a `SimNode` in `ace-sim`.
261#[derive(Debug)]
262#[cfg_attr(all(feature = "defmt", not(feature = "alloc")), derive(defmt::Format))]
263pub struct UdsServer<
264    const MAX_FRAME: usize,
265    const MAX_OUTBOX: usize,
266    const MAX_SESSIONS: usize,
267    const MAX_SERVICES: usize,
268    const MAX_DIDS: usize,
269    const MAX_SECURITY_LEVELS: usize,
270    const DEFAULT_S3: u64,
271    const DEFAULT_P2: u64,
272    const DEFAULT_P2_EXT: u64,
273    const DEFAULT_LOCKOUT: u64,
274    const DEFAULT_MAX_SECURITY_ATTEMPTS: u8,
275    const MAX_SEED: usize,
276    const MAX_PERIODIC: usize,
277    H,
278    S,
279> where
280    H: ServerHandler<S>,
281    S: SecurityProvider,
282{
283    config: ServerConfig<MAX_SESSIONS, MAX_SERVICES, MAX_DIDS, MAX_SECURITY_LEVELS>,
284    handler: H,
285    security_provider: S,
286    address: NodeAddress,
287    session: SessionState,
288    security: SecurityState<MAX_SEED, MAX_SECURITY_LEVELS>,
289    periodic: PeriodicState<MAX_PERIODIC>,
290    outbox: Vec<(NodeAddress, Vec<u8, MAX_FRAME>), MAX_OUTBOX>,
291
292    /// Whether pending requests should be dropped.
293    drop_requests: bool,
294}
295
296impl<
297        const MAX_FRAME: usize,
298        const MAX_OUTBOX: usize,
299        const MAX_SESSIONS: usize,
300        const MAX_SERVICES: usize,
301        const MAX_DIDS: usize,
302        const MAX_SECURITY_LEVELS: usize,
303        const DEFAULT_S3: u64,
304        const DEFAULT_P2: u64,
305        const DEFAULT_P2_EXT: u64,
306        const DEFAULT_LOCKOUT: u64,
307        const DEFAULT_MAX_SECURITY_ATTEMPTS: u8,
308        const MAX_SEED: usize,
309        const MAX_PERIODIC: usize,
310        H,
311        S,
312    >
313    UdsServer<
314        MAX_FRAME,
315        MAX_OUTBOX,
316        MAX_SESSIONS,
317        MAX_SERVICES,
318        MAX_DIDS,
319        MAX_SECURITY_LEVELS,
320        DEFAULT_S3,
321        DEFAULT_P2,
322        DEFAULT_P2_EXT,
323        DEFAULT_LOCKOUT,
324        DEFAULT_MAX_SECURITY_ATTEMPTS,
325        MAX_SEED,
326        MAX_PERIODIC,
327        H,
328        S,
329    >
330where
331    H: ServerHandler<S>,
332    S: SecurityProvider,
333{
334    pub fn new(
335        config: ServerConfig<MAX_SESSIONS, MAX_SERVICES, MAX_DIDS, MAX_SECURITY_LEVELS>,
336        handler: H,
337        security_provider: S,
338        address: NodeAddress,
339    ) -> Self {
340        Self {
341            session: SessionState::new(config.default_session_type.into()),
342            config,
343            handler,
344            security_provider,
345            address,
346            security: SecurityState::new(),
347            periodic: PeriodicState::new(),
348            outbox: Vec::new(),
349            drop_requests: false
350        }
351    }
352
353    // region: SimNode surface
354
355    pub fn set_drop_requests(&mut self, status: bool) {
356        self.drop_requests = status;
357    }
358
359    pub fn drop_requests(&self) -> bool {
360        self.drop_requests
361    }
362
363    pub fn address(&self) -> &NodeAddress {
364        &self.address
365    }
366
367    pub fn set_session_type(&mut self, session_type: u8) {
368        self.session.session_type = session_type;
369    }
370
371    pub fn session_type(&self) -> u8 {
372        self.session.session_type
373    }
374
375    pub fn set_security_level(&mut self, level: u8) {
376        self.session.security_level = level;
377    }
378
379    pub fn security_level(&self) -> u8 {
380        self.session.security_level
381    }
382
383    pub fn reset_security_state(&mut self) {
384        self.security.reset();
385    }
386
387    /// Receives a raw UDS frame from `src`.
388    ///
389    /// Wraps the bytes in a [`UdsFrame`] and uses [`UdsFrameExt`] for
390    /// protocol-level decisions before dispatching to service handlers.
391    /// Typed message decode via `to_message()` is deferred to individual
392    /// handlers that need structured field access.
393    pub fn handle(
394        &mut self,
395        src: &NodeAddress,
396        data: &[u8],
397        now: Instant,
398    ) -> Result<(), ServerError<H::Error>> {
399        if self.drop_requests {
400            #[cfg(feature = "defmt")]
401            defmt::info!("uds request dropped: {=[u8]}", data);
402
403            return Ok(());
404        }
405
406        self.session.last_rx = now;
407
408        let frame = UdsFrame::from_slice(data);
409
410        // Validate frame has at minimum a SID byte
411        if let Err(e) = frame.validate() {
412            return Err(ServerError::Codec(e));
413        }
414
415        let sid = match frame.service_identifier() {
416            Some(s) => s,
417            None => return self.nrc_raw(src, 0x00, H::Error::service_not_supported().into(), now),
418        };
419
420        // Guard: service must be supported in the active session
421        let sid_byte = sid.discriminant();
422        if let Err(nrc) = self.guard_service(sid_byte) {
423            return self.nrc_raw(src, sid_byte, nrc, now);
424        }
425
426        // Suppress bit - extracted here at the frame level before any
427        // typed decode. Each handler receives this as a plain bool.
428        let suppressed = frame.is_suppressed();
429
430        match sid {
431            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::TesterPresent) => {
432                self.on_tester_present(src, &frame, suppressed, now)
433            }
434
435            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::DiagnosticSessionControl) => {
436                self.on_session_control(src, &frame, suppressed, now)
437            }
438
439            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::EcuReset) => {
440                self.on_ecu_reset(src, &frame, suppressed, now)
441            }
442
443            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::SecurityAccess) => {
444                self.on_security_access(src, &frame, suppressed, now)
445            }
446
447            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::ReadDataByIdentifier) => {
448                self.on_read_did(src, &frame, suppressed, now)
449            }
450
451            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::WriteDataByIdentifier) => {
452                self.on_write_did(src, &frame, suppressed, now)
453            }
454
455            ServiceIdentifier::UdsServiceRequest(
456                UdsServiceRequest::ReadDataByPeriodicIdentifier,
457            ) => self.on_periodic_did(src, &frame, suppressed, now),
458
459            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::RoutineControl) => {
460                self.on_routine_control(src, &frame, suppressed, now)
461            }
462
463            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::CommunicationControl) => {
464                self.on_communication_control(src, &frame, suppressed, now)
465            }
466
467            ServiceIdentifier::UdsServiceRequest(
468                UdsServiceRequest::InputOutputControlByIdentifier,
469            ) => self.on_io_control(src, &frame, suppressed, now),
470
471            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::RequestDownload) => {
472                self.on_request_download(src, &frame, suppressed, now)
473            }
474
475            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::TransferData) => {
476                self.on_transfer_data(src, &frame, suppressed, now)
477            }
478
479            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::RequestTransferExit) => {
480                self.on_transfer_exit(src, &frame, suppressed, now)
481            }
482
483            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::RequestFileTransfer) => {
484                self.on_file_transfer(src, &frame, suppressed, now)
485            }
486
487            _ => self.nrc_raw(src, sid_byte, H::Error::service_not_supported().into(), now),
488        }
489    }
490
491    /// Advances internal timers - S3 watchdog and periodic DID scheduling.
492    pub fn tick(&mut self, now: Instant) -> Result<(), ServerError<H::Error>> {
493        self.check_s3(now);
494        self.dispatch_periodic(now)
495    }
496
497    /// Drains pending outbound frames into `out`.
498    pub fn drain_outbox(
499        &mut self,
500        out: &mut Vec<(NodeAddress, Vec<u8, MAX_FRAME>), MAX_OUTBOX>,
501    ) -> usize {
502        let n = self.outbox.len();
503        for item in self.outbox.drain(..) {
504            #[cfg(feature = "defmt")]
505            defmt::unwrap!(out.push(item)); // unlikely
506
507            #[cfg(not(feature = "defmt"))]
508            let _ = out.push(item);
509        }
510        n
511    }
512
513    // endregion: SimNode surface
514
515    // region: Session helpers
516
517    fn current_session(&self) -> Option<&SessionConfig> {
518        self.config.find_session(self.session.session_type)
519    }
520
521    fn check_s3(&mut self, now: Instant) {
522        if self.session.is_default() {
523            return;
524        }
525
526        let s3 = self
527            .current_session()
528            .map(|s| s.s3_timeout)
529            .unwrap_or(Duration::from_millis(DEFAULT_S3));
530
531        if let Some(elapsed) = now.checked_duration_since(self.session.last_rx) && s3.as_micros() > 0 {
532            if elapsed > s3 {
533                self.session.session_type = self.config.default_session_type.into();
534                self.session.security_level = 0;
535                self.security.clear_pending();
536            }
537        }
538    }
539
540    fn guard_service(&self, sid: u8) -> Result<(), u8> {
541        if !self.config.service_allowed(sid, self.session.session_type) {
542            return Err(H::Error::service_not_supported_in_active_session().into());
543        }
544        if !self.config.service_unlocked(sid, self.security_level()) {
545            return Err(H::Error::security_access_denied().into());
546        }
547        Ok(())
548    }
549
550    fn guard_security(&self, required: u8) -> Result<(), u8> {
551        if required > 0 && self.session.security_level < required {
552            return Err(H::Error::security_access_denied().into());
553        }
554        Ok(())
555    }
556
557    // endregion: Session helpers
558
559    // region: Response helpers
560
561    fn enqueue(
562        &mut self,
563        dst: NodeAddress,
564        frame: Vec<u8, MAX_FRAME>,
565    ) -> Result<(), ServerError<H::Error>> {
566        if self.outbox.len() >= MAX_OUTBOX {
567            Err(ServerError::OutboxFull)
568        } else {
569            #[cfg(feature = "defmt")]
570            defmt::unwrap!(self.outbox.push((dst, frame))); // unlikely
571
572            #[cfg(not(feature = "defmt"))]
573            self.outbox.push((dst, frame));
574
575            Ok(())
576        }
577    }
578
579    fn pos(
580        &mut self,
581        dst: &NodeAddress,
582        request_sid: u8,
583        payload: &[u8],
584        _now: Instant,
585    ) -> Result<(), ServerError<H::Error>> {
586        let mut frame: Vec<u8, MAX_FRAME> = Vec::new();
587
588        #[cfg(feature = "defmt")]
589        {
590            defmt::unwrap!(frame.push(request_sid | 0x40));
591            defmt::unwrap!(frame.extend_from_slice(payload));
592        }
593
594        #[cfg(not(feature = "defmt"))]
595        {
596            let _ = frame.push(request_sid | 0x40);
597            let _ = frame.extend_from_slice(payload);
598        }
599
600
601        self.enqueue(dst.clone(), frame)
602    }
603
604    fn nrc(
605        &mut self,
606        dst: &NodeAddress,
607        request_sid: u8,
608        error: H::Error,
609        _now: Instant,
610    ) -> Result<(), ServerError<H::Error>> {
611        let nrc_byte: u8 = error.into();
612        self.nrc_raw(dst, request_sid, nrc_byte, _now)
613    }
614
615    fn nrc_raw(
616        &mut self,
617        dst: &NodeAddress,
618        request_sid: u8,
619        nrc_byte: u8,
620        _now: Instant,
621    ) -> Result<(), ServerError<H::Error>> {
622        let mut frame: Vec<u8, MAX_FRAME> = Vec::new();
623
624        #[cfg(feature = "defmt")]
625        {
626            defmt::unwrap!(frame.push(0x7F));
627            defmt::unwrap!(frame.push(request_sid));
628            defmt::unwrap!(frame.push(nrc_byte));
629        }
630
631        #[cfg(not(feature = "defmt"))]
632        {
633            let _ = frame.push(0x7F);
634            let _ = frame.push(request_sid);
635            let _ = frame.push(nrc_byte);
636        }
637
638        self.enqueue(dst.clone(), frame)
639    }
640
641    // endregion: Response helpers
642
643    // region: Service handlers
644    //
645    // Each handler receives:
646    //   - `frame` - the raw UdsFrame for sub-function/payload access
647    //   - `suppressed` - suppress bit already extracted at dispatch
648    //
649    // Typed decode via `frame.to_message()` is used only where structured
650    // field access is needed. Services that only need the sub-function value
651    // and a payload slice never allocate a typed message.
652
653    fn on_tester_present(
654        &mut self,
655        src: &NodeAddress,
656        frame: &UdsFrame<'_>,
657        suppressed: bool,
658        now: Instant,
659    ) -> Result<(), ServerError<H::Error>> {
660        // TesterPresent: sub-function is always 0x00.
661        // The only meaningful information is the suppress bit.
662        if suppressed {
663            return Ok(());
664        }
665        // Echo sub-function value (suppress bit cleared) in response.
666        let sf = frame.sub_function_value().unwrap_or(0x00);
667        self.pos(src, 0x3E, &[sf], now)
668    }
669
670    fn on_session_control(
671        &mut self,
672        src: &NodeAddress,
673        frame: &UdsFrame<'_>,
674        suppressed: bool,
675        now: Instant,
676    ) -> Result<(), ServerError<H::Error>> {
677        // Sub-function value IS the session type byte.
678        let session_type = match frame.sub_function_value() {
679            Some(v) => v,
680            None => {
681                return self.nrc(
682                    src,
683                    0x10,
684                    H::Error::incorrect_message_length_or_invalid_format(),
685                    now,
686                )
687            }
688        };
689
690        if self.config.find_session(session_type).is_none() {
691            return self.nrc(src, 0x10, H::Error::sub_function_not_supported(), now);
692        }
693
694        let mut ctx = self.create_request_context();
695        let result = self.handler.session_control(&mut ctx, session_type);
696        self.handle_request_context(ctx);
697
698        if let Err(err) = result {
699            return self.nrc(src, 0x10, err, now);
700        }
701        
702        self.session.session_type = session_type;
703        self.session.security_level = 0;
704        self.session.last_rx = now;
705        self.security.clear_pending();
706        
707        if suppressed {
708            return Ok(());
709        }
710
711        let (p2_ms, p2_ext_ms) = self
712            .config
713            .find_session(session_type)
714            .map(|s| {
715                (
716                    s.p2_timeout.as_millis(),
717                    s.p2_extended_timeout.as_millis() / 10,
718                )
719            })
720            .unwrap_or((DEFAULT_P2, DEFAULT_P2_EXT));
721
722        let payload = [
723            session_type,
724            (p2_ms >> 8) as u8,
725            p2_ms as u8,
726            (p2_ext_ms >> 8) as u8,
727            p2_ext_ms as u8,
728        ];
729        self.pos(src, 0x10, &payload, now)
730    }
731
732    fn on_ecu_reset(
733        &mut self,
734        src: &NodeAddress,
735        frame: &UdsFrame<'_>,
736        suppressed: bool,
737        now: Instant,
738    ) -> Result<(), ServerError<H::Error>> {
739        // Sub-function value IS the reset type byte.
740        let reset_type = match frame.sub_function_value() {
741            Some(v) => v,
742            None => {
743                return self.nrc(
744                    src,
745                    0x11,
746                    H::Error::incorrect_message_length_or_invalid_format(),
747                    now,
748                )
749            }
750        };
751
752        let mut ctx = self.create_request_context();
753
754        let result = self.handler
755            .ecu_reset(&mut ctx, reset_type);
756
757        self.handle_request_context(ctx);
758
759        if let Err(err) = result {
760            return self.nrc(src, 0x11, err, now);
761        }
762
763        if !suppressed {
764            self.pos(src, 0x11, &[reset_type], now)?;
765        }
766
767        Ok(())
768    }
769
770    fn on_security_access(
771        &mut self,
772        src: &NodeAddress,
773        frame: &UdsFrame<'_>,
774        _suppressed: bool, // SecurityAccess has no suppress bit
775        now: Instant,
776    ) -> Result<(), ServerError<H::Error>> {
777        // Access type byte: odd = RequestSeed, even = SendKey.
778        let access_type = match frame.sub_function_value() {
779            Some(v) => v,
780            None => {
781                return self.nrc(
782                    src,
783                    0x27,
784                    H::Error::incorrect_message_length_or_invalid_format(),
785                    now,
786                )
787            }
788        };
789
790        let is_request_seed = access_type % 2 != 0;
791
792        if is_request_seed {
793            let level = access_type;
794
795            if self.security.is_locked(level, now) {
796                return self.nrc(src, 0x27, H::Error::required_time_delay_not_expired(), now);
797            }
798
799            let Some(config) = self.config.find_security_level(level) else {
800                return self.nrc(src, 0x27, H::Error::sub_function_not_supported(), now);
801            };
802
803            let mut frame: Vec<u8, MAX_FRAME> = Vec::new();
804
805            if self.security.pending_level == level
806                && !self.security.pending_seed.is_empty()
807                && self.security.pending_seed.len() == config.seed_length
808            {
809                #[cfg(feature = "defmt")]
810                {
811                    defmt::unwrap!(frame.push(0x27 | 0x40));
812                    defmt::unwrap!(frame.push(level));
813                    defmt::unwrap!(frame.extend_from_slice(self.security.pending_seed.as_slice()));
814                }
815                #[cfg(not(feature = "defmt"))]
816                {
817                    let _ = frame.push(0x27 | 0x40);
818                    let _ = frame.push(level);
819                    let _ = frame.extend_from_slice(self.security.pending_seed.as_slice());
820                }
821                return self.enqueue(src.clone(), frame);
822            }
823
824            let mut ctx = self.create_request_context();
825            let result = self.handler.security_access(&mut ctx, level, &[]);
826            self.handle_request_context(ctx);
827
828            if let Err(err) = result {
829                return self.nrc_raw(src, 0x27, err.into(), now);
830            }
831
832            let mut seed_buf = [0u8; MAX_SEED];
833            let result = self
834                .security_provider
835                .generate_seed(level, &mut seed_buf)
836                .map_err(|_| H::Error::conditions_not_correct());
837
838            let seed_len = match result {
839                Ok(v) => v,
840                Err(err) => {
841                    return self.nrc_raw(src, 0x27, err.into(), now);
842                }
843            };
844            
845            self.security.pending_seed.clear();
846            self.security.pending_level = level;
847
848            #[cfg(feature = "defmt")]
849            {
850                defmt::unwrap!(self.security.pending_seed.extend_from_slice(&seed_buf[..seed_len]));
851                defmt::unwrap!(frame.push(0x27 | 0x40));
852                defmt::unwrap!(frame.push(level));
853                defmt::unwrap!(frame.extend_from_slice(&seed_buf[..seed_len]));
854            }
855
856            #[cfg(not(feature = "defmt"))]
857            {
858                let _ = self.security.pending_seed.extend_from_slice(&seed_buf[..seed_len]);
859                let _ = frame.push(0x27 | 0x40);
860                let _ = frame.push(level);
861                let _ = frame.extend_from_slice(&seed_buf[..seed_len]);
862            }
863
864            self.enqueue(src.clone(), frame)
865        } else {
866            // SendKey - key bytes are the payload after the sub-function byte.
867            let level = access_type - 1; // RequestSeed level
868
869            if self.security.is_locked(level, now) {
870                return self.nrc(src, 0x27, H::Error::required_time_delay_not_expired(), now);
871            }
872            if self.security.pending_level != level || self.security.pending_seed.is_empty() {
873                return self.nrc(src, 0x27, H::Error::request_sequence_error(), now);
874            }
875
876            // Key bytes are the payload after the access_type byte.
877            // frame.payload() is everything after SID - key starts at payload[1].
878            let key = frame.payload().get(1..).unwrap_or(&[]);
879
880            let mut ctx = self.create_request_context();
881            let result = self.handler.security_access(&mut ctx, level, key);
882            self.handle_request_context(ctx);
883
884            if let Err(err) = result {
885                return self.nrc_raw(src, 0x27, err.into(), now);
886            }
887
888            let level_cfg = self.config.find_security_level(level);
889            let max_attempts = level_cfg
890                .map(|l| l.max_attempts)
891                .flatten()
892                .unwrap_or(DEFAULT_MAX_SECURITY_ATTEMPTS);
893            let lockout_dur = level_cfg
894                .map(|l| l.lockout_duration)
895                .flatten()
896                .unwrap_or(Duration::from_millis(DEFAULT_LOCKOUT));
897
898            let seed = self.security.pending_seed.clone();
899
900            match self.security_provider.validate_key(level, &seed, key) {
901                Ok(()) => {
902                    self.security.reset_failed(level);
903                    self.security.clear_pending();
904                    self.session.security_level = level;
905                    self.pos(src, 0x27, &[access_type], now)
906                }
907                Err(_) => {
908                    self.security.increment_failed(level);
909                    if self.security.failed_count(level) >= max_attempts {
910                        self.security.set_lockout(level, now + lockout_dur);
911                        self.security.clear_pending();
912                        return self.nrc(src, 0x27, H::Error::exceeded_number_of_attempts(), now);
913                    }
914                    self.nrc(src, 0x27, H::Error::invalid_key(), now)
915                }
916            }
917        }
918    }
919
920    fn on_read_did(
921        &mut self,
922        src: &NodeAddress,
923        frame: &UdsFrame<'_>,
924        _suppressed: bool, // ReadDataByIdentifier has no sub-function
925        now: Instant,
926    ) -> Result<(), ServerError<H::Error>> {
927        // Payload is pairs of DID bytes: [DID_high, DID_low, DID_high, DID_low, ...]
928        let payload = frame.payload();
929        if payload.len() < 2
930            || (!self.config.allow_read_many_dids && payload.len() != 2)
931            || payload.len() % 2 != 0
932        {
933            return self.nrc(
934                src,
935                0x22,
936                H::Error::incorrect_message_length_or_invalid_format(),
937                now,
938            );
939        }
940
941        let mut resp: Vec<u8, MAX_FRAME> = Vec::new();
942
943        for chunk in payload.chunks_exact(2) {
944            let did = u16::from_be_bytes([chunk[0], chunk[1]]);
945
946            if !self.config.did_readable(did, self.session.session_type) {
947                return self.nrc(src, 0x22, H::Error::request_out_of_range(), now);
948            }
949            let required_sec = self
950                .config
951                .find_did(did)
952                .map(|d| d.security_level)
953                .unwrap_or(0);
954            if let Err(nrc) = self.guard_security(required_sec) {
955                return self.nrc_raw(src, 0x22, nrc, now);
956            }
957
958            #[cfg(feature = "defmt")]
959            {
960                defmt::unwrap!(resp.push(chunk[0]));
961                defmt::unwrap!(resp.push(chunk[1]));
962            }
963
964            #[cfg(not(feature = "defmt"))]
965            {
966                let _ = resp.push(chunk[0]);
967                let _ = resp.push(chunk[1]);
968            }
969
970            let mut ctx = self.create_request_context();
971
972            let mut data_buf = [0u8; MAX_FRAME];
973            let result = self
974                .handler
975                .read_did(&mut ctx, did, &mut data_buf);
976
977            self.handle_request_context(ctx);
978
979            let len = match result {
980                Ok(v) => v,
981                Err(err) => {
982                    return self.nrc_raw(src, 0x22, err.into(), now);
983                }
984            };
985
986            #[cfg(feature = "defmt")]
987            defmt::unwrap!(resp.extend_from_slice(&data_buf[..len]));
988
989            #[cfg(not(feature = "defmt"))]
990            let _ = resp.extend_from_slice(&data_buf[..len]);
991        }
992
993        self.pos(src, 0x22, &resp, now)
994    }
995
996    fn on_write_did(
997        &mut self,
998        src: &NodeAddress,
999        frame: &UdsFrame<'_>,
1000        _suppressed: bool,
1001        now: Instant,
1002    ) -> Result<(), ServerError<H::Error>> {
1003        let payload = frame.payload();
1004        if payload.len() < 3 {
1005            return self.nrc(
1006                src,
1007                0x2E,
1008                H::Error::incorrect_message_length_or_invalid_format(),
1009                now,
1010            );
1011        }
1012
1013        let did = u16::from_be_bytes([payload[0], payload[1]]);
1014        let data_rec = &payload[2..];
1015
1016        if !self.config.did_writable(did, self.session.session_type) {
1017            return self.nrc(src, 0x2E, H::Error::request_out_of_range(), now);
1018        }
1019        let required_sec = self
1020            .config
1021            .find_did(did)
1022            .map(|d| d.security_level)
1023            .unwrap_or(0);
1024        if let Err(nrc) = self.guard_security(required_sec) {
1025            return self.nrc_raw(src, 0x2E, nrc, now);
1026        }
1027
1028        let mut ctx = self.create_request_context();
1029
1030        let result = self.handler
1031            .write_did(&mut ctx, did, data_rec);
1032
1033        self.handle_request_context(ctx);
1034
1035        if let Err(err) = result {
1036            return self.nrc_raw(src, 0x2E, err.into(), now);
1037        }
1038
1039        self.pos(src, 0x2E, &payload[..2], now)
1040    }
1041
1042    fn on_periodic_did(
1043        &mut self,
1044        src: &NodeAddress,
1045        frame: &UdsFrame<'_>,
1046        _suppressed: bool,
1047        now: Instant,
1048    ) -> Result<(), ServerError<H::Error>> {
1049        let payload = frame.payload();
1050        if payload.is_empty() {
1051            return self.nrc(
1052                src,
1053                0x2A,
1054                H::Error::incorrect_message_length_or_invalid_format(),
1055                now,
1056            );
1057        }
1058
1059        // Byte 0 is transmission mode, remaining bytes are periodic DID identifiers.
1060        let mode = payload[0];
1061        let periodic_ids = payload.get(1..).unwrap_or(&[]);
1062
1063        let mut ctx = self.create_request_context();
1064        let result = self.handler.periodic_did(&mut ctx, mode, periodic_ids);
1065        self.handle_request_context(ctx);
1066
1067        if let Err(err) = result {
1068            return self.nrc_raw(src, 0x2A, err.into(), now);
1069        }
1070
1071        match mode {
1072            // stopSending
1073            0x04 => {
1074                for &id in periodic_ids {
1075                    self.periodic.cancel(0xF200u16 | id as u16, src);
1076                }
1077                self.pos(src, 0x2A, &[mode], now)
1078            }
1079            0x01 | 0x02 | 0x03 => {
1080                let requested_interval = match mode {
1081                    0x01 => periodic::SLOW,
1082                    0x02 => periodic::MEDIUM,
1083                    _ => periodic::FAST,
1084                };
1085
1086                for &id in periodic_ids {
1087                    let did = 0xF200u16 | id as u16;
1088
1089                    if !self.config.did_readable(did, self.session.session_type) {
1090                        return self.nrc(src, 0x2A, H::Error::request_out_of_range(), now);
1091                    }
1092
1093                    let effective = self
1094                        .config
1095                        .find_did(did)
1096                        .map(|d| requested_interval.max(d.min_periodic_interval))
1097                        .unwrap_or(requested_interval);
1098
1099                    self.periodic.register(did, effective, src.clone(), now);
1100                }
1101                self.pos(src, 0x2A, &[mode], now)
1102            }
1103            _ => self.nrc(src, 0x2A, H::Error::sub_function_not_supported(), now),
1104        }
1105    }
1106
1107    fn on_routine_control(
1108        &mut self,
1109        src: &NodeAddress,
1110        frame: &UdsFrame<'_>,
1111        suppressed: bool,
1112        now: Instant,
1113    ) -> Result<(), ServerError<H::Error>> {
1114        // Sub-function value is the routine control type (0x01/0x02/0x03).
1115        // Payload after SID: [sub_function, routine_id_high, routine_id_low, option_record...]
1116        let payload = frame.payload();
1117        if payload.len() < 3 {
1118            return self.nrc(
1119                src,
1120                0x31,
1121                H::Error::incorrect_message_length_or_invalid_format(),
1122                now,
1123            );
1124        }
1125
1126        let sub_function = frame.sub_function_value().unwrap_or(0);
1127        let routine_id = u16::from_be_bytes([payload[1], payload[2]]);
1128        let option_record = payload.get(3..).unwrap_or(&[]);
1129
1130        let mut ctx = self.create_request_context();
1131
1132        let mut buf = [0u8; MAX_FRAME];
1133        let result = self
1134            .handler
1135            .routine_control(&mut ctx, routine_id, sub_function, option_record, &mut buf);
1136
1137        self.handle_request_context(ctx);
1138
1139        let len = match result {
1140            Ok(v) => v,
1141            Err(err) => {
1142                return self.nrc_raw(src, 0x31, err.into(), now);
1143            }
1144        };
1145
1146        if suppressed {
1147            return Ok(());
1148        }
1149
1150        let mut resp: Vec<u8, MAX_FRAME> = Vec::new();
1151
1152        #[cfg(feature = "defmt")]
1153        {
1154            defmt::unwrap!(resp.push(sub_function));
1155            defmt::unwrap!(resp.push(payload[1]));
1156            defmt::unwrap!(resp.push(payload[2]));
1157            defmt::unwrap!(resp.extend_from_slice(&buf[..len]));
1158        }
1159
1160        #[cfg(not(feature = "defmt"))]
1161        {
1162            let _ = resp.push(sub_function);
1163            let _ = resp.push(payload[1]);
1164            let _ = resp.push(payload[2]);
1165            let _ = resp.extend_from_slice(&buf[..len]);
1166        }
1167
1168        self.pos(src, 0x31, &resp, now)
1169    }
1170
1171    fn on_communication_control(
1172        &mut self,
1173        src: &NodeAddress,
1174        frame: &UdsFrame<'_>,
1175        suppressed: bool,
1176        now: Instant,
1177    ) -> Result<(), ServerError<H::Error>> {
1178        let payload = frame.payload();
1179        if payload.len() < 2 {
1180            return self.nrc(
1181                src,
1182                0x28,
1183                H::Error::incorrect_message_length_or_invalid_format(),
1184                now,
1185            );
1186        }
1187
1188        let control_type = frame.sub_function_value().unwrap_or(0);
1189        let comm_type = payload[1];
1190
1191        let mut ctx = self.create_request_context();
1192
1193        let result = self.handler
1194            .communication_control(&mut ctx, control_type, comm_type);
1195
1196        self.handle_request_context(ctx);
1197
1198        if let Err(err) = result {
1199            return self.nrc_raw(src, 0x28, err.into(), now);
1200        }
1201
1202        if suppressed {
1203            return Ok(());
1204        }
1205
1206        self.pos(src, 0x28, &[control_type], now)
1207    }
1208
1209    fn on_io_control(
1210        &mut self,
1211        src: &NodeAddress,
1212        frame: &UdsFrame<'_>,
1213        _suppressed: bool,
1214        now: Instant,
1215    ) -> Result<(), ServerError<H::Error>> {
1216        let payload = frame.payload();
1217        if payload.len() < 3 {
1218            return self.nrc(
1219                src,
1220                0x2F,
1221                H::Error::incorrect_message_length_or_invalid_format(),
1222                now,
1223            );
1224        }
1225
1226        let did = u16::from_be_bytes([payload[0], payload[1]]);
1227        let control_param = payload[2];
1228        let control_state = payload.get(3..).unwrap_or(&[]);
1229
1230        let mut ctx = self.create_request_context();
1231
1232        let mut buf = [0u8; MAX_FRAME];
1233        let result = self
1234            .handler
1235            .io_control(&mut ctx, did, control_param, control_state, &mut buf);
1236
1237        self.handle_request_context(ctx);
1238
1239        let len = match result {
1240            Ok(v) => v,
1241            Err(err) => {
1242                return self.nrc_raw(src, 0x2F, err.into(), now);
1243            }
1244        };
1245
1246        let mut resp: Vec<u8, MAX_FRAME> = Vec::new();
1247
1248        #[cfg(feature = "defmt")]
1249        {
1250            defmt::unwrap!(resp.push(payload[0]));
1251            defmt::unwrap!(resp.push(payload[1]));
1252            defmt::unwrap!(resp.extend_from_slice(&buf[..len]));
1253        }
1254
1255        #[cfg(not(feature = "defmt"))]
1256        {
1257            let _ = resp.push(payload[0]);
1258            let _ = resp.push(payload[1]);
1259            let _ = resp.extend_from_slice(&buf[..len]);
1260        }
1261
1262        self.pos(src, 0x2F, &resp, now)
1263    }
1264
1265    fn on_request_download(
1266        &mut self,
1267        src: &NodeAddress,
1268        frame: &UdsFrame<'_>,
1269        _suppressed: bool,
1270        now: Instant,
1271    ) -> Result<(), ServerError<H::Error>> {
1272        // Payload: [data_format_identifier, address_and_length_format,
1273        //           memory_address..., memory_size...]
1274        let payload = frame.payload();
1275        if payload.len() < 3 {
1276            return self.nrc(
1277                src,
1278                0x34,
1279                H::Error::incorrect_message_length_or_invalid_format(),
1280                now,
1281            );
1282        }
1283
1284        let data_format = payload[0];
1285        let addr_and_len_format = payload[1];
1286        let addr_len = (addr_and_len_format >> 4) as usize;
1287        let size_len = (addr_and_len_format & 0x0F) as usize;
1288
1289        if payload.len() < 2 + addr_len + size_len {
1290            return self.nrc(
1291                src,
1292                0x34,
1293                H::Error::incorrect_message_length_or_invalid_format(),
1294                now,
1295            );
1296        }
1297
1298        let memory_address = &payload[2..2 + addr_len];
1299        let memory_size = &payload[2 + addr_len..2 + addr_len + size_len];
1300
1301        let mut ctx = self.create_request_context();
1302
1303        let mut buf = [0u8; 64];
1304        let result = self
1305            .handler
1306            .request_download(&mut ctx, memory_address, memory_size, data_format, 0, &mut buf);
1307
1308        self.handle_request_context(ctx);
1309
1310        let len = match result {
1311            Ok(v) => v,
1312            Err(err) => {
1313                return self.nrc_raw(src, 0x34, err.into(), now);
1314            }
1315        };
1316
1317        self.pos(src, 0x34, &buf[..len], now)
1318    }
1319
1320    fn on_transfer_data(
1321        &mut self,
1322        src: &NodeAddress,
1323        frame: &UdsFrame<'_>,
1324        _suppressed: bool,
1325        now: Instant,
1326    ) -> Result<(), ServerError<H::Error>> {
1327        let payload = frame.payload();
1328        if payload.is_empty() {
1329            return self.nrc(
1330                src,
1331                0x36,
1332                H::Error::incorrect_message_length_or_invalid_format(),
1333                now,
1334            );
1335        }
1336
1337        let block_seq = payload[0];
1338        let data = payload.get(1..).unwrap_or(&[]);
1339
1340        let mut ctx = self.create_request_context();
1341
1342        let mut buf = [0u8; MAX_FRAME];
1343        let result = self
1344            .handler
1345            .transfer_data(&mut ctx, block_seq, data, &mut buf);
1346
1347        self.handle_request_context(ctx);
1348
1349        let len = match result {
1350            Ok(v) => v,
1351            Err(err) => {
1352                return self.nrc_raw(src, 0x36, err.into(), now);
1353            }
1354        };
1355
1356        let mut resp: Vec<u8, MAX_FRAME> = Vec::new();
1357
1358        #[cfg(feature = "defmt")]
1359        {
1360            defmt::unwrap!(resp.push(block_seq));
1361            defmt::unwrap!(resp.extend_from_slice(&buf[..len]));
1362        }
1363
1364        #[cfg(not(feature = "defmt"))]
1365        {
1366            let _ = resp.push(block_seq);
1367            let _ = resp.extend_from_slice(&buf[..len]);
1368        }
1369
1370        self.pos(src, 0x36, &resp, now)
1371    }
1372
1373    fn on_transfer_exit(
1374        &mut self,
1375        src: &NodeAddress,
1376        frame: &UdsFrame<'_>,
1377        _suppressed: bool,
1378        now: Instant,
1379    ) -> Result<(), ServerError<H::Error>> {
1380        let parameter_record = frame.payload();
1381
1382        let mut ctx = self.create_request_context();
1383
1384        let mut buf = [0u8; MAX_FRAME];
1385        let result = self
1386            .handler
1387            .request_transfer_exit(&mut ctx, parameter_record, &mut buf);
1388
1389        self.handle_request_context(ctx);
1390
1391        let len = match result {
1392            Ok(v) => v,
1393            Err(err) => {
1394                return self.nrc_raw(src, 0x37, err.into(), now);
1395            }
1396        };
1397
1398        self.pos(src, 0x37, &buf[..len], now)
1399    }
1400
1401    fn on_file_transfer(
1402        &mut self,
1403        src: &NodeAddress,
1404        frame: &UdsFrame<'_>,
1405        _suppressed: bool,
1406        now: Instant,
1407    ) -> Result<(), ServerError<H::Error>> {
1408        let payload = frame.payload();
1409        if payload.len() < 3 {
1410            return self.nrc(
1411                src,
1412                0x38,
1413                H::Error::incorrect_message_length_or_invalid_format(),
1414                now,
1415            );
1416        }
1417
1418        let operation = payload[0];
1419        // Bytes 1-2 are file path length (big-endian u16), rest is path
1420        let path_len = u16::from_be_bytes([payload[1], payload[2]]) as usize;
1421        let path = payload.get(3..3 + path_len).unwrap_or(&[]);
1422
1423        let mut ctx = self.create_request_context();
1424
1425        let mut buf = [0u8; MAX_FRAME];
1426        let result = self
1427            .handler
1428            .request_file_transfer(&mut ctx, operation, path, &mut buf);
1429
1430        self.handle_request_context(ctx);
1431
1432        let len = match result {
1433            Ok(v) => v,
1434            Err(err) => {
1435                return self.nrc_raw(src, 0x38, err.into(), now);
1436            }
1437        };
1438
1439        self.pos(src, 0x38, &buf[..len], now)
1440    }
1441
1442    // endregion: Service handlers
1443
1444    // region: Periodic dispatch
1445
1446    fn dispatch_periodic(&mut self, now: Instant) -> Result<(), ServerError<H::Error>> {
1447        let mut due: Vec<(u16, NodeAddress), MAX_PERIODIC> = Vec::new();
1448        self.periodic.collect_due(now, &mut due);
1449
1450        for (did, client) in &due {
1451            let mut ctx = self.create_request_context();
1452
1453            let mut data_buf = [0u8; MAX_FRAME];
1454            let result = self
1455                .handler
1456                .read_did(&mut ctx, *did, &mut data_buf);
1457
1458            self.handle_request_context(ctx);
1459
1460            let len = match result {
1461                Ok(v) => v,
1462                Err(err) => {
1463                    let nrc = err.into();
1464
1465                    #[cfg(feature = "defmt")]
1466                    defmt::error!("periodic error: {=u8}", nrc);
1467
1468                    self.periodic.cancel(*did, client);
1469                    continue;
1470                }
1471            };
1472
1473            // [periodic_data_identifier (1 byte), data_record (n bytes)]
1474            let did_low = (*did & 0xFF) as u8;
1475            let mut frame = Vec::new();
1476
1477            #[cfg(feature = "defmt")]
1478            {
1479                defmt::unwrap!(frame.push(did_low));
1480                defmt::unwrap!(frame.extend_from_slice(&data_buf[..len]));
1481            }
1482
1483            #[cfg(not(feature = "defmt"))]
1484            {
1485                let _ = frame.push(did_low);
1486                let _ = frame.extend_from_slice(&data_buf[..len]);
1487            }
1488
1489
1490            self.enqueue(client.clone(), frame)?;
1491            self.periodic.advance(*did, client, now);
1492        }
1493
1494        Ok(())
1495    }
1496
1497    fn create_request_context(&mut self) -> UdsRequestContext<S> {
1498        UdsRequestContext {
1499            session: self.session.clone(),
1500            security_provider: self.security_provider.clone(),
1501            drop_requests: false,
1502            clear_outbox: false,
1503            reset_security_state: false
1504        }
1505    }
1506
1507    fn handle_request_context(&mut self, ctx: UdsRequestContext<S>) {
1508        if ctx.session != self.session {
1509            self.session.session_type = ctx.session.session_type;
1510            self.session.security_level = ctx.session.security_level;
1511        }
1512        if ctx.clear_outbox {
1513            self.outbox.clear();
1514        }
1515        if ctx.reset_security_state {
1516            self.security.reset();
1517        }
1518        if ctx.drop_requests {
1519            self.drop_requests = true;
1520        }
1521    }
1522
1523    // endregion: Periodic dispatch
1524}
1525
1526// endregion: UdsServer
1527
1528#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1529pub struct UdsRequestContext<T>
1530where
1531    T: SecurityProvider
1532{
1533    pub session: SessionState,
1534    pub security_provider: T,
1535    pub(crate) drop_requests: bool,
1536    pub(crate) clear_outbox: bool,
1537    pub(crate) reset_security_state: bool,
1538}
1539
1540impl<T> UdsRequestContext<T>
1541where
1542    T: SecurityProvider
1543{
1544    pub fn drop_requests(&mut self) {
1545        self.drop_requests = true;
1546    }
1547
1548    pub fn clear_outbox(&mut self) {
1549        self.clear_outbox = true;
1550    }
1551
1552    pub fn reset_security_state(&mut self) {
1553        self.reset_security_state = true;
1554    }
1555}