// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Duplicate Address Detection.

use core::{num::NonZeroU8, time::Duration};

use net_types::{
    ip::{Ipv6, Ipv6Addr},
    MulticastAddr, UnicastAddr, Witness as _,
};
use packet_formats::icmp::ndp::NeighborSolicitation;

use crate::{
    context::{EventContext, TimerContext},
    ip::{device::state::AddressState, IpDeviceIdContext},
};

/// A timer ID for duplicate address detection.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
pub(crate) struct DadTimerId<DeviceId> {
    pub(crate) device_id: DeviceId,
    pub(crate) addr: UnicastAddr<Ipv6Addr>,
}

/// The IP device context provided to DAD.
pub(super) trait Ipv6DeviceDadContext<C>: IpDeviceIdContext<Ipv6> {
    /// Returns the address's state mutably, if it exists on the interface.
    fn get_address_state_mut(
        &mut self,
        ctx: &mut C,
        device_id: Self::DeviceId,
        addr: UnicastAddr<Ipv6Addr>,
    ) -> Option<&mut AddressState>;

    /// Returns the NDP retransmission timer configured on the device.
    fn retrans_timer(&self, ctx: &mut C, device_id: Self::DeviceId) -> Duration;
}

/// The IP layer context provided to DAD.
pub(super) trait Ipv6LayerDadContext<C>: IpDeviceIdContext<Ipv6> {
    /// Sends an NDP Neighbor Solicitation message for DAD to the local-link.
    ///
    /// The message will be sent with the unspecified (all-zeroes) source
    /// address.
    fn send_dad_packet(
        &mut self,
        ctx: &mut C,
        device_id: Self::DeviceId,
        dst_ip: MulticastAddr<Ipv6Addr>,
        message: NeighborSolicitation,
    ) -> Result<(), ()>;
}

#[derive(Debug, Eq, PartialEq)]
/// Events generated by duplicate address detection.
pub enum DadEvent<DeviceId> {
    /// Duplicate address detection completed and the address is assigned.
    AddressAssigned {
        /// Device the address belongs to.
        device: DeviceId,
        /// The address that moved to the assigned state.
        addr: UnicastAddr<Ipv6Addr>,
    },
}

/// The non-synchronized execution context for DAD.
pub(super) trait DadNonSyncContext<DeviceId>:
    TimerContext<DadTimerId<DeviceId>> + EventContext<DadEvent<DeviceId>>
{
}
impl<DeviceId, C: TimerContext<DadTimerId<DeviceId>> + EventContext<DadEvent<DeviceId>>>
    DadNonSyncContext<DeviceId> for C
{
}

/// The execution context for DAD.
pub(super) trait DadContext<C: DadNonSyncContext<Self::DeviceId>>:
    Ipv6DeviceDadContext<C> + Ipv6LayerDadContext<C>
{
}

impl<C: DadNonSyncContext<SC::DeviceId>, SC: Ipv6DeviceDadContext<C> + Ipv6LayerDadContext<C>>
    DadContext<C> for SC
{
}

/// An implementation for Duplicate Address Detection.
pub(crate) trait DadHandler<C>: IpDeviceIdContext<Ipv6> {
    /// Do duplicate address detection.
    ///
    /// # Panics
    ///
    /// Panics if tentative state for the address is not found.
    fn do_duplicate_address_detection(
        &mut self,
        ctx: &mut C,
        device_id: Self::DeviceId,
        addr: UnicastAddr<Ipv6Addr>,
    );

    /// Stops duplicate address detection.
    ///
    /// Does nothing if DAD is not being performed on the address.
    fn stop_duplicate_address_detection(
        &mut self,
        ctx: &mut C,
        device_id: Self::DeviceId,
        addr: UnicastAddr<Ipv6Addr>,
    );

    /// Handles a timer.
    // TODO(https://fxbug.dev/101399): Replace this with a `TimerHandler` bound.
    fn handle_timer(
        &mut self,
        ctx: &mut C,
        DadTimerId { device_id, addr }: DadTimerId<Self::DeviceId>,
    ) {
        self.do_duplicate_address_detection(ctx, device_id, addr)
    }
}

impl<C: DadNonSyncContext<SC::DeviceId>, SC: DadContext<C>> DadHandler<C> for SC {
    fn do_duplicate_address_detection(
        &mut self,
        ctx: &mut C,
        device_id: Self::DeviceId,
        addr: UnicastAddr<Ipv6Addr>,
    ) {
        let state = self
            .get_address_state_mut(ctx, device_id, addr)
            .unwrap_or_else(|| panic!("expected address to exist; addr={}", addr));

        let remaining = match state {
            AddressState::Tentative { dad_transmits_remaining } => dad_transmits_remaining,
            AddressState::Assigned => {
                panic!("expected address to be tentative; addr={}", addr)
            }
        };

        match remaining {
            None => {
                *state = AddressState::Assigned;
                ctx.on_event(DadEvent::AddressAssigned { device: device_id, addr });
            }
            Some(non_zero_remaining) => {
                *remaining = NonZeroU8::new(non_zero_remaining.get() - 1);

                // Per RFC 4862 section 5.1,
                //
                //   DupAddrDetectTransmits ...
                //      Autoconfiguration also assumes the presence of the variable
                //      RetransTimer as defined in [RFC4861]. For autoconfiguration
                //      purposes, RetransTimer specifies the delay between
                //      consecutive Neighbor Solicitation transmissions performed
                //      during Duplicate Address Detection (if
                //      DupAddrDetectTransmits is greater than 1), as well as the
                //      time a node waits after sending the last Neighbor
                //      Solicitation before ending the Duplicate Address Detection
                //      process.
                let retrans_timer = self.retrans_timer(ctx, device_id);

                let dst_ip = addr.to_solicited_node_address();

                // Do not include the source link-layer option when the NS
                // message as DAD messages are sent with the unspecified source
                // address which must not hold a source link-layer option.
                //
                // As per RFC 4861 section 4.3,
                //
                //   Possible options:
                //
                //      Source link-layer address
                //           The link-layer address for the sender. MUST NOT be
                //           included when the source IP address is the
                //           unspecified address. Otherwise, on link layers
                //           that have addresses this option MUST be included in
                //           multicast solicitations and SHOULD be included in
                //           unicast solicitations.
                //
                // TODO(https://fxbug.dev/85055): Either panic or guarantee that this error
                // can't happen statically.
                let _: Result<(), _> = self.send_dad_packet(
                    ctx,
                    device_id,
                    dst_ip,
                    NeighborSolicitation::new(addr.get()),
                );

                assert_eq!(
                ctx.schedule_timer(retrans_timer, DadTimerId { device_id, addr }),
                None,
                "Should not have a DAD timer set when performing DAD work; addr={}, device_id={}",
                addr,
                device_id
            );
            }
        }
    }

    fn stop_duplicate_address_detection(
        &mut self,
        ctx: &mut C,
        device_id: Self::DeviceId,
        addr: UnicastAddr<Ipv6Addr>,
    ) {
        let _: Option<C::Instant> = ctx.cancel_timer(DadTimerId { device_id, addr });
    }
}

#[cfg(test)]
mod tests {
    use packet::EmptyBuf;
    use packet_formats::icmp::ndp::Options;

    use super::*;
    use crate::{
        context::{
            testutil::{DummyCtx, DummyNonSyncCtx, DummySyncCtx, DummyTimerCtxExt as _},
            FrameContext as _, InstantContext as _,
        },
        ip::DummyDeviceId,
    };

    struct MockDadContext {
        addr: UnicastAddr<Ipv6Addr>,
        state: AddressState,
        retrans_timer: Duration,
    }

    #[derive(Debug)]
    struct DadMessageMeta {
        dst_ip: MulticastAddr<Ipv6Addr>,
        message: NeighborSolicitation,
    }

    type MockNonSyncCtx = DummyNonSyncCtx<DadTimerId<DummyDeviceId>, DadEvent<DummyDeviceId>, ()>;

    type MockCtx = DummySyncCtx<MockDadContext, DadMessageMeta, DummyDeviceId>;

    impl Ipv6DeviceDadContext<MockNonSyncCtx> for MockCtx {
        fn get_address_state_mut(
            &mut self,
            _ctx: &mut MockNonSyncCtx,
            DummyDeviceId: DummyDeviceId,
            request_addr: UnicastAddr<Ipv6Addr>,
        ) -> Option<&mut AddressState> {
            let MockDadContext { addr, state, retrans_timer: _ } = self.get_mut();
            (*addr == request_addr).then(|| state)
        }

        fn retrans_timer(
            &self,
            _ctx: &mut MockNonSyncCtx,
            DummyDeviceId: DummyDeviceId,
        ) -> Duration {
            let MockDadContext { addr: _, state: _, retrans_timer } = self.get_ref();
            *retrans_timer
        }
    }

    impl Ipv6LayerDadContext<MockNonSyncCtx> for MockCtx {
        fn send_dad_packet(
            &mut self,
            ctx: &mut MockNonSyncCtx,
            DummyDeviceId: DummyDeviceId,
            dst_ip: MulticastAddr<Ipv6Addr>,
            message: NeighborSolicitation,
        ) -> Result<(), ()> {
            self.send_frame(ctx, DadMessageMeta { dst_ip, message }, EmptyBuf)
                .map_err(|EmptyBuf| ())
        }
    }

    const DAD_ADDRESS: UnicastAddr<Ipv6Addr> =
        unsafe { UnicastAddr::new_unchecked(Ipv6Addr::new([0xa, 0, 0, 0, 0, 0, 0, 1])) };
    const OTHER_ADDRESS: UnicastAddr<Ipv6Addr> =
        unsafe { UnicastAddr::new_unchecked(Ipv6Addr::new([0xa, 0, 0, 0, 0, 0, 0, 2])) };

    #[test]
    #[should_panic(expected = "expected address to exist")]
    fn panic_unknown_address() {
        let DummyCtx { mut sync_ctx, mut non_sync_ctx } =
            DummyCtx::with_sync_ctx(MockCtx::with_state(MockDadContext {
                addr: DAD_ADDRESS,
                state: AddressState::Tentative { dad_transmits_remaining: None },
                retrans_timer: Duration::default(),
            }));
        DadHandler::do_duplicate_address_detection(
            &mut sync_ctx,
            &mut non_sync_ctx,
            DummyDeviceId,
            OTHER_ADDRESS,
        );
    }

    #[test]
    #[should_panic(expected = "expected address to be tentative")]
    fn panic_non_tentative_address() {
        let DummyCtx { mut sync_ctx, mut non_sync_ctx } =
            DummyCtx::with_sync_ctx(MockCtx::with_state(MockDadContext {
                addr: DAD_ADDRESS,
                state: AddressState::Assigned,
                retrans_timer: Duration::default(),
            }));
        DadHandler::do_duplicate_address_detection(
            &mut sync_ctx,
            &mut non_sync_ctx,
            DummyDeviceId,
            DAD_ADDRESS,
        );
    }

    #[test]
    fn dad_disabled() {
        let DummyCtx { mut sync_ctx, mut non_sync_ctx } =
            DummyCtx::with_sync_ctx(MockCtx::with_state(MockDadContext {
                addr: DAD_ADDRESS,
                state: AddressState::Tentative { dad_transmits_remaining: None },
                retrans_timer: Duration::default(),
            }));
        DadHandler::do_duplicate_address_detection(
            &mut sync_ctx,
            &mut non_sync_ctx,
            DummyDeviceId,
            DAD_ADDRESS,
        );
        let MockDadContext { addr: _, state, retrans_timer: _ } = sync_ctx.get_ref();
        assert_eq!(*state, AddressState::Assigned);
        assert_eq!(
            non_sync_ctx.take_events(),
            &[DadEvent::AddressAssigned { device: DummyDeviceId, addr: DAD_ADDRESS }][..]
        );
    }

    const DAD_TIMER_ID: DadTimerId<DummyDeviceId> =
        DadTimerId { addr: DAD_ADDRESS, device_id: DummyDeviceId };

    fn check_dad(
        sync_ctx: &MockCtx,
        non_sync_ctx: &MockNonSyncCtx,
        frames_len: usize,
        dad_transmits_remaining: Option<NonZeroU8>,
        retrans_timer: Duration,
    ) {
        let MockDadContext { addr: _, state, retrans_timer: _ } = sync_ctx.get_ref();
        assert_eq!(*state, AddressState::Tentative { dad_transmits_remaining });
        let frames = sync_ctx.frames();
        assert_eq!(frames.len(), frames_len, "frames = {:?}", frames);
        let (DadMessageMeta { dst_ip, message }, frame) =
            frames.last().expect("should have transmitted a frame");

        assert_eq!(*dst_ip, DAD_ADDRESS.to_solicited_node_address());
        assert_eq!(*message, NeighborSolicitation::new(DAD_ADDRESS.get()));

        let options = Options::parse(&frame[..]).expect("parse NDP options");
        assert_eq!(options.iter().count(), 0);
        non_sync_ctx
            .timer_ctx()
            .assert_timers_installed([(DAD_TIMER_ID, non_sync_ctx.now() + retrans_timer)]);
    }

    #[test]
    fn perform_dad() {
        const DAD_TRANSMITS_REQUIRED: u8 = 2;
        const RETRANS_TIMER: Duration = Duration::from_secs(1);

        let DummyCtx { mut sync_ctx, mut non_sync_ctx } =
            DummyCtx::with_sync_ctx(MockCtx::with_state(MockDadContext {
                addr: DAD_ADDRESS,
                state: AddressState::Tentative {
                    dad_transmits_remaining: NonZeroU8::new(DAD_TRANSMITS_REQUIRED),
                },
                retrans_timer: RETRANS_TIMER,
            }));
        DadHandler::do_duplicate_address_detection(
            &mut sync_ctx,
            &mut non_sync_ctx,
            DummyDeviceId,
            DAD_ADDRESS,
        );

        for count in 0..=1u8 {
            check_dad(
                &sync_ctx,
                &non_sync_ctx,
                usize::from(count + 1),
                NonZeroU8::new(DAD_TRANSMITS_REQUIRED - count - 1),
                RETRANS_TIMER,
            );
            assert_eq!(
                non_sync_ctx.trigger_next_timer(&mut sync_ctx, DadHandler::handle_timer),
                Some(DAD_TIMER_ID)
            );
        }
        let MockDadContext { addr: _, state, retrans_timer: _ } = sync_ctx.get_ref();
        assert_eq!(*state, AddressState::Assigned);
        assert_eq!(
            non_sync_ctx.take_events(),
            &[DadEvent::AddressAssigned { device: DummyDeviceId, addr: DAD_ADDRESS }][..]
        );
    }

    #[test]
    fn stop_dad() {
        const DAD_TRANSMITS_REQUIRED: u8 = 2;
        const RETRANS_TIMER: Duration = Duration::from_secs(2);

        let DummyCtx { mut sync_ctx, mut non_sync_ctx } =
            DummyCtx::with_sync_ctx(MockCtx::with_state(MockDadContext {
                addr: DAD_ADDRESS,
                state: AddressState::Tentative {
                    dad_transmits_remaining: NonZeroU8::new(DAD_TRANSMITS_REQUIRED),
                },
                retrans_timer: RETRANS_TIMER,
            }));
        DadHandler::do_duplicate_address_detection(
            &mut sync_ctx,
            &mut non_sync_ctx,
            DummyDeviceId,
            DAD_ADDRESS,
        );
        check_dad(
            &sync_ctx,
            &non_sync_ctx,
            1,
            NonZeroU8::new(DAD_TRANSMITS_REQUIRED - 1),
            RETRANS_TIMER,
        );

        DadHandler::stop_duplicate_address_detection(
            &mut sync_ctx,
            &mut non_sync_ctx,
            DummyDeviceId,
            DAD_ADDRESS,
        );
        non_sync_ctx.timer_ctx().assert_no_timers_installed();
    }
}
