/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2007-2009 Strasbourg University * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Sebastien Vincent */ #include "ipv6-interface.h" #include "ns3/net-device.h" #include "loopback-net-device.h" #include "ns3/log.h" #include "ns3/node.h" #include #include "icmpv6-l4-protocol.h" namespace ns3 { NS_LOG_COMPONENT_DEFINE ("Ipv6Interface"); TypeId Ipv6Interface::GetTypeId () { static TypeId tid = TypeId ("ns3::Ipv6Interface") .SetParent () ; return tid; } Ipv6Interface::Ipv6Interface () : m_ifup (false), m_forwarding (true), m_metric (1), m_node (0), m_device (0), m_curHopLimit (0), m_baseReachableTime (0), m_reachableTime (0), m_retransTimer (0) { NS_LOG_FUNCTION (this); } Ipv6Interface::~Ipv6Interface () { NS_LOG_FUNCTION_NOARGS (); } void Ipv6Interface::DoDispose () { NS_LOG_FUNCTION_NOARGS (); Object::DoDispose (); } void Ipv6Interface::DoSetup () { NS_LOG_FUNCTION_NOARGS (); if (m_node == 0 || m_device == 0) { return; } if (!m_device->NeedsArp ()) { return; } /* set up link-local address */ if (!DynamicCast (m_device)) /* no autoconf for ip6-localhost */ { Address addr = GetDevice ()->GetAddress (); if (Mac48Address::IsMatchingType (addr)) { Ipv6InterfaceAddress ifaddr = Ipv6InterfaceAddress (Ipv6Address::MakeAutoconfiguredLinkLocalAddress (Mac48Address::ConvertFrom (addr)), Ipv6Prefix (64)); AddAddress (ifaddr); } else { NS_ASSERT_MSG (false, "IPv6 autoconf for this kind of address not implemented."); } } Ptr icmpv6 = m_node->GetObject ()->GetIcmpv6 (); m_ndCache = icmpv6->CreateCache (m_device, this); } void Ipv6Interface::SetNode (Ptr node) { NS_LOG_FUNCTION (this << node); m_node = node; DoSetup (); } void Ipv6Interface::SetDevice (Ptr device) { NS_LOG_FUNCTION (this << device); m_device = device; DoSetup (); } Ptr Ipv6Interface::GetDevice () const { NS_LOG_FUNCTION_NOARGS (); return m_device; } void Ipv6Interface::SetMetric (uint16_t metric) { NS_LOG_FUNCTION (this << metric); m_metric = metric; } uint16_t Ipv6Interface::GetMetric () const { NS_LOG_FUNCTION_NOARGS (); return m_metric; } bool Ipv6Interface::IsUp () const { NS_LOG_FUNCTION_NOARGS (); return m_ifup; } bool Ipv6Interface::IsDown () const { NS_LOG_FUNCTION_NOARGS (); return !m_ifup; } void Ipv6Interface::SetUp () { NS_LOG_FUNCTION_NOARGS (); if (m_ifup) { return; } m_ifup = true; } void Ipv6Interface::SetDown () { NS_LOG_FUNCTION_NOARGS (); m_ifup = false; m_addresses.clear (); } bool Ipv6Interface::IsForwarding () const { NS_LOG_FUNCTION_NOARGS (); return m_forwarding; } void Ipv6Interface::SetForwarding (bool forwarding) { NS_LOG_FUNCTION (this << forwarding); m_forwarding = forwarding; } bool Ipv6Interface::AddAddress (Ipv6InterfaceAddress iface) { NS_LOG_FUNCTION_NOARGS (); Ipv6Address addr = iface.GetAddress (); /* DAD handling */ if (!addr.IsAny ()) { for (Ipv6InterfaceAddressListCI it = m_addresses.begin () ; it != m_addresses.end () ; ++it) { if ((*it).GetAddress () == addr) { return false; } } m_addresses.push_back (iface); if (!addr.IsAny () || !addr.IsLocalhost ()) { /* DAD handling */ Ptr icmpv6 = m_node->GetObject ()->GetIcmpv6 (); if (icmpv6 && icmpv6->IsAlwaysDad ()) { Simulator::Schedule (Seconds (0.), &Icmpv6L4Protocol::DoDAD, icmpv6, addr, this); Simulator::Schedule (Seconds (1.), &Icmpv6L4Protocol::FunctionDadTimeout, icmpv6, this, addr); } } return true; } /* bad address */ return false; } Ipv6InterfaceAddress Ipv6Interface::GetLinkLocalAddress () const { /* IPv6 interface has always at least one IPv6 link-local address */ NS_LOG_FUNCTION_NOARGS (); for (Ipv6InterfaceAddressListCI it = m_addresses.begin () ; it != m_addresses.end () ; ++it) { if ((*it).GetAddress ().IsLinkLocal ()) { return (*it); } } NS_ASSERT_MSG (false, "No link-local address on interface " << this); Ipv6InterfaceAddress addr; return addr; /* quiet compiler */ } Ipv6InterfaceAddress Ipv6Interface::GetAddress (uint32_t index) const { NS_LOG_FUNCTION (this << index); uint32_t i = 0; if (m_addresses.size () > index) { for (Ipv6InterfaceAddressListCI it = m_addresses.begin () ; it != m_addresses.end () ; ++it) { if (i == index) { return (*it); } i++; } } NS_ASSERT_MSG (false, "Address " << index << " not found"); Ipv6InterfaceAddress addr; return addr; /* quiet compiler */ } uint32_t Ipv6Interface::GetNAddresses () const { NS_LOG_FUNCTION_NOARGS (); return m_addresses.size (); } Ipv6InterfaceAddress Ipv6Interface::RemoveAddress (uint32_t index) { NS_LOG_FUNCTION (this << index); uint32_t i = 0; if (m_addresses.size () < index) { NS_ASSERT_MSG (false, "Try to remove index that don't exist in Ipv6Interface::RemoveAddress"); } for (Ipv6InterfaceAddressListI it = m_addresses.begin () ; it != m_addresses.end () ; ++it) { if (i == index) { Ipv6InterfaceAddress iface = (*it); m_addresses.erase (it); return iface; } i++; } NS_ASSERT_MSG (false, "Address " << index << " not found"); Ipv6InterfaceAddress addr; return addr; /* quiet compiler */ } Ipv6InterfaceAddress Ipv6Interface::GetAddressMatchingDestination (Ipv6Address dst) { NS_LOG_FUNCTION (this << dst); for (Ipv6InterfaceAddressList::const_iterator it = m_addresses.begin () ; it != m_addresses.end () ; ++it) { Ipv6InterfaceAddress ifaddr = (*it); if (ifaddr.GetPrefix ().IsMatch (ifaddr.GetAddress (), dst)) { return ifaddr; } } /* NS_ASSERT_MSG (false, "Not matching address."); */ Ipv6InterfaceAddress ret; return ret; /* quiet compiler */ } void Ipv6Interface::Send (Ptr p, Ipv6Address dest) { NS_LOG_FUNCTION (this << p << dest); Ptr ipv6 = m_node->GetObject (); if (!IsUp ()) { return; } /* check if destination is localhost (::1) */ if (DynamicCast (m_device)) { /* XXX additional checks needed here (such as whether multicast * goes to loopback)? */ m_device->Send (p, m_device->GetBroadcast (), Ipv6L3Protocol::PROT_NUMBER); return; } /* check if destination is for one of our interface */ for (Ipv6InterfaceAddressListCI it = m_addresses.begin () ; it != m_addresses.end () ; ++it) { if (dest == (*it).GetAddress ()) { ipv6->Receive (m_device, p, Ipv6L3Protocol::PROT_NUMBER, m_device->GetBroadcast (), m_device->GetBroadcast (), NetDevice::PACKET_HOST // note: linux uses PACKET_LOOPBACK here ); return; } } /* other address */ if (m_device->NeedsArp ()) { NS_LOG_LOGIC ("Needs ARP" << " " << dest); Ptr icmpv6 = ipv6->GetIcmpv6 (); Address hardwareDestination; bool found = false; NS_ASSERT (icmpv6); if (dest.IsMulticast ()) { NS_LOG_LOGIC ("IsMulticast"); NS_ASSERT_MSG (m_device->IsMulticast (), "Ipv6Interface::SendTo (): Sending multicast packet over non-multicast device"); hardwareDestination = m_device->GetMulticast (dest); found = true; } else { NS_LOG_LOGIC ("NDISC Lookup"); found = icmpv6->Lookup (p, dest, GetDevice (), m_ndCache, &hardwareDestination); } if (found) { NS_LOG_LOGIC ("Address Resolved. Send."); m_device ->Send (p, hardwareDestination, Ipv6L3Protocol::PROT_NUMBER); } } else { NS_LOG_LOGIC ("Doesn't need ARP"); m_device->Send (p, m_device->GetBroadcast (), Ipv6L3Protocol::PROT_NUMBER); } } void Ipv6Interface::SetCurHopLimit (uint8_t curHopLimit) { NS_LOG_FUNCTION (this << curHopLimit); m_curHopLimit = curHopLimit; } uint8_t Ipv6Interface::GetCurHopLimit () const { NS_LOG_FUNCTION_NOARGS (); return m_curHopLimit; } void Ipv6Interface::SetBaseReachableTime (uint16_t baseReachableTime) { NS_LOG_FUNCTION (this << baseReachableTime); m_baseReachableTime = baseReachableTime; } uint16_t Ipv6Interface::GetBaseReachableTime () const { NS_LOG_FUNCTION_NOARGS (); return m_baseReachableTime; } void Ipv6Interface::SetReachableTime (uint16_t reachableTime) { NS_LOG_FUNCTION (this << reachableTime); m_reachableTime = reachableTime; } uint16_t Ipv6Interface::GetReachableTime () const { NS_LOG_FUNCTION_NOARGS (); return m_reachableTime; } void Ipv6Interface::SetRetransTimer (uint16_t retransTimer) { NS_LOG_FUNCTION (this << retransTimer); m_retransTimer = retransTimer; } uint16_t Ipv6Interface::GetRetransTimer () const { NS_LOG_FUNCTION_NOARGS (); return m_retransTimer; } void Ipv6Interface::SetState (Ipv6Address address, Ipv6InterfaceAddress::State_e state) { NS_LOG_FUNCTION (this << address << state); for (Ipv6InterfaceAddressListI it = m_addresses.begin () ; it != m_addresses.end () ; ++it) { if ((*it).GetAddress () == address) { (*it).SetState (state); return; } } /* not found, maybe address has expired */ } void Ipv6Interface::SetNsDadUid (Ipv6Address address, uint32_t uid) { NS_LOG_FUNCTION (this << address << uid); for (Ipv6InterfaceAddressListI it = m_addresses.begin () ; it != m_addresses.end () ; ++it) { if ((*it).GetAddress () == address) { (*it).SetNsDadUid (uid); return; } } /* not found, maybe address has expired */ } } /* namespace ns3 */