1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2023.

//! This file contains the structs and methods associated with the Thread
//! networking layer. This represents a first attempt in Tock
//! to support Thread networking. The current implementation successfully
//! joins a Tock device as a child node to a Thread parent (tested using
//! OpenThread). This Thread capsule is a client to the UDP Mux.
//! The associated ThreadNetwork struct must be created in the `thread_network.rs`
//! component.
//!
//! The Userland interface is incredibly simple at this juncture. An application
//! can begin the Thread child/parent joining by issuing a syscall command
//! with the MLE/MAC key as an argument. Only one userspace application can use/join
//! the Thread network. Once a userspace application has joined the Thread network,
//! the Thread network is considered locked. After the Thread network
//! is "locked", other userspace applications attempting to join the network
//! will return a failure. This is temporary and will eventually be replaced.

// ------------------------------------------------------------------------------
// Current Limitations
// ------------------------------------------------------------------------------
// (1) A majority of the TLV fields used in the parent request/child id request
//     are hardcoded. Future implementations need to provide options for specifying
//     varied security policies.
// (2) Current implementation joins the Thread network sucessfully and consistently
//     but does not send update/heart beat messages to the parent prior to the child
//     timing out.
// (3) Currently no support for sending UDP messages across Thread interface. The
//     current interface is unusable for sending data. It can only be used to
//     join a network.

use crate::ieee802154::framer::{self, get_ccm_nonce};
use crate::net::ieee802154::{KeyId, MacAddress, Security, SecurityLevel};
use crate::net::ipv6::ip_utils::IPAddr;
use crate::net::network_capabilities::NetworkCapability;

use crate::net::ieee802154;
use crate::net::thread::thread_utils::generate_src_ipv6;
use crate::net::thread::thread_utils::ThreadState;
use crate::net::thread::thread_utils::MULTICAST_IPV6;
use crate::net::thread::thread_utils::THREAD_PORT_NUMBER;
use crate::net::thread::thread_utils::{
    encode_cryp_data, form_child_id_req, form_parent_req, mac_from_ipv6, MleCommand, NetworkKey,
    AUTH_DATA_LEN, AUX_SEC_HEADER_LENGTH, IPV6_LEN, SECURITY_SUITE_LEN,
};
use crate::net::udp::udp_port_table::UdpPortManager;
use crate::net::udp::udp_recv::UDPRecvClient;
use crate::net::udp::udp_send::{UDPSendClient, UDPSender};
use capsules_core::driver;

use core::cell::Cell;

use kernel::capabilities::UdpDriverCapability;
use kernel::errorcode::into_statuscode;
use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
use kernel::hil::symmetric_encryption::CCMClient;
use kernel::hil::symmetric_encryption::AES128CCM;
use kernel::hil::time;
use kernel::processbuffer::ReadableProcessBuffer;
use kernel::syscall::{CommandReturn, SyscallDriver};
use kernel::utilities::cells::MapCell;
use kernel::utilities::leasable_buffer::SubSliceMut;
use kernel::{ErrorCode, ProcessId};

const SECURITY_SUITE_ENCRYP: u8 = 0;
pub const DRIVER_NUM: usize = driver::NUM::Thread as usize;

/// Ids for read-only allow buffers
mod ro_allow {
    pub const WRITE: usize = 0;
    /// The number of allow buffers the kernel stores for this grant
    pub const COUNT: u8 = 1;
}

// /// Ids for read-write allow buffers
// mod rw_allow {
//     pub const READ: usize = 0;
//     pub const CFG: usize = 1;
//     pub const RX_CFG: usize = 2;
//     /// The number of allow buffers the kernel stores for this grant
//     pub const COUNT: u8 = 3;
// }

/// IDs for subscribed upcalls.
mod upcall {
    pub const JOINCOMPLETE: usize = 0;
}

#[derive(Default)]
pub struct App {}

#[allow(dead_code)]
pub struct ThreadNetworkDriver<'a, A: time::Alarm<'a>> {
    /// UDP sender
    sender: &'a dyn UDPSender<'a>,

    /// AES crypto engine for MLE encryption
    aes_crypto: &'a dyn AES128CCM<'a>,

    /// Alarm for timeouts
    alarm: &'a A,

    /// Grant of apps that use this thread driver.
    apps: Grant<App, UpcallCount<1>, AllowRoCount<{ ro_allow::COUNT }>, AllowRwCount<0>>,

    /// mac address of device
    src_mac_addr: [u8; 8],

    /// Maximum length payload that an app can transmit via this driver
    max_tx_pyld_len: usize,

    /// UDP bound port table (manages kernel bindings)
    port_table: &'static UdpPortManager,

    /// kernel buffer used for sending
    send_buffer: MapCell<SubSliceMut<'static, u8>>,

    /// kernel buffer used for receiving
    recv_buffer: MapCell<SubSliceMut<'static, u8>>,

    /// state machine for the Thread device
    state: MapCell<ThreadState>,

    /// UDP driver capability
    driver_send_cap: &'static dyn UdpDriverCapability,

    /// Network capability
    net_cap: &'static NetworkCapability,

    /// Frame counter for Thread MLE
    frame_count: Cell<u32>,

    /// Stored Thread network containing mac/MLE key
    networkkey: MapCell<NetworkKey>,

    /// Length of the message passed to the crypto engine
    crypto_sizelock: MapCell<usize>,
}

// Note: For now, we initialize the Thread state as empty.
// We replace the Thread state when the first userspace
// application calls the Thread capsule to initiate a Thread network.
// This serves to "lock" the Thread capsule to only one application.
// For now, Tock only supports one application using the Thread network.
// After the network is "locked" to one application, other userspace
// applications requesting to join a Thread network will fail.
impl<'a, A: time::Alarm<'a>> ThreadNetworkDriver<'a, A> {
    pub fn new(
        sender: &'a dyn UDPSender<'a>,
        aes_crypto: &'a dyn AES128CCM<'a>,
        alarm: &'a A,
        grant: Grant<App, UpcallCount<1>, AllowRoCount<{ ro_allow::COUNT }>, AllowRwCount<0>>,
        src_mac_addr: [u8; 8],
        max_tx_pyld_len: usize,
        port_table: &'static UdpPortManager,
        send_buffer: SubSliceMut<'static, u8>,
        recv_buffer: SubSliceMut<'static, u8>,
        driver_send_cap: &'static dyn UdpDriverCapability,
        net_cap: &'static NetworkCapability,
    ) -> ThreadNetworkDriver<'a, A> {
        ThreadNetworkDriver {
            sender,
            aes_crypto,
            alarm,
            apps: grant,
            src_mac_addr,
            max_tx_pyld_len,
            port_table,
            send_buffer: MapCell::new(send_buffer),
            recv_buffer: MapCell::new(recv_buffer),
            state: MapCell::empty(),
            driver_send_cap,
            net_cap,
            frame_count: Cell::new(5),
            networkkey: MapCell::empty(),
            crypto_sizelock: MapCell::empty(),
        }
    }

    /// Takes the MLE and MAC keys and replaces the networkkey
    pub fn set_networkkey(&self, mle_key: [u8; 16], mac_key: [u8; 16]) {
        self.networkkey.replace(NetworkKey { mle_key, mac_key });
    }

    fn send_parent_req(&self) {
        // UNCOMMENT TO DEBUG THREAD //
        // kernel::debug!("[Thread] Sending parent request...");

        // Panicking on unwrap indicates the state was taken without replacement
        // (unreachable with proper state machine implementation)
        let curr_state = self.state.take().unwrap();

        match curr_state {
            ThreadState::Detached => {
                // A parent request can only begin from a detached state. We utilize
                // helper functions to form the request and send the parent request
                // to the multicast IP/Mac Address
                self.state.replace(ThreadState::SendParentReq);
                let parent_req_mle = form_parent_req();
                let src_ipv6 = generate_src_ipv6(&self.src_mac_addr);
                self.thread_mle_send(&parent_req_mle, MULTICAST_IPV6, src_ipv6)
                    .err()
                    .map(|code| {
                        // Thread send failed sending parent req so we terminate and return
                        // to a detached state.
                        self.state.replace(ThreadState::Detached);

                        // UNCOMMENT TO DEBUG THREAD //
                        // kernel::debug!(
                        //     "[Thread] Failed sending MLE parent request - crypto operation error."
                        // );
                        self.terminate_child_join(Err(code));
                    });
            }
            ThreadState::SEDActive(_, _)
            | ThreadState::SendUpdate(_, _)
            | ThreadState::SendUDPMsg => {
                // These states constitute a device that has previously sucessfully
                // joined the network. There is no need to issue a new parent request.
                // Replace state, and terminate.
                self.state.replace(curr_state);
                self.terminate_child_join(Err(ErrorCode::ALREADY));
            }
            _ => {
                // All other Thread states indicate that the thread device has already
                // begun the process of connecting to a parent device. Terminate the parent request.
                // Replace state, and terminate.
                self.state.replace(curr_state);
                self.terminate_child_join(Err(ErrorCode::BUSY));
            }
        };
    }

    fn thread_mle_send(
        &self,
        mle_buf: &[u8],
        dest_addr: IPAddr,
        src_addr: IPAddr,
    ) -> Result<(), ErrorCode> {
        // TODO: Hardcoded encryption suite and auxiliary security; add support to send encrypted/unencrypted MLE

        // We hardcode the auxiliary security for now
        let security = Security {
            level: SecurityLevel::EncMic32,
            asn_in_nonce: false,
            frame_counter: Some(self.frame_count.get()),
            key_id: KeyId::Source4Index([0, 0, 0, 0], 1),
        };

        // Begin cryptographic and sending procedure for the MLE message
        self.send_buffer
            .take()
            .map_or(Err(ErrorCode::NOMEM), |send_buffer| {
                self.perform_crypt_op(src_addr, dest_addr, security, mle_buf, send_buffer.take())
                    .map_err(|(code, buf)| {
                        // Error occured with cryptographic operation, replace buffer
                        // for future transmissions and return error code
                        self.send_buffer.replace(SubSliceMut::new(buf));
                        code
                    })
            })
    }

    fn recv_logic(&self, sender_ip: IPAddr) -> Result<(), ErrorCode> {
        // This function is called once the received MLE payload has been placed
        // into the recv_buffer. The function handles the message and responds accordingly

        self.recv_buffer
            .take()
            .map_or(Err(ErrorCode::NOMEM), |mut recv_buf| {
                if recv_buf[0] == MleCommand::ParentResponse as u8 {
                    // Received Parent Response -> form Child ID Request

                    // UNCOMMENT TO DEBUG THREAD //
                    // kernel::debug!("[Thread] Received Parent Response.");
                    // kernel::debug!("[Thread] Sending Child ID Request...");

                    let src_ipv6 = generate_src_ipv6(&self.src_mac_addr);

                    let (output, offset) =
                        form_child_id_req(recv_buf.as_slice(), self.frame_count.get())?;

                    // Advance state machine
                    self.state.replace(ThreadState::SendChildIdReq(sender_ip));

                    self.thread_mle_send(&output[..offset], sender_ip, src_ipv6)?;
                } else if recv_buf[0] == MleCommand::ChildIdResponse as u8 {
                    // Receive child id response -> advance state machine
                    self.state.replace(ThreadState::SEDActive(
                        sender_ip,
                        MacAddress::Long(mac_from_ipv6(sender_ip)),
                    ));

                    // TODO: once heart beats are implemented, we will set
                    // the timer here (as seen below)
                    // let curr_time = self.alarm.now();
                    // self.alarm.set_alarm(
                    //     curr_time,
                    //     time::ConvertTicks::ticks_from_seconds(self.alarm, 5),
                    // );
                }

                recv_buf.reset();
                self.recv_buffer.replace(recv_buf);
                Ok(())
            })
    }

    fn terminate_child_join(&self, res: Result<(), ErrorCode>) {
        // Function to schedule upcall to userland on parent request termination. Notifies
        // userland of the reason for termination with the first argument.

        self.apps.each(|_, _, kernel_data| {
            kernel_data
                .schedule_upcall(upcall::JOINCOMPLETE, (into_statuscode(res), 0, 0))
                .ok();
        });
    }

    fn perform_crypt_op(
        &self,
        src_addr: IPAddr,
        dst_addr: IPAddr,
        security: Security,
        payload: &[u8],
        buf: &'static mut [u8],
    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
        // Wrapper function for performing the AES-128CCM encryption. This function generates the nonce,
        // sets the nonce/key for the crypto engine, generates the authenticated data, and initiates
        // the crypto operation.

        // Note: The payload argument does not include aux sec header

        // Obtain and unwrap frame counter
        let frame_counter = security.frame_counter;
        if frame_counter.is_none() {
            // UNCOMMENT TO DEBUG THREAD //
            // kernel::debug!("[Thread] Malformed auxiliary security header");
            return Err((ErrorCode::INVAL, buf));
        }

        // Generate nonce, obtain network key and set crypto engine accordingly
        let nonce = get_ccm_nonce(
            &mac_from_ipv6(src_addr),
            frame_counter.unwrap(),
            security.level,
        );
        let mle_key = self.networkkey.get();
        let mic_len = security.level.mic_len();
        match mle_key {
            Some(netkey) => {
                if self.aes_crypto.set_key(&netkey.mle_key).is_err()
                    || self.aes_crypto.set_nonce(&nonce).is_err()
                {
                    // UNCOMMENT TO DEBUG THREAD //
                    // kernel::debug!("[Thread] Failure setting networkkey and/or nonce.");
                    return Err((ErrorCode::FAIL, buf));
                }
            }
            None => {
                // UNCOMMENT TO DEBUG THREAD //
                // kernel::debug!("[Thread] Attempt to access networkkey when no networkkey set.");
                return Err((ErrorCode::NOSUPPORT, buf));
            }
        }

        // Thread MLE security utilizes the AES128 CCM security used by 802.15.4 link layer security.
        // Notably, there are a few minor modifications. AES128 requires authentication data (a data)
        // and the secured message data (m data). Together, the a data is used to encrypt the m data
        // while also generating a message integrity code (MIC). Thread subtly changes the
        // a data from the 802.15.4 specification. For Thread MLE, the a data consists of a concatenation
        // of the IP source address || IP destination address || auxiliary security header. It is especially important
        // to note that the security control field is not included in the auxiliary security header. Likewise,
        // the first byte of the payload is not included in the a data. For further information, refer to
        // (Thread Spec v1.3.0 -- sect. 4.9)
        //
        // Because all MLE messages must be encrypted with MLE security (v1.3.0 sect 4.10), all MLE messages
        // that are processed must possess an auxiliary security header of 10 bytes. The payload therefore consists of:
        //
        // |-----(1 byte)-----|----(10 bytes)------|---(UNKNOWN)---|--(DEPENDENT ON PROTOCOL)--|
        // |  SECURITY SUITE  |   AUX SEC HEADER   |      MLE      |            Mic            |
        //
        // Since the aux sec header is fixed, the auth data is always 32 bytes [16 (IPV6) + 16 (IPV6) + 10 aux sec header].
        // The m data len can be determined because it is the only unknown length.

        let aux_sec_header = &mut [0u8; AUX_SEC_HEADER_LENGTH];
        Security::encode(&security, aux_sec_header);

        let m_data_len = payload.len();

        // Encode auth data and payload into `buf`
        let encode_res = encode_cryp_data(src_addr, dst_addr, aux_sec_header, payload, buf).done();

        // Error check on result from encoding, failure likely means buf was not large enough
        if encode_res.is_none() {
            // UNCOMMENT TO DEBUG THREAD //
            // kernel::debug!("[Thread] Error encoding cryptographic data into buffer");
            return Err((ErrorCode::FAIL, buf));
        }

        let (offset, ()) = encode_res.unwrap();

        // GENERAL NOTE: `self.crypto_sizelock`
        // This does not seem to be the most elegant solution. The `crypto_sizelock` arose from the fact
        // that we must know the length of the payload when the `crypt_done` callback
        // occurs in order to only send/receive the portion of the 200 byte buffer that is the message.
        // The other option to `crypto_sizelock` is to only pass to the crypto engine a buffer
        // that is the size of the transmission/reception. This however is flawed
        // as it leads to an inability to replace/restore the 200 byte buffer. The crypto engine
        // requires a reference to static memory (leading to the recv/send buf being taken).
        // This is only able to be replaced when the `crypt_done` callback occurs and returns the
        // buf used by the crypto engine. If a partial buffer is used, it is impossible to then replace
        // the full sized buffer to the send/recv buf. Likewise, I choose to use the `crypt_sizelock`
        // and pass the whole 200 byte buffer. The `crypto_sizelock` works for
        // now until a more elegant solution is implemented.

        // The sizelock is empty except when a crypto operation
        // is underway. If the sizelock is not empty, return error
        if self.crypto_sizelock.is_some() {
            // UNCOMMENT TO DEBUG THREAD //
            // kernel::debug!(
            //     "[Thread] Error - cryptographic resources in use; crypto_sizelock occupied"
            // );
            return Err((ErrorCode::BUSY, buf));
        }

        // Store the length of the payload.
        self.crypto_sizelock.replace(offset + mic_len);
        self.aes_crypto
            .crypt(buf, 0, AUTH_DATA_LEN, m_data_len, mic_len, true, true)
    }
}

impl<'a, A: time::Alarm<'a>> framer::KeyProcedure for ThreadNetworkDriver<'a, A> {
    /// Gets the key corresponding to the key that matches the given security
    /// level `level` and key ID `key_id`. If no such key matches, returns
    /// `None`.
    // TODO: This implementation only supports one key
    fn lookup_key(&self, _level: SecurityLevel, _key_id: KeyId) -> Option<[u8; 16]> {
        if let Some(netkey) = self.networkkey.get() {
            Some(netkey.mac_key)
        } else {
            None
        }
    }
}

impl<'a, A: time::Alarm<'a>> framer::DeviceProcedure for ThreadNetworkDriver<'a, A> {
    /// Gets the key corresponding to the key that matches the given security
    /// level `level` and key ID `key_id`. If no such key matches, returns
    /// `None`.
    // TODO: This implementation only supports one key
    fn lookup_addr_long(&self, _addr: MacAddress) -> Option<[u8; 8]> {
        Some(self.src_mac_addr)
    }
}

impl<'a, A: time::Alarm<'a>> SyscallDriver for ThreadNetworkDriver<'a, A> {
    /// ### `command_num`
    /// - `0`: Driver Check
    /// - `1`: Add a new mle/mac networkkey and initiate a parent request.

    fn command(
        &self,
        command_num: usize,
        _arg1: usize,
        _: usize,
        processid: ProcessId,
    ) -> CommandReturn {
        match command_num {
            0 => CommandReturn::success(),

            1 => self
                .apps
                .enter(processid, |_, kernel_data| {
                    kernel_data
                        .get_readonly_processbuffer(ro_allow::WRITE)
                        .and_then(|ro_buf| {
                            ro_buf.enter(|src_key| {
                                // check Thread state, if thread state is not empty,
                                // another userspace application has control of the Thread
                                // network and other requesting applications should fail.
                                if self.state.is_some() {
                                    return CommandReturn::failure(ErrorCode::BUSY);
                                }

                                // src key consists of the mle and mac keys; Thread
                                // hash is performed in userland and 32 byte hash is
                                // passed to thread capsule and entered as mac/mle key
                                // (For key generation see Thread spec v1.3.0 7.1.4)
                                if src_key.len() != 32 {
                                    return CommandReturn::failure(ErrorCode::SIZE);
                                }
                                let mut mle_key = [0u8; 16];
                                let mut mac_key = [0u8; 16];
                                src_key[..16].copy_to_slice(&mut mle_key);
                                src_key[16..32].copy_to_slice(&mut mac_key);
                                self.set_networkkey(mle_key, mac_key);

                                // Thread state begins as detached if sucessfully joined
                                self.state.replace(ThreadState::Detached);
                                CommandReturn::success()
                            })
                        })
                        .unwrap_or(CommandReturn::failure(ErrorCode::INVAL))
                })
                .map_or_else(
                    |err| CommandReturn::failure(err.into()),
                    |ok_val| {
                        // If no failure in saving the mle/mac key, initiate
                        // sending the parent request
                        self.send_parent_req();
                        ok_val
                    },
                ),

            _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
        }
    }

    fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
        self.apps.enter(processid, |_, _| {})
    }
}

impl<'a, A: time::Alarm<'a>> UDPSendClient for ThreadNetworkDriver<'a, A> {
    fn send_done(&self, _result: Result<(), ErrorCode>, mut dgram: SubSliceMut<'static, u8>) {
        // TODO: handle result from send done and respond accordingly

        // Panicking on unwrap indicates the state was taken without replacement
        // (unreachable with proper state machine implementation)
        let curr_state = self.state.take().unwrap();

        // Advance state machine
        let next_state = match curr_state {
            ThreadState::SendUpdate(dst_ip, dst_mac) => ThreadState::SEDActive(dst_ip, dst_mac),
            ThreadState::SendUDPMsg => unimplemented!(),
            ThreadState::SendChildIdReq(_) => ThreadState::WaitingChildRsp,
            ThreadState::SendParentReq => {
                // UNCOMMENT TO DEBUG THREAD //
                // kernel::debug!("[Thread] Completed sending parent request to multicast IP");
                ThreadState::WaitingParentRsp
            }
            _ => panic!("Thread state machine diverged"),
        };

        self.frame_count.set(self.frame_count.get() + 1);

        // Replace the returned buffer and state
        dgram.reset();
        self.send_buffer.replace(dgram);
        self.state.replace(next_state);
    }
}

impl<'a, A: time::Alarm<'a>> time::AlarmClient for ThreadNetworkDriver<'a, A> {
    // TODO: This function is mainly here as a place holder as it will be needed
    // for implementing timeouts/timing for sending heartbeat messages to the parent
    // node
    fn alarm(&self) {
        match self.state.take().unwrap() {
            // TODO: Implement retries as defined in the thread spec (when timeouts occur)
            ThreadState::Detached => unimplemented!("[Thread ALARM] Detached"),
            ThreadState::SendParentReq => unimplemented!("[Thread ALARM] Send Parent Req"),
            ThreadState::SendChildIdReq(_) => unimplemented!("[Thread ALARM] Send Child ID Req"),
            ThreadState::SEDActive(_ipaddr, _mac) => {
                // TODO: SEND HEARTBEAT to parent node
                unimplemented!("[Thread ALARM] Send Heartbeat")
            }
            _ => panic!(""),
        }
    }
}

impl<'a, A: time::Alarm<'a>> UDPRecvClient for ThreadNetworkDriver<'a, A> {
    fn receive(
        &self,
        src_addr: IPAddr,
        dst_addr: IPAddr,
        _src_port: u16,
        _dst_port: u16,
        payload: &[u8],
    ) {
        if payload[0] != SECURITY_SUITE_ENCRYP {
            // Tock's current implementation of Thread ignores all messages that do not possess MLE encryption. This
            // is due to the Thread spec stating "Except for when specifically indicated, incoming
            // messages that are not secured with either MLE or link-layer security SHOULD be ignored." (v.1.3.0 sect 4.10)
            // UNCOMMENT TO DEBUG THREAD //
            // kernel::debug!("[Thread] DROPPED PACKET - Received unencrypted MLE packet.");
        }

        // decode aux security header from packet into Security data type
        let sec_res = ieee802154::Security::decode(&payload[1..]).done();

        // Guard statement for improperly formated aux sec header
        if sec_res.is_none() {
            // UNCOMMENT TO DEBUG THREAD //
            // kernel::debug!("[Thread] DROPPED PACKET - Malformed auxiliary security header.");
            return;
        }

        let security = sec_res.unwrap().1;

        // Take the receive buffer and pass to the `perform_crypto_op` wrapper function. This
        // initiates encoding all relevant auth data, setting crypto engine and initiating the
        // crypto operation.
        self.recv_buffer.take().map_or_else(
            || {
                // UNCOMMENT TO DEBUG THREAD //
                // kernel::debug!("[Thread] DROPPED PACKET - Receive buffer not available")
            },
            |recv_buf| {
                self.perform_crypt_op(
                    src_addr,
                    dst_addr,
                    security,
                    &payload[SECURITY_SUITE_LEN + AUX_SEC_HEADER_LENGTH
                        ..payload.len() - security.level.mic_len()],
                    recv_buf.take(),
                )
                .map_or_else(
                    // Error check on crypto operation. If the crypto operation
                    // fails, we log the error and replace the receive buffer for
                    // future receptions
                    |(_code, buf)| {
                        // UNCOMMENT TO DEBUG THREAD alter _code to code//
                        // kernel::debug!(
                        //     "[Thread] DROPPED PACKET - Crypto Operation Error *{:?}",
                        //     code
                        // );
                        self.recv_buffer.replace(SubSliceMut::new(buf));
                    },
                    |()| (),
                )
            },
        );
    }
}

impl<'a, A: time::Alarm<'a>> CCMClient for ThreadNetworkDriver<'a, A> {
    fn crypt_done(&self, buf: &'static mut [u8], _res: Result<(), ErrorCode>, _tag_is_valid: bool) {
        // TODO: check validity of result/tag and handle accordingly

        // Obtain the length of the payload from the sizelock
        let buf_len = self.crypto_sizelock.take().unwrap();

        // The auth data contains the src_addr || dest_addr || aux_sec_header;
        // Recover src/dst addr from the auth data
        let mut src_ipv6 = [0u8; IPV6_LEN];
        let mut dst_ipv6 = [0u8; IPV6_LEN];
        src_ipv6.copy_from_slice(&buf[..IPV6_LEN]);
        dst_ipv6.copy_from_slice(&buf[IPV6_LEN..(2 * IPV6_LEN)]);

        // The crypto operation requires 32 bytes (2 IPV6 addresses) as part of the auth data. We
        // do not care about this data so we shift the data to overwrite this data with the aux sec header
        // and payload. We shift this to an offset of 1 so that we can add the security suite field
        let auth_addr_offset = AUTH_DATA_LEN - AUX_SEC_HEADER_LENGTH;
        buf.copy_within(auth_addr_offset.., SECURITY_SUITE_LEN);

        // Recover the length of the mic from the security information encoded in the aux_sec_header
        let mic_len = ieee802154::Security::decode(&buf[SECURITY_SUITE_LEN..])
            .done()
            .unwrap()
            .1
            .level
            .mic_len();

        // We hard code the security suite to `0` for now as all messages are
        // assumed to be encrypted for the current implementation
        buf[..SECURITY_SUITE_LEN].copy_from_slice(&[SECURITY_SUITE_ENCRYP]);

        // the assembled_buf_len is the length of: security suite || aux sec header || mle payload || mic
        let assembled_buf_len = buf_len - auth_addr_offset + SECURITY_SUITE_LEN;

        // We create a new subslice that we will slice accordingly depending on if we are sending/receiving
        let mut assembled_subslice = SubSliceMut::new(buf);

        // Panicking on unwrap indicates the state was taken without replacement
        // (unreachable with proper state machine implementation)
        let curr_state = self.state.take().unwrap();

        match curr_state {
            ThreadState::SendParentReq | ThreadState::SendChildIdReq(_) => {
                //TODO: Add alarm for timeouts

                // To send, we need to send: security suite || aux sec header || mle payload || mic
                // which correlates to the assembled_buf_len
                assembled_subslice.slice(..assembled_buf_len);

                let dest_ipv6 = match curr_state {
                    // Determine destination IP depending on message type
                    ThreadState::SendParentReq => MULTICAST_IPV6,
                    ThreadState::SendChildIdReq(dst_ipv6) => dst_ipv6,
                    _ => unreachable!(),
                };

                // we replace the state with the current state here
                // because we cannot advance the state machine until
                // after the `send_done` callback is received
                self.state.replace(curr_state);

                // Begin sending the transmission
                self.sender
                    .driver_send_to(
                        dest_ipv6,
                        THREAD_PORT_NUMBER,
                        THREAD_PORT_NUMBER,
                        assembled_subslice,
                        self.driver_send_cap,
                        self.net_cap,
                    )
                    .map_err(|buf| {
                        // if the sending fails prior to transmission, replace
                        // the buffer and pass error accordingly to terminate_child_join
                        // in following unwrap statement
                        self.send_buffer.replace(buf);
                        ErrorCode::FAIL
                    })
                    .unwrap_or_else(|code| self.terminate_child_join(Err(code)));
            }
            ThreadState::WaitingChildRsp => {
                // TODO: Receive child response
            }
            ThreadState::WaitingParentRsp => {
                // Upon receiving messages, the receive logic only requires the MLE payload. Subsequently,
                // we slice the assembled_subslice to exclude the security suite, aux sec header, and mic.
                assembled_subslice
                    .slice(AUX_SEC_HEADER_LENGTH + SECURITY_SUITE_LEN..assembled_buf_len - mic_len);

                // Move the decrypted MLE message into the recv_buf and execute the receiving logic. Upon
                // an error in `recv_logic`, joining the network fails and schedule termination upcall
                self.recv_buffer.replace(assembled_subslice);
                self.recv_logic(IPAddr(src_ipv6))
                    .err()
                    .map(|code| self.terminate_child_join(Err(code)));
            }
            _ => (),
        };
    }
}