netlink/netlink-socket.cc
author Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
Thu, 05 May 2011 09:28:21 +0200
changeset 66 2fe1f3e576c9
parent 63 model/netlink-socket.cc@e89dca438df6
permissions -rw-r--r--
make it somewhat build sanely

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2008 Liu Jian
 *
 * 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: Liu Jian <liujatp@gmail.com>
 *         Hajime Tazaki <tazaki@sfc.wide.ad.jp>
 */

#include "netlink-socket.h"
#include "netlink-socket-address.h"
#include "netlink-message.h"
#include "netlink-message-route.h"
#include "ns3/log.h"
#include "ns3/node.h"
#include "ns3/packet.h"
#include "ns3/ipv4-address.h"
#include "ns3/ipv4.h"
#include "ns3/simple-net-device.h"
#include "ns3/uinteger.h"
#include "ns3/trace-source-accessor.h"
#include <iostream>
#include <sstream>
#include "ns3/ipv6-address.h"
#include "ns3/ipv6.h"
#include "ns3/ipv4-l3-protocol.h"
#include "ns3/ipv4-static-routing-helper.h"
#include "ns3/ipv4-routing-table-entry.h"
#include "ns3/ipv6-l3-protocol.h"
#include "ns3/ipv6-interface.h"
#include "ns3/ipv6-static-routing-helper.h"
#include "ns3/ipv6-routing-table-entry.h"
#include "ns3/socket.h"
#include "ns3/mac48-address.h"
#include <sys/socket.h>
#include <linux/if.h>
#include <errno.h>

NS_LOG_COMPONENT_DEFINE ("NetlinkSocket");

namespace ns3 {

// GroupSockets store the netlinksocket with noero group value
// it was due to the mulitcast netlink messages.
class GroupSockets
{
public:
  static uint32_t GetNSockets(void)
  { 
    return m_Sockets.size();
  }
  static Ptr<NetlinkSocket> GetSocket(uint32_t index)
  {
    NS_ASSERT(index < m_Sockets.size());
    return m_Sockets[index];
  }
  static void AddSocket(Ptr<NetlinkSocket>sock)
  {
    m_Sockets.push_back(sock);
  }
private:
   /*use a std::vector to store the sockets with nozero group value*/
  static std::vector<Ptr<NetlinkSocket> >m_Sockets;
};
std::vector<Ptr<NetlinkSocket> >GroupSockets::m_Sockets;

NS_OBJECT_ENSURE_REGISTERED (NetlinkSocket);

/*
Netlink Socket
*/
TypeId
NetlinkSocket::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::NetlinkSocket")
    .SetParent<Socket> ()
    .AddConstructor<NetlinkSocket> ()
    .AddTraceSource ("Drop", "Drop packet due to receive buffer overflow",
                     MakeTraceSourceAccessor (&NetlinkSocket::m_dropTrace))
    .AddAttribute ("RcvBufSize",
                   "NetlinkSocket maximum receive buffer size (bytes)",
                   UintegerValue (0xffffffffl),
                   MakeUintegerAccessor (&NetlinkSocket::m_rcvBufSize),
                   MakeUintegerChecker<uint32_t> ())
    .AddAttribute ("IcmpCallback", "Callback invoked whenever an icmp error is received on this socket.",
                   CallbackValue (),
                   MakeCallbackAccessor (&NetlinkSocket::m_icmpCallback),
                   MakeCallbackChecker ())
    ;
  return tid;
}

NetlinkSocket::NetlinkSocket ()
  : m_shutdownSend (false),
    m_shutdownRecv (false),
    m_rxAvailable (0),
    m_srcPid (0),
    m_srcGroups (0),
    m_dstPid (0),
    m_dstGroups (0)
{
  NS_LOG_FUNCTION_NOARGS ();
  m_errno = ERROR_NOTERROR;
}
NetlinkSocket::~NetlinkSocket ()
{
  NS_LOG_FUNCTION (this);
}
void 
NetlinkSocket::DoDispose (void)
{
  NS_LOG_FUNCTION_NOARGS ();
}

int
NetlinkSocket::ErrnoToSimuErrno (void)
{
  switch (m_errno)
    {
    case Socket::ERROR_ISCONN:
      return EISCONN;
    case Socket::ERROR_NOTCONN:
      return ENOTCONN;
    case Socket::ERROR_MSGSIZE:
      return EMSGSIZE;
    case Socket::ERROR_AGAIN:
      return EAGAIN;
    case Socket::ERROR_SHUTDOWN:
      return ESHUTDOWN;
    case Socket::ERROR_OPNOTSUPP:
      return EOPNOTSUPP;
    case Socket::ERROR_AFNOSUPPORT:
      return EAFNOSUPPORT;
    case Socket::ERROR_INVAL:
      return EINVAL;
    case Socket::ERROR_BADF:
      return EBADF;
    case Socket::ERROR_NOROUTETOHOST:
      return EHOSTUNREACH;
    case Socket::ERROR_NODEV:
      return ENODEV;
    case Socket::ERROR_ADDRNOTAVAIL:
      return EADDRNOTAVAIL;
    case Socket::SOCKET_ERRNO_LAST:
    case Socket::ERROR_NOTERROR:
    default:
      NS_ASSERT (false);
      return 0; // quiet compiler
      break;
    }
}

void 
NetlinkSocket::SetNode (Ptr<Node> node)
{
  NS_LOG_FUNCTION_NOARGS ();
  m_node = node;
}


enum Socket::SocketErrno
NetlinkSocket::GetErrno (void) const
{
  NS_LOG_FUNCTION_NOARGS ();
  return m_errno;
}
enum Socket::SocketType 
NetlinkSocket::GetSocketType (void) const
{
  return Socket::NS3_SOCK_DGRAM;
}

Ptr<Node>
NetlinkSocket::GetNode (void) const
{
  NS_LOG_FUNCTION_NOARGS ();
  return m_node;
}

uint32_t
NetlinkSocket::GetSrcPid (void) const
{
  NS_LOG_FUNCTION_NOARGS ();
  return m_srcPid;
}
uint32_t
NetlinkSocket::GetSrcGroups (void)const
{
  NS_LOG_FUNCTION_NOARGS ();
  return m_srcGroups;
}
uint32_t
NetlinkSocket::GetDstPid (void) const
{
  NS_LOG_FUNCTION_NOARGS ();
  return m_dstPid;
}
uint32_t
NetlinkSocket::GetDstGroups (void)const
{
  NS_LOG_FUNCTION_NOARGS ();
  return m_dstGroups;
}

int
NetlinkSocket::Bind (void)
{
  NS_LOG_FUNCTION_NOARGS ();
  NetlinkSocketAddress address;
  return DoBind (address);
}
int
NetlinkSocket::Bind (const Address &address)
{ 
  NS_LOG_FUNCTION (this << address);

  if (!NetlinkSocketAddress::IsMatchingType (address))
    {
      m_errno = ERROR_INVAL;
      return -1;
    }
  NetlinkSocketAddress ad = NetlinkSocketAddress::ConvertFrom (address);
  return DoBind (ad);
}
int
NetlinkSocket::DoBind (const NetlinkSocketAddress &address)
{
  NS_LOG_FUNCTION (this << address);

  m_srcPid = address.GetProcessID ();
  m_srcGroups = address.GetGroupsMask ();

  if (m_srcGroups)
    {
      GroupSockets::AddSocket(this);
    } 
  return 0;
}

int 
NetlinkSocket::Listen (void)
{
  NS_LOG_FUNCTION_NOARGS ();
  m_errno = Socket::ERROR_OPNOTSUPP;
  return -1;
}

uint32_t
NetlinkSocket::GetTxAvailable (void) const
{
  NS_LOG_FUNCTION_NOARGS ();
  return 0;
}
uint32_t
NetlinkSocket::GetRxAvailable (void) const
{
  NS_LOG_FUNCTION_NOARGS ();
  // We separately maintain this state to avoid walking the queue 
  // every time this might be called
  return m_rxAvailable;
}

int
NetlinkSocket::ShutdownSend (void)
{
  NS_LOG_FUNCTION_NOARGS ();
  m_shutdownSend = true;
  return 0;
}
int
NetlinkSocket::ShutdownRecv (void)
{
  NS_LOG_FUNCTION_NOARGS ();
  m_shutdownRecv = true;
  return 0;
}

int
NetlinkSocket::Close (void)
{
  NS_LOG_FUNCTION_NOARGS ();
  ShutdownSend();
  ShutdownRecv();
  return 0;
}

int
NetlinkSocket::Connect (const Address &address)
{
  NS_LOG_FUNCTION (this << address);
  m_errno = Socket::ERROR_OPNOTSUPP;
  return 0;
}

Ptr<Packet>
NetlinkSocket::Recv (uint32_t maxSize, uint32_t flags)
{
  NS_LOG_FUNCTION (this << maxSize<< flags);
  if (m_dataReceiveQueue.empty())
    {
      return 0;
    }

  Ptr<Packet> p = m_dataReceiveQueue.front ();
  if (p->GetSize () <= maxSize) 
    {
      m_dataReceiveQueue.pop ();
      m_rxAvailable -= p->GetSize ();
    }
  else
    {
      p = 0; 
    }
  return p;
}

Ptr<Packet>
NetlinkSocket::RecvFrom (uint32_t maxSize, uint32_t flags, Address &fromAddress)
{
  NS_LOG_FUNCTION (this << maxSize << flags << fromAddress);
  Ptr<Packet> packet = Recv (maxSize, flags);
  if (packet != 0)
    {
      SocketAddressTag tag;
      bool found;
      found = packet->FindFirstMatchingByteTag (tag);
      NS_ASSERT (found);
      fromAddress = tag.GetAddress ();
    }
  return packet;
}

int
NetlinkSocket::Send (Ptr<Packet> p,uint32_t flags)
{
  NS_LOG_FUNCTION (this << p << flags);
  NetlinkSocketAddress address = NetlinkSocketAddress(m_dstPid, m_dstGroups);
  return SendTo(p, flags, address);
}

int
NetlinkSocket::SendTo (Ptr<Packet> p, uint32_t flags, const Address &toAddress)
{
  NS_LOG_FUNCTION (this << p << flags << toAddress);
  NetlinkSocketAddress ad;

  if (!NetlinkSocketAddress::IsMatchingType (toAddress))
    {
      NS_LOG_LOGIC ("ERROR_AFNOSUPPORT");
      m_errno = ERROR_AFNOSUPPORT;
      return -1;
    }
  ad = NetlinkSocketAddress::ConvertFrom (toAddress);
  m_dstPid = ad.GetProcessID();
  m_dstGroups = ad.GetGroupsMask();
  NS_LOG_INFO ("send netlink message to pid = " << m_dstPid << ", groups = " << m_dstGroups);
  NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " Sending netlink message from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ());

  //Ptr<NetlinkSocket>kernel_socket = GetNetlinkSocketByAddress(ad);
  //kernel_socket->m_receivedData.push_back(p);
  //kernel_socket->NotifyDataReceived(p);

  //when netlink socket send packet, the first step is to find the dest netlink socket through address
  //then send the packet to it. For we partly implement the netlink-family, the dest address
  //is always the kernel(pid = 0), (Actually, there must be one static kernel netlink socket to
  //receive/handle messages), we do not setup a kernel socket to receive packet.
  //
  
  MultipartNetlinkMessage multipartnlmsg;
  uint32_t packet_len, remain_len;

  packet_len = p->GetSize ();
  remain_len = packet_len;

  while (remain_len > NetlinkMessageHeader::GetHeaderSize ())
    {
      remain_len -= p->RemoveHeader (multipartnlmsg);
      NS_ASSERT (remain_len == p->GetSize ());

      //actually, message to kernel contains single one netlink message
      for (uint32_t i = 0; i < multipartnlmsg.GetNMessages(); i ++)
        {
          NetlinkMessage nlmsg = multipartnlmsg.GetMessage (i);
          if (HandleMessage (nlmsg) < 0)
            {
              if (m_errno)
                {
                  SendAckMessage (nlmsg, -ErrnoToSimuErrno ());
                }
            }
          else if (NetlinkMessage::IsMessageFlagsAck (nlmsg.GetHeader ().GetMsgFlags ()))
            {
              SendAckMessage (nlmsg, 0);
            }
        }
    }

  NotifyDataSent (packet_len);
  NS_LOG_INFO ("netlink socket kernel error " << -m_errno);
  return packet_len;
}

int
NetlinkSocket::GetSockName (Address &address) const
{
  NS_LOG_FUNCTION_NOARGS ();
  NetlinkSocketAddress ad;

  ad.SetProcessID (GetSrcPid ());
  ad.SetGroupsMask (GetSrcGroups ());
  address = ad;
  return 0;
}
int
NetlinkSocket::GetPeerName (Address &address) const
{
  NS_LOG_FUNCTION_NOARGS ();
  // XXX
  NS_ASSERT (false);
  return -1;
}
bool 
NetlinkSocket::SetAllowBroadcast (bool allowBroadcast)
{
  NS_ASSERT (false);
  return false;
}
bool 
NetlinkSocket::GetAllowBroadcast () const
{
  NS_ASSERT (false);
  return false;
}


void
NetlinkSocket::ForwardUp (Ptr<Packet> packet, NetlinkSocketAddress &address)
{
  NS_LOG_FUNCTION (this << packet << address);

  if (m_shutdownRecv)
    {
      return;
    }
  if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize)
    {
      SocketAddressTag tag;
      tag.SetAddress (address);
      packet->AddByteTag (tag);
      m_dataReceiveQueue.push (packet);
      m_rxAvailable += packet->GetSize ();
      NotifyDataRecv ();
    }
  else
    {
      NS_LOG_WARN ("No receive buffer space available.  Drop.");
      m_dropTrace (packet);
    }
}

int32_t
NetlinkSocket::SendMessageUnicast (const MultipartNetlinkMessage &nlmsg, uint32_t pid, int32_t nonblock)
{
  NS_LOG_FUNCTION (this << pid << nonblock);
  //here we send message instantly
  Ptr<Packet> p = Create<Packet> ();
  p->AddHeader (nlmsg);

  NetlinkSocketAddress address;
  address.SetProcessID (pid);

  //send packet to user space
  ForwardUp (p, address);
  return 0;
}
int32_t
NetlinkSocket::SendMessageBroadcast (const MultipartNetlinkMessage &nlmsg, 
                                     uint32_t pid, 
                                     uint32_t group,
                                     Ptr<Node> node)
{
  NS_LOG_FUNCTION ("SendMessageBroadcast" << pid << group);
  //fisrt find the dest netlink socket through group value, then attach this nlmsg to its recv-queue
  for (uint32_t i = 0; i < GroupSockets::GetNSockets (); i ++)
    {
      Ptr<NetlinkSocket> nlsock = GroupSockets::GetSocket (i);

      if ((nlsock->GetSrcGroups () & group) &&
          (nlsock->GetSrcPid () != pid) &&
          node == nlsock->GetNode ())
        {
          //here we send message instantly
          Ptr<Packet> p = Create<Packet> ();
          p->AddHeader (nlmsg);

          NetlinkSocketAddress address;
          address.SetProcessID (nlsock->GetSrcPid());
          address.SetGroupsMask (group);

          //send packet to user space
          nlsock->ForwardUp (p, address);
        }
    }
  return 0;
}
void
NetlinkSocket::SendAckMessage (const NetlinkMessage&nlmsg, int32_t err)
{
  NS_LOG_FUNCTION (this << err);
  NetlinkMessageHeader rep;
  NetlinkMessage ackmsg;
  NetlinkMessageError errmsg;

  rep.SetMsgPid (nlmsg.GetHeader ().GetMsgPid ());
  rep.SetMsgSeq (nlmsg.GetHeader ().GetMsgSeq ());
  rep.SetMsgType (NETLINK_MSG_ERROR);
  rep.SetMsgFlags (0);

  errmsg.SetError (err);
  //kernel send the whole nlmsg back if error != 0, here we just send the header back
  errmsg.SetMsg (nlmsg.GetHeader ());

  //then send errmsg back to user space
  ackmsg.SetHeader (rep);
  ackmsg.SetErrorMessage (errmsg);

  SendMessageUnicast (ackmsg, rep.GetMsgPid (), 1);
}

int32_t
NetlinkSocket::HandleMessage (const NetlinkMessage&nlmsg)
{
  NS_LOG_FUNCTION (this);
  uint16_t type = nlmsg.GetMsgType ();
  NetlinkMessageHeader nhr = nlmsg.GetHeader ();

  if (nhr.GetMsgLen () < NetlinkMessageHeader::GetHeaderSize ())
    {
      m_errno = ERROR_INVAL;
      return -1;
    }

  if (NetlinkMessage::IsMessageNetlinkControl (type))
    {
      NS_LOG_INFO ("netlink control message type not parsed in kernel");
      return 0;
    }
  else if (NetlinkMessage::IsMessageNetlinkRoute (type))
    {
      return HandleNetlinkRouteMessage (nlmsg);
    }
  else
    {
      NS_LOG_INFO ("netlink message type not parsed in kernel");
      m_errno = ERROR_INVAL;
      return -1;
    }  
}

int32_t
NetlinkSocket::HandleNetlinkRouteMessage (const NetlinkMessage &nlmsg)
{
  NS_LOG_FUNCTION (this);
  uint8_t family;
  int16_t type;
  int32_t err;

  /* Only requests are handled by kernel now */
  if (!NetlinkMessage::IsMessageFlagsRequest (nlmsg.GetHeader ().GetMsgFlags ()))
    return 0;

  type = nlmsg.GetMsgType ();

  /* A control message: ignore them */
  if (NetlinkMessage::IsMessageNetlinkControl (type))
    {
      return 0;
    }
  else if (NetlinkMessage::IsMessageNetlinkRoute (type))
    {
      /* All the messages must have at least 1 byte length */
      if (nlmsg.GetPayloadSize () < 1)
        return 0;

      family = nlmsg.GetFamily ();
      /*here we do not deal with different family, default for AF_NET*/
      NS_ASSERT(family == AF_INET || family == AF_UNSPEC || family == AF_PACKET || family == AF_INET6);  

      /*for GET*** message, dump it to userspace*/
      if (NetlinkMessage::IsMessageTypeGet (type) && 
          NetlinkMessage::IsMessageFlagsDump (nlmsg.GetHeader ().GetMsgFlags ())) 
        {
          DumpNetlinkRouteMessage (nlmsg, type, family);
          return -1;
        }

      /* other types of messages*/
      return DoNetlinkRouteMessage (nlmsg, type, family);
    }
  else/* Unknown message: reply with EINVAL */
    {
      err = ERROR_INVAL;
      return -1;
    } 
}

int32_t
NetlinkSocket::DumpNetlinkRouteMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
{
  NS_LOG_FUNCTION (this << type << family);

  NS_ASSERT (type == NETLINK_RTM_GETADDR || type == NETLINK_RTM_GETROUTE || type == NETLINK_RTM_GETLINK);

  MultipartNetlinkMessage nlmsg_dump;
  NetlinkMessageHeader nhr = nlmsg.GetHeader ();
  int32_t err;

  if (type == NETLINK_RTM_GETADDR)
    {
      nlmsg_dump = BuildInterfaceAddressDumpMessage (m_srcPid, nhr.GetMsgSeq(), family);
    }
  else if (type == NETLINK_RTM_GETLINK)
    {
      nlmsg_dump = BuildInterfaceInfoDumpMessage (m_srcPid, nhr.GetMsgSeq(), family);      
    }
  else if (type == NETLINK_RTM_GETROUTE)
    {
      nlmsg_dump = BuildRouteDumpMessage (m_srcPid, nhr.GetMsgSeq(), family);
    }
  else
    {
      m_errno = ERROR_INVAL;
      return -1;
    }

  //then append netlink message with type NLMSG_DONE
  NetlinkMessage nlmsg_done;
  NetlinkMessageHeader nhr2 = NetlinkMessageHeader (NETLINK_MSG_DONE, NETLINK_MSG_F_MULTI, 
                                                   nlmsg.GetHeader ().GetMsgSeq (), m_srcPid);
  nlmsg_done.SetHeader (nhr2);
  //kernel append nlmsg_dump size to it, here we omit it
  nlmsg_dump.AppendMessage (nlmsg_done);

  err = SendMessageUnicast (nlmsg_dump, m_srcPid, 1);
  return err;
}

/*here only for ADD/DEL/GET*** types*/
int32_t
NetlinkSocket::DoNetlinkRouteMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
{
  NS_LOG_FUNCTION (this << type <<family);
  int32_t err;

  if (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR)
    {      
      err = DoInterfaceAddressMessage (nlmsg, type, family);
    }
  else if (type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE || type == NETLINK_RTM_GETROUTE)
    {     
      err = DoRouteMessage (nlmsg, type, family);
    }
  else if (type == NETLINK_RTM_GETLINK || type == NETLINK_RTM_SETLINK)
    {     
      err = DoInterfaceInfoMessage (nlmsg, type, family);
    }
  else
    {
      NS_LOG_LOGIC ("netlink message:type( " << type << ") not processed by ns3 now." );
      m_errno = ERROR_INVAL;
      err = -1;
    } 
  
  return err;
}

MultipartNetlinkMessage
NetlinkSocket::BuildInterfaceAddressDumpMessage (uint32_t pid, uint32_t seq, uint8_t family)
{
  NS_LOG_FUNCTION (this << pid << seq <<family);
  MultipartNetlinkMessage nlmsg_dump;
  Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();

  for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i ++)
    {
      if (!ipv4->IsUp (i))
        continue;

      Ipv4Address addri = ipv4->GetAddress (i, 0).GetLocal ();
      Ipv4Mask maski = ipv4->GetAddress (i, 0).GetMask ();
      Ipv4Address bcast = ipv4->GetAddress (i, 0).GetBroadcast ();

      //here get the address mask length
      uint32_t mask = maski.Get ();
      uint8_t mask_len = 0;
      while (mask)
        {
          mask = mask << 1;
          mask_len ++;
        }
      
      //next fill the message body
      NetlinkMessage nlmsg_ifa;
      NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWADDR, NETLINK_MSG_F_MULTI, seq, pid);
      InterfaceAddressMessage ifamsg;

      ifamsg.SetInterfaceIndex (i);
      ifamsg.SetFamily (AF_INET);//default AF_INET      
      ifamsg.SetLength (mask_len);
      ifamsg.SetFlags (0);
      ifamsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);

      ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LOCAL,    ADDRESS, addri));
      ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ADDRESS,  ADDRESS, addri));
      ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_BROADCAST,ADDRESS, bcast));
      //      ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LABEL,    STRING,  "ns3-ifaddr"));//not used in ns3
      //ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ANYCAST,  ADDRESS, Ipv4Address("0.0.0.0")));//not used in ns3
      //XXXother attributes not used by ns3

      nlmsg_ifa.SetHeader(nhr);
      nlmsg_ifa.SetInterfaceAddressMessage (ifamsg);
      nlmsg_dump.AppendMessage (nlmsg_ifa);
    }

  // For IPv6
  Ptr<Ipv6>ipv6 = m_node->GetObject<Ipv6> ();

  for (uint32_t i = 0; i < ipv6->GetNInterfaces(); i ++)
    {
      if (!ipv6->IsUp (i))
        continue;

      for (uint32_t j = 0; j < ipv6->GetNAddresses(i); j ++)
        {
          Ipv6Address addri = ipv6->GetAddress (i, j).GetAddress();
          Ipv6Prefix prefix = ipv6->GetAddress (i, j).GetPrefix ();

          //here get the address mask length
          uint8_t mask_len = prefix.GetPrefixLength();

          //loopback address's prefix is wrong... FIXME
          if (addri.IsEqual(Ipv6Address::GetLoopback()))
            mask_len = 128;
      
          //next fill the message body
          NetlinkMessage nlmsg_ifa;
          NetlinkMessageHeader nhr = NetlinkMessageHeader(NETLINK_RTM_NEWADDR, NETLINK_MSG_F_MULTI, seq, pid);
          InterfaceAddressMessage ifamsg;       

          ifamsg.SetInterfaceIndex(i);
          ifamsg.SetFamily(AF_INET6);
          ifamsg.SetFlags(0);


          if (addri.IsLinkLocal())
            {
              ifamsg.SetLength(64);
              ifamsg.SetScope (RouteMessage::RT_SCOPE_LINK);
            }
          else
            {
              ifamsg.SetLength(mask_len);
              ifamsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
            }


          ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LOCAL,    ADDRESS, addri));
          ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ADDRESS,  ADDRESS, addri));
          //XXXother attributes not used by ns3

          nlmsg_ifa.SetHeader(nhr);
          nlmsg_ifa.SetInterfaceAddressMessage (ifamsg);
          nlmsg_dump.AppendMessage (nlmsg_ifa);
        }
    }
  return nlmsg_dump;
}
MultipartNetlinkMessage
NetlinkSocket::BuildInterfaceInfoDumpMessage (uint32_t pid, uint32_t seq, uint8_t family)
{
  NS_LOG_FUNCTION (this << pid << seq <<family);
  MultipartNetlinkMessage nlmsg_dump;
  for (uint32_t i = 0; i < m_node->GetNDevices (); i ++)
    {
      Ptr<NetDevice> dev = m_node->GetDevice (i);
      Address mac;
      Address bcast;
      uint32_t mtu;
      uint32_t flags = 0;

      mac = dev->GetAddress ();
      bcast = dev->GetBroadcast ();
      mtu = (uint32_t)dev->GetMtu ();

      if (dev->IsLinkUp ())
        {
          flags |= IFF_RUNNING;
          flags |= IFF_UP;
        }
      if (dev->IsBroadcast ())
        {
          flags |= IFF_BROADCAST;
        }
      if (dev->IsMulticast ())
        {
          flags |= IFF_MULTICAST;
        }

      NetlinkMessage nlmsg_ifinfo;
      NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWLINK, NETLINK_MSG_F_MULTI, seq, pid);
      InterfaceInfoMessage ifinfomsg;     

      ifinfomsg.SetFamily(0);      // AF_UNSPEC
      ifinfomsg.SetDeviceType (0); // not clear
      ifinfomsg.SetInterfaceIndex (i);
      ifinfomsg.SetDeviceFlags (flags); // not clear
      ifinfomsg.SetChangeMask (0xffffffff);

      // the ns3 device have no  name, here we set "ns3-device i" for test
      std::stringstream ss;
      ss <<  "ns3-device" << i;

      ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_IFNAME,    STRING,  ss.str()));
      //not used in ns3
      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_TXQLEN,    U32,     0));
      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_WEIGHT,    U32,     0));
      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_OPERSTATE, U8,      0));
      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_LINKMODE,  U8,      0));
      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_MAP,       UNSPEC,  0));
      ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_ADDRESS,   ADDRESS, mac));
      ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_BROADCAST, ADDRESS, bcast));
      ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_MTU,       U32,     mtu));
      ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_LINK,      U32,     i));
      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_QDISC,     STRING,  ""));
      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_MASTER,    U32,     0));
      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_STATS,     UNSPEC,  0));

      nlmsg_ifinfo.SetHeader (nhr);
      nlmsg_ifinfo.SetInterfaceInfoMessage (ifinfomsg);
      nlmsg_dump.AppendMessage (nlmsg_ifinfo);
    }
  return nlmsg_dump;
}
MultipartNetlinkMessage
NetlinkSocket::BuildRouteDumpMessage (uint32_t pid, uint32_t seq, uint8_t family)
{
  NS_LOG_FUNCTION (this << pid << seq <<family);
  MultipartNetlinkMessage nlmsg_dump;
  Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();

  // We only care about staticRouting for netlink support
  Ipv4StaticRoutingHelper routingHelper;
  Ptr<Ipv4StaticRouting> ipv4Static = routingHelper.GetStaticRouting (ipv4);
  for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); i ++)
    {
      NetlinkMessage nlmsg_rt;
      NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWROUTE, NETLINK_MSG_F_MULTI, seq, pid);
      RouteMessage rtmsg;
      Ipv4RoutingTableEntry route = ipv4Static->GetRoute (i);

      rtmsg.SetFamily (AF_INET);
      rtmsg.SetDstLength (32);
      rtmsg.SetSrcLength (0);
      rtmsg.SetTos (0);//not clear
      rtmsg.SetTableId (RouteMessage::RT_TABLE_MAIN);
      rtmsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
      rtmsg.SetProtocol (RouteMessage::RT_PROT_UNSPEC);
      rtmsg.SetFlags (RouteMessage::RT_F_CLONED);

      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_DST, ADDRESS, route.GetDest ()));
      // ns3 use local address as the route src address
      //      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_SRC, ADDRESS, route.GetSource()));
      //      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_PREFSRC, ADDRESS, route.GetSource()));//not used in ns3
      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_IIF, U32, route.GetInterface ()));
      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_OIF, U32, route.GetInterface ()));      
      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_GATEWAY, ADDRESS, route.GetGateway ()));

      nlmsg_rt.SetHeader (nhr);
      nlmsg_rt.SetRouteMessage (rtmsg);
      nlmsg_dump.AppendMessage (nlmsg_rt);
    }

  Ptr<Ipv6> ipv6 = m_node->GetObject<Ipv6> ();
  // We only care about staticRouting for netlink support
  Ipv6StaticRoutingHelper routingHelper6;
  Ptr<Ipv6StaticRouting> ipv6Static = routingHelper6.GetStaticRouting (ipv6);
  for (uint32_t i = 0; i < ipv6Static->GetNRoutes (); i ++)
    {
      NetlinkMessage nlmsg_rt;
      NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWROUTE, NETLINK_MSG_F_MULTI, seq, pid);
      RouteMessage rtmsg;
      Ipv6RoutingTableEntry route = ipv6Static->GetRoute (i);

      rtmsg.SetFamily (AF_INET6);
      rtmsg.SetDstLength (128);
      rtmsg.SetSrcLength (0);
      rtmsg.SetTos (0);//not clear
      rtmsg.SetTableId (RouteMessage::RT_TABLE_MAIN);
      rtmsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
      rtmsg.SetProtocol (RouteMessage::RT_PROT_UNSPEC);
      rtmsg.SetFlags (RouteMessage::RT_F_CLONED);

      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_DST, ADDRESS, route.GetDest ()));
      //ns3 use local address as the route src address
      // rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_SRC, ADDRESS, 
      //                                          ipv6->GetSourceAddress(route.GetDest ())));
      // rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_PREFSRC, ADDRESS, 
      //                                          ipv6->GetSourceAddress(route.GetDest ())));
      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_IIF, U32, route.GetInterface()));
      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_OIF, U32, route.GetInterface()));      
      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_GATEWAY, ADDRESS, route.GetGateway()));

      nlmsg_rt.SetHeader (nhr);
      nlmsg_rt.SetRouteMessage (rtmsg);
      nlmsg_dump.AppendMessage (nlmsg_rt);
    }

  return nlmsg_dump;
}

int32_t
NetlinkSocket::DoInterfaceAddressMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
{
  NS_LOG_FUNCTION (this << type << family);
  NS_ASSERT (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR);

  // XXX
  NS_ASSERT_MSG (false, "Not implemented yet (RTM_NEWADDR/RTM_DELADDR)");

  InterfaceAddressMessage ifamsg = nlmsg.GetInterfaceAddressMessage ();
  Ipv4Address addri, addr_local, bcast;
  NetlinkAttribute attr_local;
  uint32_t index = ifamsg.GetInterfaceIndex ();
  Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
  int flag4 = 0, flag6 = 0;

  if (type == NETLINK_RTM_NEWADDR)
    {
      //when adding an interface address, it should check the input arguments
      //prefix-len and local address attribute
      if (ifamsg.GetLength () > 32 || 
          ifamsg.GetAttributeByType (attr_local, InterfaceAddressMessage::IF_A_LOCAL) == false)
        {
          m_errno = ERROR_INVAL;
          return -1;
        }
    }  

  //get necessary information for add/del, many attributes we not used
  for (uint32_t i = 0; i < ifamsg.GetNNetlinkAttribute (); i ++)
    {
      NetlinkAttribute attr = ifamsg.GetNetlinkAttribute (i);
      uint32_t attr_type = attr.GetAttrType ();

      switch(attr_type)
        {
        case InterfaceAddressMessage::IF_A_ADDRESS:
          addri = Ipv4Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
          break;
        case InterfaceAddressMessage::IF_A_BROADCAST:
          bcast = Ipv4Address::ConvertFrom(attr.GetAttrPayload ().GetAddress ());
          break;
        case InterfaceAddressMessage::IF_A_LOCAL:
          addr_local = Ipv4Address::ConvertFrom(attr.GetAttrPayload ().GetAddress ());
          break;
        case InterfaceAddressMessage::IF_A_LABEL:
        case InterfaceAddressMessage::IF_A_ANYCAST:
          break;
        }
    }

  if (type == NETLINK_RTM_NEWADDR)
    {
      //when adding an interface address by index, if the indexed interface was not exist,
      //create an new NetDevice with an new index and set the address
      //otherwise set the indexed interface directly
      if (index >= ipv4->GetNInterfaces ())
        {          
          Ptr<SimpleNetDevice> dev;
          dev = CreateObject<SimpleNetDevice> ();
          dev ->SetAddress (Mac48Address::Allocate ());
          m_node->AddDevice (dev);

          uint32_t netdev_idx = ipv4->AddInterface (dev);
          // FIXME!
          Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (addri, Ipv4Mask ());
          ipv4->AddAddress (netdev_idx, ipv4Addr);
          ipv4->SetUp (netdev_idx);
          NS_LOG_INFO ("Add an interface address at index "<< netdev_idx << "but not the ifamsg input" << index);
        }
      else
        {
          Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (addri, Ipv4Mask ());
          ipv4->AddAddress (index, ipv4Addr);
          if (!ipv4->IsUp (index))
            ipv4->SetUp (index);
        }    
      flag4 = 1;
    }
  else//type == NETLINK_RTM_DELADDR
    {
      //when delete an interface address by index, if the indexed interface  was not exist
      //return an error EINVAL, otherwise set down the interface which has the addri
      if (index >= ipv4->GetNInterfaces ())
        {
          m_errno = ERROR_NODEV;
          return -1;
        }
      else
        {
          for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i ++)
            {
              Ipv4Address ad = ipv4->GetAddress (i, 0).GetLocal ();
              if (ad == addri && ipv4->IsUp (i))
                {
                  ipv4->SetDown (i);
                  break;
                }
              if (i == ipv4->GetNInterfaces () - 1)
                {
                  m_errno = ERROR_ADDRNOTAVAIL;
                  return -1;
                }
            }
          flag4 = 1;
        }      
    }
  
  //then send an broadcast message, let all user know this operation happened
  NetlinkMessage nlmsg_broadcast = nlmsg;
  NetlinkMessageHeader nhr;
  nhr.SetMsgLen (nlmsg.GetHeader ().GetMsgLen ());
  nhr.SetMsgType (nlmsg.GetHeader ().GetMsgType ());
  nlmsg_broadcast.SetHeader (nhr);
  if (flag4)
    {
      SendMessageBroadcast (nlmsg_broadcast, 0, NETLINK_RTM_GRP_IPV4_IFADDR, GetNode ());
    }
  else if (flag6)
    {
      SendMessageBroadcast (nlmsg_broadcast, 0, RTMGRP_IPV6_IFADDR, GetNode ());
    }

  return 0;
}

int32_t
NetlinkSocket::DoInterfaceInfoMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
{
  NS_LOG_FUNCTION (this << type << family);
  NS_ASSERT (type == NETLINK_RTM_GETLINK || type == NETLINK_RTM_SETLINK);
  InterfaceInfoMessage ifinfomsg = nlmsg.GetInterfaceInfoMessage ();
  // XXX
  NS_ASSERT_MSG (false, "Not implemented yet (RTM_GETLINK/RTM_SETLINK)");
  return -1;
}

Address
NetlinkSocket::ConvertFrom (uint8_t family, const Address &address)
{
  Address retval;
  if (family == AF_INET)
    {
      retval = Ipv4Address::ConvertFrom (address);
    }
  else if (family == AF_INET6)
    {
      retval = Ipv6Address::ConvertFrom (address);
    }
  return retval;
}

int32_t
NetlinkSocket::DoRouteMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
{
  NS_LOG_FUNCTION (this << type << family);
  NS_ASSERT (type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE ||type == NETLINK_RTM_GETROUTE);

  RouteMessage rtmsg = nlmsg.GetRouteMessage ();
  Ipv4Address src, dest, gateway;
  Ipv6Address src6, dest6, gateway6;
  uint32_t index = 0;
  int attr_flags[RouteMessage::RT_A_MAX] = {0};
  uint8_t dstlen = rtmsg.GetDstLength ();

  //get necessary information for add/del, many attributes we not used
  for (uint32_t i = 0; i < rtmsg.GetNNetlinkAttribute (); i ++)
    {
      NetlinkAttribute attr = rtmsg.GetNetlinkAttribute (i);
      uint32_t attr_type = attr.GetAttrType ();
      attr_flags[attr_type] = 1;

      switch(attr_type)
        {
        case RouteMessage::RT_A_DST:
          if (family == AF_INET)
            {
              dest = Ipv4Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
            }
          else if (family == AF_INET6)
            {
              dest6 = Ipv6Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
            }
          break;
        case RouteMessage::RT_A_SRC:
          if (family == AF_INET)
            {
              src = Ipv4Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
            }
          else if (family == AF_INET6)
            {
              src6 = Ipv6Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
            }
          break;
        case RouteMessage::RT_A_OIF:
          index = attr.GetAttrPayload ().GetU32 ();
          break;
        case RouteMessage::RT_A_GATEWAY:
          if (family == AF_INET)
            {
              gateway = Ipv4Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
            }
          else if (family == AF_INET6)
            {
              gateway6 = Ipv6Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
            }
          break;
        case RouteMessage::RT_A_IIF:
        case RouteMessage::RT_A_PRIORITY:
        case RouteMessage::RT_A_PREFSRC:
        case RouteMessage::RT_A_METRICS:
        case RouteMessage::RT_A_MULTIPATH:
        case RouteMessage::RT_A_PROTOINFO:
        case RouteMessage::RT_A_FLOW:
        case RouteMessage::RT_A_CACHEINFO:
        case RouteMessage::RT_A_SESSION:
        case RouteMessage::RT_A_MP_ALGO:
        case RouteMessage::RT_A_TABLE:
          NS_LOG_INFO("route attribute not used by ns3" << attr_type);
          //not used by ns3
          break;
        }
    }

  // Sigh....
  Ptr<Ipv4>ipv4 = m_node->GetObject<Ipv4> ();
  Ipv4StaticRoutingHelper routingHelper;
  Ptr<Ipv4StaticRouting> ipv4Static = routingHelper.GetStaticRouting (ipv4);

  Ptr<Ipv6>ipv6 = m_node->GetObject<Ipv6> ();
  Ipv6StaticRoutingHelper routingHelper6;
  Ptr<Ipv6StaticRouting> ipv6Static = routingHelper6.GetStaticRouting (ipv6);

  NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " Route message, type: " << type << "; from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
      << " to " << dest<< " through " << gateway);

  if (type == NETLINK_RTM_NEWROUTE)
    {
      //ns3 add a route entry only depends on 2 or 3 attribute
      //other route msg attibute were ignored
      if (attr_flags[RouteMessage::RT_A_DST])
        {
          if (family == AF_INET)
            {
              if (!attr_flags[RouteMessage::RT_A_OIF])
                {
                  bool found = 0;
                  for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++)
                    {
                      for (uint32_t j = 0; j < ipv4->GetNAddresses (i); j++)
                        {
                          if ((attr_flags[RouteMessage::RT_A_GATEWAY]))
                            {
                              Ipv4Mask mask = ipv4->GetAddress (i, j).GetMask ();
                              if (mask.IsMatch (ipv4->GetAddress (i, j).GetLocal (), gateway))
                                {
                                  index = i;
                                  found = true;
                                  break;
                                }
                            }
                          if (found) break;
                        }
                    }
                  if (!found)
                    {
                      NS_LOG_DEBUG ("No suitable interface to add an route entry");
                      m_errno = ERROR_ADDRNOTAVAIL;
                      return -1;
                    }
                }
            if (dstlen == 32)
              {
                int exist_flag = 0;
                for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); ++i)
                  {
                    Ipv4RoutingTableEntry rt = ipv4Static->GetRoute (i);
                    if (dest == rt.GetDest ())
                      {
                        exist_flag = 1;
                      }
                  }

                if (exist_flag)
                  { //route to dest already exists
                    int delete_flag = 0;
                    if (nlmsg.GetHeader ().GetMsgFlags () & NETLINK_MSG_F_REPLACE)
                      {
                        for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); ++i)
                          {
                            Ipv4RoutingTableEntry rt = ipv4Static->GetRoute (i);
                            if (dest == rt.GetDest ())
                              {
                                ipv4Static->RemoveRoute (i);
                                NS_LOG_DEBUG ("Route from  " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal () << " to "
                                    << dest << " through " << gateway << " removed");
                                delete_flag = 1;
                              }
                          }

                        if (!delete_flag)
                          {
                             NS_LOG_INFO ("no route entry removed by dest address in new route sector " << dest);
                             m_errno = ERROR_INVAL;
                             return -1;
                           }
                      }
                    else
                      {
                        NS_LOG_DEBUG ("Route exists but overwriting declined!");
                      }
                    if ((attr_flags[RouteMessage::RT_A_GATEWAY]))
                      {
                        NS_LOG_DEBUG (Simulator::Now().GetSeconds() << "Overwrite route from "
                            << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal () << " to " << dest<< " through " << gateway << " with index" << index);
                        ipv4Static->AddHostRouteTo (dest, gateway, index);
                      }
                    else
                      {
                        NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "Overwrite route from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
                            << " to " << dest<< " through " << "self" << " with index" << index);
                        ipv4Static->AddHostRouteTo (dest, index);
                      }
                }
                else
                  { //route to dest doesn't exist
                    if (nlmsg.GetHeader ().GetMsgFlags () & NETLINK_MSG_F_CREATE)
                      {
                        if (attr_flags[RouteMessage::RT_A_GATEWAY])
                          {
                            NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "Add new route from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
                                << " to " << dest<< " through " << gateway << " with index" << index);
                            ipv4Static->AddHostRouteTo (dest, gateway, index);
                          }
                        else
                          {
                            NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "Add new route from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
                                << " to " << dest<< " through " << "self" << " with index" << index);
                            ipv4Static->AddHostRouteTo (dest, index);
                          }
                      }
                    else
                      {
                        NS_LOG_ERROR ("Route doesn't exist but writing declined!");
                      }
                  }

                NS_LOG_DEBUG ("=After change attempt=");
                //Dump of table
                NS_LOG_DEBUG (m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal () << ":");
                for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); ++i)
                  {
                    Ipv4RoutingTableEntry rt = ipv4Static->GetRoute (i);
                    NS_LOG_DEBUG (rt.GetDest () << " through " << rt.GetGateway ());
                  }
                NS_LOG_DEBUG ("= = = = = = = = = = =");
              }
            else // dstlen != 32
              {
                if (attr_flags[RouteMessage::RT_A_GATEWAY])
                  {
                    ipv4Static->AddNetworkRouteTo (dest, Ipv4Mask (~(1<<(32 - dstlen))+1), gateway, index);
                  }
                else
                  {
                    ipv4Static->AddNetworkRouteTo (dest, Ipv4Mask (~(1<<(32 - dstlen))+1), index);
                  }
              }
          }
          else if (family == AF_INET6)
            {
            if (!attr_flags[RouteMessage::RT_A_OIF])
              {
#ifdef FIXME
              if (ipv6->GetIfIndexForDestination (gateway6, index) == false)
                {
                  NS_LOG_INFO ("No suitable interface to add an route entry");
                  m_errno = ERROR_ADDRNOTAVAIL;
                  return -1;
                }
#endif
              }

            Ipv6Prefix pref (dstlen);
            if (attr_flags[RouteMessage::RT_A_GATEWAY])
              {
                ipv6Static->AddNetworkRouteTo (dest6, pref, gateway6, index);
              }
            else
              {
                ipv6Static->AddNetworkRouteTo (dest6, pref, Ipv6Address("::"), index);
              }
            }
          }
        else
          {
            NS_LOG_INFO("too few attributes to add an route entry");
            m_errno = ERROR_INVAL;
            return -1;
          }
    }
  else if (type == NETLINK_RTM_DELROUTE)
    {
      NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "Route delete request from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
          << " to " << dest<< " through " << gateway);
      if (attr_flags[RouteMessage::RT_A_DST])
        {
          int delete_flag = 0;

          if (family == AF_INET)
            {
              for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); i ++)
                {
                Ipv4RoutingTableEntry rt = ipv4Static->GetRoute (i);
                if (gateway == rt.GetGateway () && dest == rt.GetDest ())
                  {
                    ipv4Static->RemoveRoute (i);
                    delete_flag = 1;
                  }
                }
            }
          else if (family == AF_INET6)
            {
              for (uint32_t i = 0; i < ipv6Static->GetNRoutes (); i ++)
                {
                Ipv6RoutingTableEntry rt = ipv6Static->GetRoute (i);
                if (gateway6 == rt.GetGateway () && dest6 == rt.GetDest ())
                  {
                    ipv6Static->RemoveRoute (i);
                    delete_flag = 1;
                  }
                }
            }

          if (!delete_flag)
            {
              NS_LOG_INFO ("no route entry removed by dest address " << dest);
              m_errno = ERROR_INVAL;
              return -1;
            }
        }
      else
        {
          NS_LOG_INFO ("too few attributes to add an route entry");
          m_errno = ERROR_INVAL;
          return -1;    
        }
    }
  else// type == NETLINK_RTM_GETROUTE
    {
      NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "GetRoute "<< "from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal () << " to " << dest);
      if (!attr_flags[RouteMessage::RT_A_DST])
        {
          NS_LOG_INFO ("too few attributes to get an route entry");
          m_errno = ERROR_INVAL;
          return -1;
        }
      
      int get_flag = 0;
      if (family == AF_INET)
        {
          for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); i ++)
            {
              Ipv4RoutingTableEntry route = ipv4Static->GetRoute (i);
              //find the route entry with same dest address and send unicast to user space
              if (dest.IsEqual (route.GetDest ()))
                {
                  //                Ptr<Ipv4>ipv4 = m_node->GetObject<Ipv4> ();
                  NetlinkMessage nlmsg_route;
                  NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWROUTE, 0, 
                                                                   nlmsg.GetHeader ().GetMsgSeq (), m_srcPid);
                  RouteMessage rtmsg;

                  //fill rtmsg and attributes
                  rtmsg.SetFamily (AF_INET);
                  rtmsg.SetDstLength (32);
                  rtmsg.SetSrcLength (0);
                  rtmsg.SetTos (0);//not clear
                  rtmsg.SetTableId (RouteMessage::RT_TABLE_MAIN);
                  rtmsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
                  rtmsg.SetProtocol (RouteMessage::RT_PROT_UNSPEC);
                  rtmsg.SetFlags (RouteMessage::RT_F_CLONED);

                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_DST, ADDRESS, route.GetDest ()));
                  //ns3 use local address as the route src address
                  // rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_SRC, ADDRESS, ipv4->GetSourceAddress(route.GetDest ())));
                  // rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_PREFSRC, ADDRESS, ipv4->GetSourceAddress(route.GetDest ())));
                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_IIF, U32, route.GetInterface ()));
                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_OIF, U32, route.GetInterface ()));
                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_GATEWAY, ADDRESS, route.GetGateway ()));

                  //fill an netlink message body
                  nlmsg_route.SetHeader (nhr);
                  nlmsg_route.SetRouteMessage (rtmsg);
                  
                  SendMessageUnicast (nlmsg_route, m_srcPid, 1);
                  get_flag = 1;
                }
            }
        }
      else if (family == AF_INET6)
        {
          for (uint32_t i = 0; i < ipv6Static->GetNRoutes(); i ++)
            {
              Ipv6RoutingTableEntry route = ipv6Static->GetRoute (i);
              //find the route entry with same dest address and send unicast to user space
              if (dest6.IsEqual (route.GetDest ()))
                {
                  NetlinkMessage nlmsg_route;
                  NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWROUTE, 0, 
                                                                   nlmsg.GetHeader ().GetMsgSeq (), m_srcPid);
                  RouteMessage rtmsg;

                  //fill rtmsg and attributes
                  rtmsg.SetFamily (AF_INET6);
                  rtmsg.SetDstLength (32);
                  rtmsg.SetSrcLength (0);
                  rtmsg.SetTos (0);//not clear
                  rtmsg.SetTableId (RouteMessage::RT_TABLE_MAIN);
                  rtmsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
                  rtmsg.SetProtocol (RouteMessage::RT_PROT_UNSPEC);
                  rtmsg.SetFlags (RouteMessage::RT_F_CLONED);

                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_DST, ADDRESS, route.GetDest ()));
                  //ns3 use local address as the route src address
                  // rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_SRC, ADDRESS, ipv6->GetSourceAddress(route.GetDest ())));
                  // rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_PREFSRC, ADDRESS, ipv6->GetSourceAddress(route.GetDest ())));
                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_IIF, U32, route.GetInterface ()));
                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_OIF, U32, route.GetInterface ()));
                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_GATEWAY, ADDRESS, route.GetGateway ()));

                  //fill an netlink message body
                  nlmsg_route.SetHeader (nhr);
                  nlmsg_route.SetRouteMessage (rtmsg);

                  SendMessageUnicast (nlmsg_route, m_srcPid, 1);
                  get_flag = 1;
                }
            }
        }
      
      if (!get_flag)
        {
          NS_LOG_INFO ("no route entry exist by dest address" << dest);
          m_errno = ERROR_INVAL;
          return -1;
        }
    }

  //then send an broadcast message, let all user know this operation happened
  MultipartNetlinkMessage nlmsg_multi;
  NetlinkMessage nlmsg_broadcast = nlmsg;
  NetlinkMessage nlmsg_done;
  NetlinkMessageHeader nhr_done = NetlinkMessageHeader (NETLINK_MSG_DONE, NETLINK_MSG_F_MULTI, 0, 0);
  nlmsg_done.SetHeader (nhr_done);
  nlmsg_multi.AppendMessage (nlmsg);
  nlmsg_multi.AppendMessage (nlmsg_done);
  SendMessageBroadcast (nlmsg_multi, 0, NETLINK_RTM_GRP_IPV4_ROUTE, GetNode ());
  //   SendMessageBroadcast(nlmsg_broadcast, 0, RTMGRP_IPV6_ROUTE);
  return 0;
}

int32_t
NetlinkSocket::NotifyIfLinkMessage (Address address, uint16_t type, uint8_t family)
{
  NS_ASSERT_MSG (false, "Not implemented yet (NotifyIfLinkMessage)");
  return 0;
}

int32_t
NetlinkSocket::NotifyIfAddrMessage (Ipv6Interface* interface, Ipv6Address addr, int cmd)
{
  MultipartNetlinkMessage nlmsg_multi;
  NetlinkMessage nlmsg_ifa;
  NetlinkMessageHeader nhr = NetlinkMessageHeader (cmd, NETLINK_MSG_F_MULTI, 0, 0);
  InterfaceAddressMessage ifamsg;

  NS_ASSERT_MSG (false, "Not implemented yet (NotifyIfAddrMessage)");

  // FIXME!
  Ipv6Prefix prefix = Ipv6Prefix(64);

  //here get the address mask length
  uint8_t bytes[16];
  prefix.GetBytes (bytes);
  uint8_t mask_len = 0;
  for (int j = 0; j < 16; j++)
    {
      while (bytes[j])
        {
          bytes[j] = bytes[j] << 1;
          mask_len ++;
        }
    }
      
  ifamsg.SetInterfaceIndex (interface->GetDevice ()->GetIfIndex ());
  ifamsg.SetFamily (AF_INET6);
  ifamsg.SetLength (mask_len);
  ifamsg.SetFlags (0);
  ifamsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);

  ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LOCAL,    ADDRESS, addr));
  ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ADDRESS,  ADDRESS, addr));
  //  ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_BROADCAST,ADDRESS, bcast));
  //      ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LABEL,    STRING,  "ns3-ifaddr"));//not used in ns3
  //ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ANYCAST,  ADDRESS, Ipv4Address("0.0.0.0")));//not used in ns3
  //XXXother attributes not used by ns3

  nlmsg_ifa.SetHeader (nhr);
  nlmsg_ifa.SetInterfaceAddressMessage (ifamsg);

  NetlinkMessage nlmsg_done;
  NetlinkMessageHeader nhr_done = NetlinkMessageHeader (NETLINK_MSG_DONE, NETLINK_MSG_F_MULTI, 0, 0);
  nlmsg_done.SetHeader (nhr_done);

  nlmsg_multi.AppendMessage (nlmsg_ifa);
  nlmsg_multi.AppendMessage (nlmsg_done);

  SendMessageBroadcast (nlmsg_multi, 0, RTMGRP_IPV6_IFADDR, interface->GetDevice ()->GetNode ());  
  return 0;
}

#ifdef FIXME
int32_t
NetlinkSocket::NotifyRouteMessage(Ojbect route, uint16_t type, uint8_t family)
{
  NetlinkMessage nlmsg_broadcast = nlmsg;
  NetlinkMessageHeader nhr;
  NS_ASSERT_MSG (false, "Not implemented yet");

  nhr.SetMsgLen (nlmsg.GetHeader ().GetMsgLen ());
  nhr.SetMsgType (nlmsg.GetHeader ().GetMsgType ());
  nlmsg_broadcast.SetHeader (nhr);
  SendMessageBroadcast (nlmsg_broadcast, 0, RTMGRP_IPV6_ROUTE);
  return 0;
}
#endif

}//namespace ns3