text: /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
  /*
   *  Copyright (c) 2007,2008, 2009 INRIA, UDcast
   *
   * 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
   *
   *         Mohamed Amine Ismail <amine.ismail@sophia.inria.fr>
   */
  #include "ipcs-classifier-record.h"
  #include <stdint.h>
  #include "ns3/ipv4-address.h"
  #include "wimax-tlv.h"
  NS_LOG_COMPONENT_DEFINE ("IpcsClassifierRecord");
  
  namespace ns3 {
  
  IpcsClassifierRecord::IpcsClassifierRecord (void)
  {
    m_priority = 255;
    m_priority = 0;
    m_index = 0;
    m_tosLow = 0;
    m_tosHigh = 0;
    m_tosMask = 0;
    m_cid = 0;
    m_protocol.push_back (6); // tcp
    m_protocol.push_back (17); // udp
    AddSrcAddr (Ipv4Address ("0.0.0.0"), Ipv4Mask ("0.0.0.0"));
    AddDstAddr (Ipv4Address ("0.0.0.0"), Ipv4Mask ("0.0.0.0"));
    AddSrcPortRange (0, 65535);
    AddDstPortRange (0, 65535);
  }
  
  IpcsClassifierRecord::~IpcsClassifierRecord (void)
  {
  }
  
  IpcsClassifierRecord::IpcsClassifierRecord (Tlv tlv)
  {
    NS_ASSERT_MSG (tlv.GetType () == CsParamVectorTlvValue::Packet_Classification_Rule, "Invalid TLV");
    ClassificationRuleVectorTlvValue* rules = ((ClassificationRuleVectorTlvValue*)(tlv.PeekValue ()));
    m_priority = 0;
    m_index = 0;
    m_tosLow = 0;
    m_tosHigh = 0;
    m_tosMask = 0;
    m_cid = 0;
    for (std::vector<Tlv*>::const_iterator iter = rules->Begin (); iter != rules->End (); ++iter)
      {
        switch ((*iter)->GetType ())
          {
          case ClassificationRuleVectorTlvValue::Priority:
            {
              m_priority = ((U8TlvValue*)((*iter)->PeekValue ()))->GetValue ();
              break;
            }
          case ClassificationRuleVectorTlvValue::ToS:
            {
              NS_FATAL_ERROR ("ToS Not implemented-- please implement and contribute a patch");
              break;
            }
          case ClassificationRuleVectorTlvValue::Protocol:
            {
              ProtocolTlvValue * list = (ProtocolTlvValue *)(*iter)->PeekValue ();
              for (std::vector<uint8_t>::const_iterator iter2 = list->Begin (); iter2 != list->End (); ++iter2)
                {
                  AddProtocol (*iter2);
                }
              break;
            }
          case ClassificationRuleVectorTlvValue::IP_src:
            {
              Ipv4AddressTlvValue * list = (Ipv4AddressTlvValue *)(*iter)->PeekValue ();
              for (std::vector<Ipv4AddressTlvValue::ipv4Addr>::const_iterator iter2 = list->Begin (); iter2 != list->End (); ++iter2)
                {
                  AddSrcAddr ((*iter2).Address, (*iter2).Mask);
                }
              break;
            }
          case ClassificationRuleVectorTlvValue::IP_dst:
            {
              Ipv4AddressTlvValue * list = (Ipv4AddressTlvValue *)(*iter)->PeekValue ();
              for (std::vector<Ipv4AddressTlvValue::ipv4Addr>::const_iterator iter2 = list->Begin (); iter2 != list->End (); ++iter2)
                {
                  AddDstAddr ((*iter2).Address, (*iter2).Mask);
                }
              break;
            }
          case ClassificationRuleVectorTlvValue::Port_src:
            {
              PortRangeTlvValue * list = (PortRangeTlvValue *)(*iter)->PeekValue ();
              for (std::vector<PortRangeTlvValue::PortRange>::const_iterator iter2 = list->Begin (); iter2 != list->End (); ++iter2)
                {
                  AddSrcPortRange ((*iter2).PortLow, (*iter2).PortHigh);
                }
              break;
            }
          case ClassificationRuleVectorTlvValue::Port_dst:
            {
              PortRangeTlvValue * list = (PortRangeTlvValue *)(*iter)->PeekValue ();
              for (std::vector<PortRangeTlvValue::PortRange>::const_iterator iter2 = list->Begin (); iter2 != list->End (); ++iter2)
                {
                  AddDstPortRange ((*iter2).PortLow, (*iter2).PortHigh);
                }
              break;
            }
          case ClassificationRuleVectorTlvValue::Index:
            {
              m_index = ((U16TlvValue*)((*iter)->PeekValue ()))->GetValue ();
              break;
            }
          }
      }
  }
  
  IpcsClassifierRecord::IpcsClassifierRecord (Ipv4Address SrcAddress,
                                              Ipv4Mask SrcMask,
                                              Ipv4Address DstAddress,
                                              Ipv4Mask DstMask,
                                              uint16_t SrcPortLow,
                                              uint16_t SrcPortHigh,
                                              uint16_t DstPortLow,
                                              uint16_t DstPortHigh,
                                              uint8_t protocol,
                                              uint8_t priority)
  {
    m_priority = priority;
    m_protocol.push_back (protocol);
    AddSrcAddr (SrcAddress, SrcMask);
    AddDstAddr (DstAddress, DstMask);
    AddSrcPortRange (SrcPortLow, SrcPortHigh);
    AddDstPortRange (DstPortLow, DstPortHigh);
    m_index = 0;
    m_tosLow = 0;
    m_tosHigh = 0;
    m_tosMask = 0;
    m_cid = 0;
  }
  
  void
  IpcsClassifierRecord::AddSrcAddr (Ipv4Address srcAddress, Ipv4Mask srcMask)
  {
    struct ipv4Addr tmp;
    tmp.Address = srcAddress;
    tmp.Mask = srcMask;
    m_srcAddr.push_back (tmp);
  }
  void
  IpcsClassifierRecord::AddDstAddr (Ipv4Address dstAddress, Ipv4Mask dstMask)
  {
    struct ipv4Addr tmp;
    tmp.Address = dstAddress;
    tmp.Mask = dstMask;
    m_dstAddr.push_back (tmp);
  }
  void
  IpcsClassifierRecord::AddSrcPortRange (uint16_t srcPortLow, uint16_t srcPortHigh)
  {
    struct PortRange tmp;
    tmp.PortLow = srcPortLow;
    tmp.PortHigh = srcPortHigh;
    m_srcPortRange.push_back (tmp);
  
  }
  void
  IpcsClassifierRecord::AddDstPortRange (uint16_t dstPortLow, uint16_t dstPortHigh)
  {
    struct PortRange tmp;
    tmp.PortLow = dstPortLow;
    tmp.PortHigh = dstPortHigh;
    m_dstPortRange.push_back (tmp);
  }
  void
  IpcsClassifierRecord::AddProtocol (uint8_t proto)
  {
    m_protocol.push_back (proto);
  }
  void
  IpcsClassifierRecord::SetPriority (uint8_t prio)
  {
    m_priority = prio;
  }
  void
  IpcsClassifierRecord::SetCid (uint16_t cid)
  {
    m_cid = cid;
  }
  void
  IpcsClassifierRecord::SetIndex (uint16_t index)
  {
    m_index = index;
  }
  
  uint16_t
  IpcsClassifierRecord::GetIndex (void) const
  {
    return m_index;
  }
  uint16_t
  IpcsClassifierRecord::GetCid (void) const
  {
    return m_cid;
  }
  uint8_t
  IpcsClassifierRecord::GetPriority (void) const
  {
    return m_priority;
  }
  
  bool
  IpcsClassifierRecord::CheckMatchSrcAddr (Ipv4Address srcAddress) const
  {
    for (std::vector<struct ipv4Addr>::const_iterator iter = m_srcAddr.begin (); iter != m_srcAddr.end (); ++iter)
      {
        NS_LOG_INFO ("src addr check match: pkt=" << srcAddress << " cls=" << (*iter).Address << "/" << (*iter).Mask);
        if (srcAddress.CombineMask ((*iter).Mask) == (*iter).Address)
          {
            return true;
          }
      }
    NS_LOG_INFO ("NOT OK!");
    return false;
  }
  bool
  IpcsClassifierRecord::CheckMatchDstAddr (Ipv4Address dstAddress) const
  {
  
    for (std::vector<struct ipv4Addr>::const_iterator iter = m_dstAddr.begin (); iter != m_dstAddr.end (); ++iter)
      {
        NS_LOG_INFO ("dst addr check match: pkt=" << dstAddress << " cls=" << (*iter).Address << "/" << (*iter).Mask);
        if (dstAddress.CombineMask ((*iter).Mask) == (*iter).Address)
          {
            return true;
          }
      }
    NS_LOG_INFO ("NOT OK!");
    return false;
  }
  bool
  IpcsClassifierRecord::CheckMatchSrcPort (uint16_t port) const
  {
    for (std::vector<struct PortRange>::const_iterator iter = m_srcPortRange.begin (); iter != m_srcPortRange.end (); ++iter)
      {
        NS_LOG_INFO ("src port check match: pkt=" << port << " cls= [" << (*iter).PortLow << " TO " << (*iter).PortHigh
                                                  << "]");
        if (port >= (*iter).PortLow && port <= (*iter).PortHigh)
          {
            return true;
          }
      }
    NS_LOG_INFO ("NOT OK!");
    return false;
  }
  bool
  IpcsClassifierRecord::CheckMatchDstPort (uint16_t port) const
  {
    for (std::vector<struct PortRange>::const_iterator iter = m_dstPortRange.begin (); iter != m_dstPortRange.end (); ++iter)
      {
        NS_LOG_INFO ("dst port check match: pkt=" << port << " cls= [" << (*iter).PortLow << " TO " << (*iter).PortHigh
                                                  << "]");
        if (port >= (*iter).PortLow && port <= (*iter).PortHigh)
          {
            return true;
          }
      }
    NS_LOG_INFO ("NOT OK!");
    return false;
  }
  bool
  IpcsClassifierRecord::CheckMatchProtocol (uint8_t proto) const
  {
    for (std::vector<uint8_t>::const_iterator iter = m_protocol.begin (); iter != m_protocol.end (); ++iter)
      {
        NS_LOG_INFO ("proto check match: pkt=" << (uint16_t) proto << " cls=" << (uint16_t) proto);
        if (proto == (*iter))
          {
            return true;
          }
      }
    NS_LOG_INFO ("NOT OK!");
    return false;
  }
  bool
  IpcsClassifierRecord::CheckMatch (Ipv4Address srcAddress,
                                    Ipv4Address dstAddress,
                                    uint16_t srcPort,
                                    uint16_t dstPort,
                                    uint8_t proto) const
  {
    return (CheckMatchProtocol (proto) && CheckMatchDstPort (dstPort) && CheckMatchSrcPort (srcPort)
            && CheckMatchDstAddr (dstAddress) && CheckMatchSrcAddr (srcAddress));
  }
  
  Tlv
  IpcsClassifierRecord::ToTlv (void) const
  {
    Ipv4AddressTlvValue ipv4AddrValSrc;
    for (std::vector<struct ipv4Addr>::const_iterator iter = m_srcAddr.begin (); iter != m_srcAddr.end (); ++iter)
      {
        ipv4AddrValSrc.Add ((*iter).Address, (*iter).Mask);
      }
  
    Ipv4AddressTlvValue ipv4AddrValDst;
    for (std::vector<struct ipv4Addr>::const_iterator iter = m_dstAddr.begin (); iter != m_dstAddr.end (); ++iter)
      {
        ipv4AddrValDst.Add ((*iter).Address, (*iter).Mask);
      }
  
    ProtocolTlvValue protoVal;
    for (std::vector<uint8_t>::const_iterator iter = m_protocol.begin (); iter != m_protocol.end (); ++iter)
      {
        protoVal.Add ((*iter));
      }
  
    PortRangeTlvValue portValueSrc;
    for (std::vector<struct PortRange>::const_iterator iter = m_srcPortRange.begin (); iter != m_srcPortRange.end (); ++iter)
      {
        portValueSrc.Add ((*iter).PortLow, (*iter).PortHigh);
      }
  
    PortRangeTlvValue portValueDst;
    for (std::vector<struct PortRange>::const_iterator iter = m_dstPortRange.begin (); iter != m_dstPortRange.end (); ++iter)
      {
        portValueDst.Add ((*iter).PortLow, (*iter).PortHigh);
      }
  
    ClassificationRuleVectorTlvValue ClassVectVal;
    ClassVectVal.Add (Tlv (ClassificationRuleVectorTlvValue::Priority, 1, U8TlvValue (m_priority)));
    ClassVectVal.Add (Tlv (ClassificationRuleVectorTlvValue::Protocol, protoVal.GetSerializedSize (), protoVal));
    ClassVectVal.Add (Tlv (ClassificationRuleVectorTlvValue::IP_src, ipv4AddrValSrc.GetSerializedSize (), ipv4AddrValSrc));
    ClassVectVal.Add (Tlv (ClassificationRuleVectorTlvValue::IP_dst, ipv4AddrValDst.GetSerializedSize (), ipv4AddrValDst));
    ClassVectVal.Add (Tlv (ClassificationRuleVectorTlvValue::Port_src, portValueSrc.GetSerializedSize (), portValueSrc));
    ClassVectVal.Add (Tlv (ClassificationRuleVectorTlvValue::Port_dst, portValueDst.GetSerializedSize (), portValueDst));
    ClassVectVal.Add (Tlv (ClassificationRuleVectorTlvValue::Index, 2, U16TlvValue (1)));
  
    Tlv tmp_tlv (CsParamVectorTlvValue::Packet_Classification_Rule, ClassVectVal.GetSerializedSize (), ClassVectVal);
  
    return tmp_tlv;
  }
  
  } // namespace ns3
  