merge with nsnam.org
authorPavel Boyko <boyko@iitp.ru>
Fri, 29 May 2009 10:15:19 +0400
changeset 5028 01f02baebba9
parent 5025 fc820a3a1975 (diff)
parent 4475 a232dcbbe7a8 (current diff)
child 5029 141a8e5fd047
merge with nsnam.org
bindings/python/ns3_module_common.py
examples/wscript
src/applications/udp-echo/udp-echo-server.cc
src/devices/wifi/dca-txop.h
src/devices/wifi/dcf-manager.cc
src/devices/wifi/dcf-manager.h
src/devices/wifi/wscript
src/devices/wifi/yans-wifi-phy.cc
src/devices/wifi/yans-wifi-phy.h
src/helper/static-multicast-route-helper.cc
src/helper/static-multicast-route-helper.h
src/helper/wscript
src/internet-stack/arp-ipv4-interface.cc
src/internet-stack/arp-ipv4-interface.h
src/internet-stack/internet-stack.cc
src/internet-stack/internet-stack.h
src/internet-stack/ipv4-l3-protocol.cc
src/internet-stack/ipv4-loopback-interface.cc
src/internet-stack/ipv4-loopback-interface.h
src/internet-stack/ipv4-static-routing.cc
src/internet-stack/ipv4-static-routing.h
src/internet-stack/tcp-socket-impl.cc
src/internet-stack/udp-socket-impl.cc
src/node/wscript
src/wscript
--- a/bindings/python/ns3_module_common.py	Thu May 28 21:41:45 2009 -0700
+++ b/bindings/python/ns3_module_common.py	Fri May 29 10:15:19 2009 +0400
@@ -9,6 +9,16 @@
     module.add_class('Buffer')
     ## buffer.h: ns3::Buffer::Iterator [class]
     module.add_class('Iterator', outer_class=root_module['ns3::Buffer'])
+    ## packet.h: ns3::ByteTagIterator [class]
+    module.add_class('ByteTagIterator')
+    ## packet.h: ns3::ByteTagIterator::Item [class]
+    module.add_class('Item', outer_class=root_module['ns3::ByteTagIterator'])
+    ## byte-tag-list.h: ns3::ByteTagList [class]
+    module.add_class('ByteTagList')
+    ## byte-tag-list.h: ns3::ByteTagList::Iterator [class]
+    module.add_class('Iterator', outer_class=root_module['ns3::ByteTagList'])
+    ## byte-tag-list.h: ns3::ByteTagList::Iterator::Item [struct]
+    module.add_class('Item', outer_class=root_module['ns3::ByteTagList::Iterator'])
     ## data-rate.h: ns3::DataRate [class]
     module.add_class('DataRate')
     ## packet.h: ns3::Packet [class]
@@ -21,20 +31,18 @@
     module.add_enum('', ['PAYLOAD', 'HEADER', 'TRAILER'], outer_class=root_module['ns3::PacketMetadata::Item'])
     ## packet-metadata.h: ns3::PacketMetadata::ItemIterator [class]
     module.add_class('ItemIterator', outer_class=root_module['ns3::PacketMetadata'])
+    ## packet.h: ns3::PacketTagIterator [class]
+    module.add_class('PacketTagIterator')
+    ## packet.h: ns3::PacketTagIterator::Item [class]
+    module.add_class('Item', outer_class=root_module['ns3::PacketTagIterator'])
+    ## packet-tag-list.h: ns3::PacketTagList [class]
+    module.add_class('PacketTagList')
+    ## packet-tag-list.h: ns3::PacketTagList::TagData [struct]
+    module.add_class('TagData', outer_class=root_module['ns3::PacketTagList'])
     ## tag.h: ns3::Tag [class]
     module.add_class('Tag', parent=root_module['ns3::ObjectBase'])
     ## tag-buffer.h: ns3::TagBuffer [class]
     module.add_class('TagBuffer')
-    ## packet.h: ns3::TagIterator [class]
-    module.add_class('TagIterator')
-    ## packet.h: ns3::TagIterator::Item [class]
-    module.add_class('Item', outer_class=root_module['ns3::TagIterator'])
-    ## tag-list.h: ns3::TagList [class]
-    module.add_class('TagList')
-    ## tag-list.h: ns3::TagList::Iterator [class]
-    module.add_class('Iterator', outer_class=root_module['ns3::TagList'])
-    ## tag-list.h: ns3::TagList::Iterator::Item [struct]
-    module.add_class('Item', outer_class=root_module['ns3::TagList::Iterator'])
     ## chunk.h: ns3::Chunk [class]
     module.add_class('Chunk', parent=root_module['ns3::ObjectBase'])
     ## data-rate.h: ns3::DataRateChecker [class]
@@ -107,18 +115,22 @@
 def register_methods(root_module):
     register_Ns3Buffer_methods(root_module, root_module['ns3::Buffer'])
     register_Ns3BufferIterator_methods(root_module, root_module['ns3::Buffer::Iterator'])
+    register_Ns3ByteTagIterator_methods(root_module, root_module['ns3::ByteTagIterator'])
+    register_Ns3ByteTagIteratorItem_methods(root_module, root_module['ns3::ByteTagIterator::Item'])
+    register_Ns3ByteTagList_methods(root_module, root_module['ns3::ByteTagList'])
+    register_Ns3ByteTagListIterator_methods(root_module, root_module['ns3::ByteTagList::Iterator'])
+    register_Ns3ByteTagListIteratorItem_methods(root_module, root_module['ns3::ByteTagList::Iterator::Item'])
     register_Ns3DataRate_methods(root_module, root_module['ns3::DataRate'])
     register_Ns3Packet_methods(root_module, root_module['ns3::Packet'])
     register_Ns3PacketMetadata_methods(root_module, root_module['ns3::PacketMetadata'])
     register_Ns3PacketMetadataItem_methods(root_module, root_module['ns3::PacketMetadata::Item'])
     register_Ns3PacketMetadataItemIterator_methods(root_module, root_module['ns3::PacketMetadata::ItemIterator'])
+    register_Ns3PacketTagIterator_methods(root_module, root_module['ns3::PacketTagIterator'])
+    register_Ns3PacketTagIteratorItem_methods(root_module, root_module['ns3::PacketTagIterator::Item'])
+    register_Ns3PacketTagList_methods(root_module, root_module['ns3::PacketTagList'])
+    register_Ns3PacketTagListTagData_methods(root_module, root_module['ns3::PacketTagList::TagData'])
     register_Ns3Tag_methods(root_module, root_module['ns3::Tag'])
     register_Ns3TagBuffer_methods(root_module, root_module['ns3::TagBuffer'])
-    register_Ns3TagIterator_methods(root_module, root_module['ns3::TagIterator'])
-    register_Ns3TagIteratorItem_methods(root_module, root_module['ns3::TagIterator::Item'])
-    register_Ns3TagList_methods(root_module, root_module['ns3::TagList'])
-    register_Ns3TagListIterator_methods(root_module, root_module['ns3::TagList::Iterator'])
-    register_Ns3TagListIteratorItem_methods(root_module, root_module['ns3::TagList::Iterator::Item'])
     register_Ns3Chunk_methods(root_module, root_module['ns3::Chunk'])
     register_Ns3DataRateChecker_methods(root_module, root_module['ns3::DataRateChecker'])
     register_Ns3DataRateValue_methods(root_module, root_module['ns3::DataRateValue'])
@@ -346,6 +358,113 @@
                    is_const=True)
     return
 
+def register_Ns3ByteTagIterator_methods(root_module, cls):
+    ## packet.h: ns3::ByteTagIterator::ByteTagIterator(ns3::ByteTagIterator const & arg0) [copy constructor]
+    cls.add_constructor([param('ns3::ByteTagIterator const &', 'arg0')])
+    ## packet.h: bool ns3::ByteTagIterator::HasNext() const [member function]
+    cls.add_method('HasNext', 
+                   'bool', 
+                   [], 
+                   is_const=True)
+    ## packet.h: ns3::ByteTagIterator::Item ns3::ByteTagIterator::Next() [member function]
+    cls.add_method('Next', 
+                   'ns3::ByteTagIterator::Item', 
+                   [])
+    return
+
+def register_Ns3ByteTagIteratorItem_methods(root_module, cls):
+    ## packet.h: ns3::ByteTagIterator::Item::Item(ns3::ByteTagIterator::Item const & arg0) [copy constructor]
+    cls.add_constructor([param('ns3::ByteTagIterator::Item const &', 'arg0')])
+    ## packet.h: ns3::TypeId ns3::ByteTagIterator::Item::GetTypeId() const [member function]
+    cls.add_method('GetTypeId', 
+                   'ns3::TypeId', 
+                   [], 
+                   is_const=True)
+    ## packet.h: uint32_t ns3::ByteTagIterator::Item::GetStart() const [member function]
+    cls.add_method('GetStart', 
+                   'uint32_t', 
+                   [], 
+                   is_const=True)
+    ## packet.h: uint32_t ns3::ByteTagIterator::Item::GetEnd() const [member function]
+    cls.add_method('GetEnd', 
+                   'uint32_t', 
+                   [], 
+                   is_const=True)
+    ## packet.h: void ns3::ByteTagIterator::Item::GetTag(ns3::Tag & tag) const [member function]
+    cls.add_method('GetTag', 
+                   'void', 
+                   [param('ns3::Tag &', 'tag')], 
+                   is_const=True)
+    return
+
+def register_Ns3ByteTagList_methods(root_module, cls):
+    ## byte-tag-list.h: ns3::ByteTagList::ByteTagList() [constructor]
+    cls.add_constructor([])
+    ## byte-tag-list.h: ns3::ByteTagList::ByteTagList(ns3::ByteTagList const & o) [copy constructor]
+    cls.add_constructor([param('ns3::ByteTagList const &', 'o')])
+    ## byte-tag-list.h: ns3::TagBuffer ns3::ByteTagList::Add(ns3::TypeId tid, uint32_t bufferSize, int32_t start, int32_t end) [member function]
+    cls.add_method('Add', 
+                   'ns3::TagBuffer', 
+                   [param('ns3::TypeId', 'tid'), param('uint32_t', 'bufferSize'), param('int32_t', 'start'), param('int32_t', 'end')])
+    ## byte-tag-list.h: void ns3::ByteTagList::Add(ns3::ByteTagList const & o) [member function]
+    cls.add_method('Add', 
+                   'void', 
+                   [param('ns3::ByteTagList const &', 'o')])
+    ## byte-tag-list.h: void ns3::ByteTagList::RemoveAll() [member function]
+    cls.add_method('RemoveAll', 
+                   'void', 
+                   [])
+    ## byte-tag-list.h: ns3::ByteTagList::Iterator ns3::ByteTagList::Begin(int32_t offsetStart, int32_t offsetEnd) const [member function]
+    cls.add_method('Begin', 
+                   'ns3::ByteTagList::Iterator', 
+                   [param('int32_t', 'offsetStart'), param('int32_t', 'offsetEnd')], 
+                   is_const=True)
+    ## byte-tag-list.h: void ns3::ByteTagList::AddAtEnd(int32_t adjustment, int32_t appendOffset) [member function]
+    cls.add_method('AddAtEnd', 
+                   'void', 
+                   [param('int32_t', 'adjustment'), param('int32_t', 'appendOffset')])
+    ## byte-tag-list.h: void ns3::ByteTagList::AddAtStart(int32_t adjustment, int32_t prependOffset) [member function]
+    cls.add_method('AddAtStart', 
+                   'void', 
+                   [param('int32_t', 'adjustment'), param('int32_t', 'prependOffset')])
+    return
+
+def register_Ns3ByteTagListIterator_methods(root_module, cls):
+    ## byte-tag-list.h: ns3::ByteTagList::Iterator::Iterator(ns3::ByteTagList::Iterator const & arg0) [copy constructor]
+    cls.add_constructor([param('ns3::ByteTagList::Iterator const &', 'arg0')])
+    ## byte-tag-list.h: bool ns3::ByteTagList::Iterator::HasNext() const [member function]
+    cls.add_method('HasNext', 
+                   'bool', 
+                   [], 
+                   is_const=True)
+    ## byte-tag-list.h: ns3::ByteTagList::Iterator::Item ns3::ByteTagList::Iterator::Next() [member function]
+    cls.add_method('Next', 
+                   'ns3::ByteTagList::Iterator::Item', 
+                   [])
+    ## byte-tag-list.h: uint32_t ns3::ByteTagList::Iterator::GetOffsetStart() const [member function]
+    cls.add_method('GetOffsetStart', 
+                   'uint32_t', 
+                   [], 
+                   is_const=True)
+    return
+
+def register_Ns3ByteTagListIteratorItem_methods(root_module, cls):
+    ## byte-tag-list.h: ns3::ByteTagList::Iterator::Item::tid [variable]
+    cls.add_instance_attribute('tid', 'ns3::TypeId', is_const=False)
+    ## byte-tag-list.h: ns3::ByteTagList::Iterator::Item::size [variable]
+    cls.add_instance_attribute('size', 'uint32_t', is_const=False)
+    ## byte-tag-list.h: ns3::ByteTagList::Iterator::Item::start [variable]
+    cls.add_instance_attribute('start', 'int32_t', is_const=False)
+    ## byte-tag-list.h: ns3::ByteTagList::Iterator::Item::end [variable]
+    cls.add_instance_attribute('end', 'int32_t', is_const=False)
+    ## byte-tag-list.h: ns3::ByteTagList::Iterator::Item::buf [variable]
+    cls.add_instance_attribute('buf', 'ns3::TagBuffer', is_const=False)
+    ## byte-tag-list.h: ns3::ByteTagList::Iterator::Item::Item(ns3::ByteTagList::Iterator::Item const & arg0) [copy constructor]
+    cls.add_constructor([param('ns3::ByteTagList::Iterator::Item const &', 'arg0')])
+    ## byte-tag-list.h: ns3::ByteTagList::Iterator::Item::Item(ns3::TagBuffer buf) [constructor]
+    cls.add_constructor([param('ns3::TagBuffer', 'buf')])
+    return
+
 def register_Ns3DataRate_methods(root_module, cls):
     cls.add_output_stream_operator()
     cls.add_binary_comparison_operator('!=')
@@ -388,19 +507,24 @@
     cls.add_method('AddAtEnd', 
                    'void', 
                    [param('ns3::Ptr< ns3::Packet const >', 'packet')])
+    ## packet.h: void ns3::Packet::AddByteTag(ns3::Tag const & tag) const [member function]
+    cls.add_method('AddByteTag', 
+                   'void', 
+                   [param('ns3::Tag const &', 'tag')], 
+                   is_const=True)
     ## packet.h: void ns3::Packet::AddHeader(ns3::Header const & header) [member function]
     cls.add_method('AddHeader', 
                    'void', 
                    [param('ns3::Header const &', 'header')])
+    ## packet.h: void ns3::Packet::AddPacketTag(ns3::Tag const & tag) const [member function]
+    cls.add_method('AddPacketTag', 
+                   'void', 
+                   [param('ns3::Tag const &', 'tag')], 
+                   is_const=True)
     ## packet.h: void ns3::Packet::AddPaddingAtEnd(uint32_t size) [member function]
     cls.add_method('AddPaddingAtEnd', 
                    'void', 
                    [param('uint32_t', 'size')])
-    ## packet.h: void ns3::Packet::AddTag(ns3::Tag const & tag) const [member function]
-    cls.add_method('AddTag', 
-                   'void', 
-                   [param('ns3::Tag const &', 'tag')], 
-                   is_const=True)
     ## packet.h: void ns3::Packet::AddTrailer(ns3::Trailer const & trailer) [member function]
     cls.add_method('AddTrailer', 
                    'void', 
@@ -439,21 +563,26 @@
                    'void', 
                    [], 
                    is_static=True)
-    ## packet.h: bool ns3::Packet::FindFirstMatchingTag(ns3::Tag & tag) const [member function]
-    cls.add_method('FindFirstMatchingTag', 
+    ## packet.h: bool ns3::Packet::FindFirstMatchingByteTag(ns3::Tag & tag) const [member function]
+    cls.add_method('FindFirstMatchingByteTag', 
                    'bool', 
                    [param('ns3::Tag &', 'tag')], 
                    is_const=True)
+    ## packet.h: ns3::ByteTagIterator ns3::Packet::GetByteTagIterator() const [member function]
+    cls.add_method('GetByteTagIterator', 
+                   'ns3::ByteTagIterator', 
+                   [], 
+                   is_const=True)
+    ## packet.h: ns3::PacketTagIterator ns3::Packet::GetPacketTagIterator() const [member function]
+    cls.add_method('GetPacketTagIterator', 
+                   'ns3::PacketTagIterator', 
+                   [], 
+                   is_const=True)
     ## packet.h: uint32_t ns3::Packet::GetSize() const [member function]
     cls.add_method('GetSize', 
                    'uint32_t', 
                    [], 
                    is_const=True)
-    ## packet.h: ns3::TagIterator ns3::Packet::GetTagIterator() const [member function]
-    cls.add_method('GetTagIterator', 
-                   'ns3::TagIterator', 
-                   [], 
-                   is_const=True)
     ## packet.h: uint32_t ns3::Packet::GetUid() const [member function]
     cls.add_method('GetUid', 
                    'uint32_t', 
@@ -469,6 +598,11 @@
                    'uint32_t', 
                    [param('ns3::Header &', 'header')], 
                    is_const=True)
+    ## packet.h: bool ns3::Packet::PeekPacketTag(ns3::Tag & tag) const [member function]
+    cls.add_method('PeekPacketTag', 
+                   'bool', 
+                   [param('ns3::Tag &', 'tag')], 
+                   is_const=True)
     ## packet.h: uint32_t ns3::Packet::PeekTrailer(ns3::Trailer & trailer) [member function]
     cls.add_method('PeekTrailer', 
                    'uint32_t', 
@@ -478,13 +612,22 @@
                    'void', 
                    [param('std::ostream &', 'os')], 
                    is_const=True)
-    ## packet.h: void ns3::Packet::PrintTags(std::ostream & os) const [member function]
-    cls.add_method('PrintTags', 
+    ## packet.h: void ns3::Packet::PrintByteTags(std::ostream & os) const [member function]
+    cls.add_method('PrintByteTags', 
                    'void', 
                    [param('std::ostream &', 'os')], 
                    is_const=True)
-    ## packet.h: void ns3::Packet::RemoveAllTags() [member function]
-    cls.add_method('RemoveAllTags', 
+    ## packet.h: void ns3::Packet::PrintPacketTags(std::ostream & os) const [member function]
+    cls.add_method('PrintPacketTags', 
+                   'void', 
+                   [param('std::ostream &', 'os')], 
+                   is_const=True)
+    ## packet.h: void ns3::Packet::RemoveAllByteTags() [member function]
+    cls.add_method('RemoveAllByteTags', 
+                   'void', 
+                   [])
+    ## packet.h: void ns3::Packet::RemoveAllPacketTags() [member function]
+    cls.add_method('RemoveAllPacketTags', 
                    'void', 
                    [])
     ## packet.h: void ns3::Packet::RemoveAtEnd(uint32_t size) [member function]
@@ -499,6 +642,10 @@
     cls.add_method('RemoveHeader', 
                    'uint32_t', 
                    [param('ns3::Header &', 'header')])
+    ## packet.h: bool ns3::Packet::RemovePacketTag(ns3::Tag & tag) [member function]
+    cls.add_method('RemovePacketTag', 
+                   'bool', 
+                   [param('ns3::Tag &', 'tag')])
     ## packet.h: uint32_t ns3::Packet::RemoveTrailer(ns3::Trailer & trailer) [member function]
     cls.add_method('RemoveTrailer', 
                    'uint32_t', 
@@ -623,6 +770,80 @@
                    [])
     return
 
+def register_Ns3PacketTagIterator_methods(root_module, cls):
+    ## packet.h: ns3::PacketTagIterator::PacketTagIterator(ns3::PacketTagIterator const & arg0) [copy constructor]
+    cls.add_constructor([param('ns3::PacketTagIterator const &', 'arg0')])
+    ## packet.h: bool ns3::PacketTagIterator::HasNext() const [member function]
+    cls.add_method('HasNext', 
+                   'bool', 
+                   [], 
+                   is_const=True)
+    ## packet.h: ns3::PacketTagIterator::Item ns3::PacketTagIterator::Next() [member function]
+    cls.add_method('Next', 
+                   'ns3::PacketTagIterator::Item', 
+                   [])
+    return
+
+def register_Ns3PacketTagIteratorItem_methods(root_module, cls):
+    ## packet.h: ns3::PacketTagIterator::Item::Item(ns3::PacketTagIterator::Item const & arg0) [copy constructor]
+    cls.add_constructor([param('ns3::PacketTagIterator::Item const &', 'arg0')])
+    ## packet.h: ns3::TypeId ns3::PacketTagIterator::Item::GetTypeId() const [member function]
+    cls.add_method('GetTypeId', 
+                   'ns3::TypeId', 
+                   [], 
+                   is_const=True)
+    ## packet.h: void ns3::PacketTagIterator::Item::GetTag(ns3::Tag & tag) const [member function]
+    cls.add_method('GetTag', 
+                   'void', 
+                   [param('ns3::Tag &', 'tag')], 
+                   is_const=True)
+    return
+
+def register_Ns3PacketTagList_methods(root_module, cls):
+    ## packet-tag-list.h: ns3::PacketTagList::PacketTagList() [constructor]
+    cls.add_constructor([])
+    ## packet-tag-list.h: ns3::PacketTagList::PacketTagList(ns3::PacketTagList const & o) [copy constructor]
+    cls.add_constructor([param('ns3::PacketTagList const &', 'o')])
+    ## packet-tag-list.h: void ns3::PacketTagList::Add(ns3::Tag const & tag) const [member function]
+    cls.add_method('Add', 
+                   'void', 
+                   [param('ns3::Tag const &', 'tag')], 
+                   is_const=True)
+    ## packet-tag-list.h: bool ns3::PacketTagList::Remove(ns3::Tag & tag) [member function]
+    cls.add_method('Remove', 
+                   'bool', 
+                   [param('ns3::Tag &', 'tag')])
+    ## packet-tag-list.h: bool ns3::PacketTagList::Peek(ns3::Tag & tag) const [member function]
+    cls.add_method('Peek', 
+                   'bool', 
+                   [param('ns3::Tag &', 'tag')], 
+                   is_const=True)
+    ## packet-tag-list.h: void ns3::PacketTagList::RemoveAll() [member function]
+    cls.add_method('RemoveAll', 
+                   'void', 
+                   [])
+    ## packet-tag-list.h: ns3::PacketTagList::TagData const * ns3::PacketTagList::Head() const [member function]
+    cls.add_method('Head', 
+                   'ns3::PacketTagList::TagData const *', 
+                   [], 
+                   is_const=True)
+    return
+
+def register_Ns3PacketTagListTagData_methods(root_module, cls):
+    ## packet-tag-list.h: ns3::PacketTagList::TagData::data [variable]
+    cls.add_instance_attribute('data', 'uint8_t [ 20 ]', is_const=False)
+    ## packet-tag-list.h: ns3::PacketTagList::TagData::next [variable]
+    cls.add_instance_attribute('next', 'ns3::PacketTagList::TagData *', is_const=False)
+    ## packet-tag-list.h: ns3::PacketTagList::TagData::tid [variable]
+    cls.add_instance_attribute('tid', 'ns3::TypeId', is_const=False)
+    ## packet-tag-list.h: ns3::PacketTagList::TagData::count [variable]
+    cls.add_instance_attribute('count', 'uint32_t', is_const=False)
+    ## packet-tag-list.h: ns3::PacketTagList::TagData::TagData(ns3::PacketTagList::TagData const & arg0) [copy constructor]
+    cls.add_constructor([param('ns3::PacketTagList::TagData const &', 'arg0')])
+    ## packet-tag-list.h: ns3::PacketTagList::TagData::TagData() [constructor]
+    cls.add_constructor([])
+    return
+
 def register_Ns3Tag_methods(root_module, cls):
     ## tag.h: ns3::Tag::Tag(ns3::Tag const & arg0) [copy constructor]
     cls.add_constructor([param('ns3::Tag const &', 'arg0')])
@@ -718,113 +939,6 @@
                    [param('uint8_t *', 'buffer'), param('uint32_t', 'size')])
     return
 
-def register_Ns3TagIterator_methods(root_module, cls):
-    ## packet.h: ns3::TagIterator::TagIterator(ns3::TagIterator const & arg0) [copy constructor]
-    cls.add_constructor([param('ns3::TagIterator const &', 'arg0')])
-    ## packet.h: bool ns3::TagIterator::HasNext() const [member function]
-    cls.add_method('HasNext', 
-                   'bool', 
-                   [], 
-                   is_const=True)
-    ## packet.h: ns3::TagIterator::Item ns3::TagIterator::Next() [member function]
-    cls.add_method('Next', 
-                   'ns3::TagIterator::Item', 
-                   [])
-    return
-
-def register_Ns3TagIteratorItem_methods(root_module, cls):
-    ## packet.h: ns3::TagIterator::Item::Item(ns3::TagIterator::Item const & arg0) [copy constructor]
-    cls.add_constructor([param('ns3::TagIterator::Item const &', 'arg0')])
-    ## packet.h: ns3::TypeId ns3::TagIterator::Item::GetTypeId() const [member function]
-    cls.add_method('GetTypeId', 
-                   'ns3::TypeId', 
-                   [], 
-                   is_const=True)
-    ## packet.h: uint32_t ns3::TagIterator::Item::GetStart() const [member function]
-    cls.add_method('GetStart', 
-                   'uint32_t', 
-                   [], 
-                   is_const=True)
-    ## packet.h: uint32_t ns3::TagIterator::Item::GetEnd() const [member function]
-    cls.add_method('GetEnd', 
-                   'uint32_t', 
-                   [], 
-                   is_const=True)
-    ## packet.h: void ns3::TagIterator::Item::GetTag(ns3::Tag & tag) const [member function]
-    cls.add_method('GetTag', 
-                   'void', 
-                   [param('ns3::Tag &', 'tag')], 
-                   is_const=True)
-    return
-
-def register_Ns3TagList_methods(root_module, cls):
-    ## tag-list.h: ns3::TagList::TagList() [constructor]
-    cls.add_constructor([])
-    ## tag-list.h: ns3::TagList::TagList(ns3::TagList const & o) [copy constructor]
-    cls.add_constructor([param('ns3::TagList const &', 'o')])
-    ## tag-list.h: ns3::TagBuffer ns3::TagList::Add(ns3::TypeId tid, uint32_t bufferSize, int32_t start, int32_t end) [member function]
-    cls.add_method('Add', 
-                   'ns3::TagBuffer', 
-                   [param('ns3::TypeId', 'tid'), param('uint32_t', 'bufferSize'), param('int32_t', 'start'), param('int32_t', 'end')])
-    ## tag-list.h: void ns3::TagList::Add(ns3::TagList const & o) [member function]
-    cls.add_method('Add', 
-                   'void', 
-                   [param('ns3::TagList const &', 'o')])
-    ## tag-list.h: void ns3::TagList::RemoveAll() [member function]
-    cls.add_method('RemoveAll', 
-                   'void', 
-                   [])
-    ## tag-list.h: ns3::TagList::Iterator ns3::TagList::Begin(int32_t offsetStart, int32_t offsetEnd) const [member function]
-    cls.add_method('Begin', 
-                   'ns3::TagList::Iterator', 
-                   [param('int32_t', 'offsetStart'), param('int32_t', 'offsetEnd')], 
-                   is_const=True)
-    ## tag-list.h: void ns3::TagList::AddAtEnd(int32_t adjustment, int32_t appendOffset) [member function]
-    cls.add_method('AddAtEnd', 
-                   'void', 
-                   [param('int32_t', 'adjustment'), param('int32_t', 'appendOffset')])
-    ## tag-list.h: void ns3::TagList::AddAtStart(int32_t adjustment, int32_t prependOffset) [member function]
-    cls.add_method('AddAtStart', 
-                   'void', 
-                   [param('int32_t', 'adjustment'), param('int32_t', 'prependOffset')])
-    return
-
-def register_Ns3TagListIterator_methods(root_module, cls):
-    ## tag-list.h: ns3::TagList::Iterator::Iterator(ns3::TagList::Iterator const & arg0) [copy constructor]
-    cls.add_constructor([param('ns3::TagList::Iterator const &', 'arg0')])
-    ## tag-list.h: bool ns3::TagList::Iterator::HasNext() const [member function]
-    cls.add_method('HasNext', 
-                   'bool', 
-                   [], 
-                   is_const=True)
-    ## tag-list.h: ns3::TagList::Iterator::Item ns3::TagList::Iterator::Next() [member function]
-    cls.add_method('Next', 
-                   'ns3::TagList::Iterator::Item', 
-                   [])
-    ## tag-list.h: uint32_t ns3::TagList::Iterator::GetOffsetStart() const [member function]
-    cls.add_method('GetOffsetStart', 
-                   'uint32_t', 
-                   [], 
-                   is_const=True)
-    return
-
-def register_Ns3TagListIteratorItem_methods(root_module, cls):
-    ## tag-list.h: ns3::TagList::Iterator::Item::tid [variable]
-    cls.add_instance_attribute('tid', 'ns3::TypeId', is_const=False)
-    ## tag-list.h: ns3::TagList::Iterator::Item::size [variable]
-    cls.add_instance_attribute('size', 'uint32_t', is_const=False)
-    ## tag-list.h: ns3::TagList::Iterator::Item::start [variable]
-    cls.add_instance_attribute('start', 'int32_t', is_const=False)
-    ## tag-list.h: ns3::TagList::Iterator::Item::end [variable]
-    cls.add_instance_attribute('end', 'int32_t', is_const=False)
-    ## tag-list.h: ns3::TagList::Iterator::Item::buf [variable]
-    cls.add_instance_attribute('buf', 'ns3::TagBuffer', is_const=False)
-    ## tag-list.h: ns3::TagList::Iterator::Item::Item(ns3::TagList::Iterator::Item const & arg0) [copy constructor]
-    cls.add_constructor([param('ns3::TagList::Iterator::Item const &', 'arg0')])
-    ## tag-list.h: ns3::TagList::Iterator::Item::Item(ns3::TagBuffer buf) [constructor]
-    cls.add_constructor([param('ns3::TagBuffer', 'buf')])
-    return
-
 def register_Ns3Chunk_methods(root_module, cls):
     ## chunk.h: ns3::Chunk::Chunk(ns3::Chunk const & arg0) [copy constructor]
     cls.add_constructor([param('ns3::Chunk const &', 'arg0')])
--- a/doc/doxygen.conf	Thu May 28 21:41:45 2009 -0700
+++ b/doc/doxygen.conf	Fri May 29 10:15:19 2009 +0400
@@ -300,7 +300,7 @@
 # If set to NO (the default) these classes will be included in the various 
 # overviews. This option has no effect if EXTRACT_ALL is enabled.
 
-HIDE_UNDOC_CLASSES     = YES
+HIDE_UNDOC_CLASSES     = NO
 
 # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
 # friend (class|struct|union) declarations. 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/mesh.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,206 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#include "ns3/core-module.h"
+#include "ns3/simulator-module.h"
+#include "ns3/node-module.h"
+#include "ns3/helper-module.h"
+#include "ns3/global-routing-module.h"
+#include "ns3/wifi-module.h"
+#include "ns3/mesh-module.h"
+#include "ns3/mobility-module.h"
+#include "ns3/dot11s-helper.h"
+
+#include <iostream>
+#include <sstream>
+#include <fstream>
+
+using namespace ns3;
+using namespace dot11s;
+
+NS_LOG_COMPONENT_DEFINE ("TestMeshScript");
+class MeshTest
+{
+  public:
+    /// Init test
+    MeshTest ();
+    /// Configure test from command line arguments
+    void Configure (int argc, char ** argv);
+    /// Run test
+    int Run ();
+  private:
+    int       xSize;
+    int       ySize;
+    double    step;
+    double    randomStart;
+    double    totalTime;
+    double    packetInterval;
+    uint16_t  packetSize;
+    uint32_t  nIfaces;
+    bool      chan;
+    bool      pcap;
+    uint64_t  seed;
+    /// List of network nodes
+    NodeContainer nodes;
+    /// List of all mesh point devices
+    NetDeviceContainer meshDevices;
+    //Addresses of interfaces:
+    Ipv4InterfaceContainer interfaces;
+    //InternetStackHelper stack;
+    //Ipv4AddressHelper address;
+  private:
+    /// Create nodes and setup theis mobility
+    void CreateNodes ();
+    /// Install internet stack on nodes
+    void InstallInternetStack ();
+    /// Install applications
+    void InstallApplication ();
+    /// Print mesh devices diagnostics
+    void Report ();  
+};
+MeshTest::MeshTest () :
+  xSize (3),
+  ySize (3),
+  step (100.0),
+  randomStart (0.1),
+  totalTime (100.0),
+  packetInterval (0.1),
+  packetSize (1024),
+  nIfaces (1),
+  chan (true),
+  pcap (false),
+  seed (1)
+{
+}
+void
+MeshTest::Configure (int argc, char *argv[])
+{
+  CommandLine cmd;
+  cmd.AddValue ("x-size", "Number of nodes in a row grid. [6]", xSize);
+  cmd.AddValue ("y-size", "Number of rows in a grid. [6]", ySize);
+  cmd.AddValue ("step",   "Size of edge in our grid, meters. [100 m]", step);
+  cmd.AddValue ("start",  "Maximum random start delay, seconds. [0.1 s]", randomStart);
+  cmd.AddValue ("time",  "Simulation time, seconds [100 s]", totalTime);
+  cmd.AddValue ("packet-interval",  "Interval between packets, seconds [0.001 s]", packetInterval);
+  cmd.AddValue ("packet-size",  "Size of packets", packetSize);
+  cmd.AddValue ("interfaces", "Number of radio interfaces used by each mesh point. [1]", nIfaces);
+  cmd.AddValue ("channels",   "Use different frequency channels for different interfaces. [0]", chan);
+  cmd.AddValue ("pcap",   "Enable PCAP traces on interfaces. [0]", pcap);
+  cmd.AddValue ("seed",   "Seed value", seed);
+  
+  cmd.Parse (argc, argv);
+  NS_LOG_DEBUG ("Grid:" << xSize << "*" << ySize);
+  NS_LOG_DEBUG ("Simulation time: " << totalTime << " s");
+  SeedManager::SetSeed(seed);
+}
+void
+MeshTest::CreateNodes ()
+{ 
+  nodes.Create (ySize*xSize);
+  // Setting channel
+  YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default ();
+  YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
+  wifiPhy.SetChannel (wifiChannel.Create ());
+  // Install mesh point devices & protocols
+  MeshWifiHelper mesh;
+  mesh.SetSpreadInterfaceChannels (chan);
+  std::vector<uint32_t> roots;
+  //roots.push_back(xSize-1);
+  //roots.push_back(xSize*ySize-xSize);
+  meshDevices = mesh.Install (wifiPhy, nodes, roots, nIfaces);
+  // Setup mobility
+  MobilityHelper mobility;
+  mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
+                                 "MinX", DoubleValue (0.0),
+                                 "MinY", DoubleValue (0.0),
+                                 "DeltaX", DoubleValue (step),
+                                 "DeltaY", DoubleValue (step),
+                                 "GridWidth", UintegerValue (xSize),
+                                 "LayoutType", StringValue ("RowFirst"));
+  mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+  mobility.Install (nodes);
+  if (pcap)
+    wifiPhy.EnablePcapAll (std::string ("mp-"));
+}
+void
+MeshTest::InstallInternetStack ()
+{
+  InternetStackHelper stack;
+  stack.Install (nodes);
+  Ipv4AddressHelper address;
+  address.SetBase ("10.1.1.0", "255.255.255.0");
+  interfaces = address.Assign (meshDevices);
+}
+void
+MeshTest::InstallApplication ()
+{
+  UdpEchoServerHelper echoServer (9);
+  ApplicationContainer serverApps = echoServer.Install (nodes.Get (0));
+  serverApps.Start (Seconds (0.0));
+  serverApps.Stop (Seconds (totalTime));
+  UdpEchoClientHelper echoClient (interfaces.GetAddress (0), 9);
+  echoClient.SetAttribute ("MaxPackets", UintegerValue ((uint32_t)(totalTime*(1/packetInterval))));
+  echoClient.SetAttribute ("Interval", TimeValue (Seconds (packetInterval)));
+  echoClient.SetAttribute ("PacketSize", UintegerValue (packetSize));
+  ApplicationContainer clientApps = echoClient.Install (nodes.Get (xSize*ySize-1));
+  clientApps.Start (Seconds (0.0));
+  clientApps.Stop (Seconds (totalTime));
+}
+int
+MeshTest::Run ()
+{
+  CreateNodes ();
+  InstallInternetStack ();
+  InstallApplication ();
+  Simulator::Schedule (Seconds(totalTime), & MeshTest::Report, this);
+  Simulator::Stop (Seconds (totalTime));
+  Simulator::Run ();
+  Simulator::Destroy ();
+  return 0;
+}
+void
+MeshTest::Report ()
+{
+  NS_LOG_UNCOND("Report is here:");
+  unsigned n (0);
+  for (NetDeviceContainer::Iterator i = meshDevices.Begin (); i != meshDevices.End (); ++i, ++n)
+  {
+    std::ostringstream os;
+    os << "mp-report-" << n << ".xml";
+    std::cerr << "Printing mesh point device #" << n << " diagnostics to " << os.str () << "\n";
+    std::ofstream of;
+    of.open (os.str().c_str());
+    if (! of.is_open ())
+    {
+      std::cerr << "Error: Can't open file " << os.str() << "\n";
+      return;
+    }
+    MeshWifiHelper::Report (*i, of);
+    of.close ();
+  }
+}
+int
+main (int argc, char *argv[])
+{
+  MeshTest t; 
+  t.Configure (argc, argv);
+  return t.Run();
+}
--- a/examples/stats/wifi-example-apps.cc	Thu May 28 21:41:45 2009 -0700
+++ b/examples/stats/wifi-example-apps.cc	Fri May 29 10:15:19 2009 +0400
@@ -131,7 +131,7 @@
 
   TimestampTag timestamp;
   timestamp.SetTimestamp(Simulator::Now());
-  packet->AddTag(timestamp);
+  packet->AddByteTag (timestamp);
 
   // Could connect the socket since the address never changes; using SendTo
   // here simply because all of the standard apps do not.
@@ -250,7 +250,7 @@
     }
 
     TimestampTag timestamp;
-    packet->FindFirstMatchingTag(timestamp);
+    packet->FindFirstMatchingByteTag(timestamp);
     Time tx = timestamp.GetTimestamp();
 
     if (m_delay != 0) {
--- a/examples/wscript	Thu May 28 21:41:45 2009 -0700
+++ b/examples/wscript	Fri May 29 10:15:19 2009 +0400
@@ -124,6 +124,10 @@
                                  ['core', 'simulator', 'mobility', 'wifi'])
     obj.source = 'wifi-ap.cc'
 
+    obj = bld.create_ns3_program('mesh',
+                                 ['core', 'simulator', 'mobility', 'wifi'])
+    obj.source = 'mesh.cc'
+
     bld.add_subdirs('stats')
 
     obj = bld.create_ns3_program('wifi-wired-bridging',
--- a/samples/main-packet-tag.cc	Thu May 28 21:41:45 2009 -0700
+++ b/samples/main-packet-tag.cc	Fri May 29 10:15:19 2009 +0400
@@ -101,19 +101,19 @@
 
   // store the tag in a packet.
   Ptr<Packet> p = Create<Packet> (100);
-  p->AddTag (tag);
+  p->AddPacketTag (tag);
 
   // create a copy of the packet
   Ptr<Packet> aCopy = p->Copy ();
 
   // read the tag from the packet copy
   MyTag tagCopy;
-  p->FindFirstMatchingTag (tagCopy);
+  p->PeekPacketTag (tagCopy);
 
   // the copy and the original are the same !
   NS_ASSERT (tagCopy.GetSimpleValue () == tag.GetSimpleValue ());
 
-  aCopy->PrintTags (std::cout);
+  aCopy->PrintPacketTags (std::cout);
   std::cout << std::endl;
 
   return 0;
--- a/src/applications/udp-echo/udp-echo-client.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/applications/udp-echo/udp-echo-client.cc	Fri May 29 10:15:19 2009 +0400
@@ -90,6 +90,7 @@
 UdpEchoClient::DoDispose (void)
 {
   NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_UNCOND("TOTAL SENT:"<<m_sent);
   Application::DoDispose ();
 }
 
--- a/src/applications/udp-echo/udp-echo-server.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/applications/udp-echo/udp-echo-server.cc	Fri May 29 10:15:19 2009 +0400
@@ -52,11 +52,13 @@
 UdpEchoServer::UdpEchoServer ()
 {
   NS_LOG_FUNCTION_NOARGS ();
+  m_received = 0;
 }
 
 UdpEchoServer::~UdpEchoServer()
 {
   NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_UNCOND("Total received:"<<m_received);
   m_socket = 0;
 }
 
@@ -118,10 +120,11 @@
       if (InetSocketAddress::IsMatchingType (from))
         {
           InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
+          m_received ++;
           NS_LOG_INFO ("Received " << packet->GetSize() << " bytes from " << 
             address.GetIpv4());
 
-          packet->RemoveAllTags ();
+          packet->RemoveAllPacketTags ();
 
           NS_LOG_LOGIC ("Echoing packet");
           socket->SendTo (packet, 0, from);
--- a/src/applications/udp-echo/udp-echo-server.h	Thu May 28 21:41:45 2009 -0700
+++ b/src/applications/udp-echo/udp-echo-server.h	Fri May 29 10:15:19 2009 +0400
@@ -60,6 +60,7 @@
   uint16_t m_port;
   Ptr<Socket> m_socket;
   Address m_local;
+  uint32_t m_received;
 };
 
 } // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/byte-tag-list.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,421 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * 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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "byte-tag-list.h"
+#include "ns3/log.h"
+#include <vector>
+#include <string.h>
+
+NS_LOG_COMPONENT_DEFINE ("ByteTagList");
+
+#define USE_FREE_LIST 1
+#define FREE_LIST_SIZE 1000
+#define OFFSET_MAX (2147483647)
+
+namespace ns3 {
+
+struct ByteTagListData {
+  uint32_t size;
+  uint32_t count;
+  uint32_t dirty;
+  uint8_t data[4];
+};
+
+#ifdef USE_FREE_LIST
+static class ByteTagListDataFreeList : public std::vector<struct ByteTagListData *>
+{
+public:
+  ~ByteTagListDataFreeList ();
+} g_freeList;
+static uint32_t g_maxSize = 0;
+
+ByteTagListDataFreeList::~ByteTagListDataFreeList ()
+{
+  for (ByteTagListDataFreeList::iterator i = begin ();
+       i != end (); i++)
+    {
+      uint8_t *buffer = (uint8_t *)(*i);
+      delete [] buffer;
+    }
+}
+#endif /* USE_FREE_LIST */
+
+ByteTagList::Iterator::Item::Item (TagBuffer buf_)
+    : buf (buf_)
+{}
+
+bool 
+ByteTagList::Iterator::HasNext (void) const
+{
+  return m_current < m_end;
+}
+struct ByteTagList::Iterator::Item 
+ByteTagList::Iterator::Next (void)
+{
+  NS_ASSERT (HasNext ());
+  struct Item item = Item (TagBuffer (m_current+16, m_end));
+  item.tid.SetUid (m_nextTid);
+  item.size = m_nextSize;
+  item.start = std::max (m_nextStart, m_offsetStart);
+  item.end = std::min (m_nextEnd, m_offsetEnd);
+  m_current += 4 + 4 + 4 + 4 + item.size;
+  item.buf.TrimAtEnd (m_end - m_current);
+  PrepareForNext ();
+  return item;
+}
+void
+ByteTagList::Iterator::PrepareForNext (void)
+{
+  while (m_current < m_end)
+    {
+      TagBuffer buf = TagBuffer (m_current, m_end);
+      m_nextTid = buf.ReadU32 ();
+      m_nextSize = buf.ReadU32 ();
+      m_nextStart = buf.ReadU32 ();
+      m_nextEnd = buf.ReadU32 ();
+      if (m_nextStart >= m_offsetEnd || m_nextEnd <= m_offsetStart)
+	{
+	  m_current += 4 + 4 + 4 + 4 + m_nextSize;
+	}
+      else
+	{
+	  break;
+	}
+    }
+}
+ByteTagList::Iterator::Iterator (uint8_t *start, uint8_t *end, int32_t offsetStart, int32_t offsetEnd)
+  : m_current (start),
+    m_end (end),
+    m_offsetStart (offsetStart),
+    m_offsetEnd (offsetEnd)
+{
+  PrepareForNext ();
+}
+
+uint32_t 
+ByteTagList::Iterator::GetOffsetStart (void) const
+{
+  return m_offsetStart;
+}
+
+
+ByteTagList::ByteTagList ()
+  : m_used (0),
+    m_data (0)
+{
+  NS_LOG_FUNCTION (this);
+}
+ByteTagList::ByteTagList (const ByteTagList &o)
+  : m_used (o.m_used),
+    m_data (o.m_data)
+{
+  NS_LOG_FUNCTION (this << &o);
+  if (m_data != 0)
+    {
+      m_data->count++;
+    }
+}
+ByteTagList &
+ByteTagList::operator = (const ByteTagList &o)
+{
+  NS_LOG_FUNCTION (this << &o);
+  if (this == &o)
+    {
+      return *this;
+    }
+
+  Deallocate (m_data);
+  m_data = o.m_data;
+  m_used = o.m_used;
+  if (m_data != 0)
+    {
+      m_data->count++;
+    }
+  return *this;
+}
+ByteTagList::~ByteTagList ()
+{
+  NS_LOG_FUNCTION (this);
+  Deallocate (m_data);
+  m_data = 0;
+  m_used = 0;
+}
+
+TagBuffer
+ByteTagList::Add (TypeId tid, uint32_t bufferSize, int32_t start, int32_t end)
+{
+  NS_LOG_FUNCTION (this << tid << bufferSize << start << end);
+  uint32_t spaceNeeded = m_used + bufferSize + 4 + 4 + 4 + 4;
+  NS_ASSERT (m_used <= spaceNeeded);
+  if (m_data == 0)
+    {
+      m_data = Allocate (spaceNeeded);
+      m_used = 0;
+    } 
+  else if (m_data->size < spaceNeeded ||
+	   (m_data->count != 1 && m_data->dirty != m_used))
+    {
+      struct ByteTagListData *newData = Allocate (spaceNeeded);
+      memcpy (&newData->data, &m_data->data, m_used);
+      Deallocate (m_data);
+      m_data = newData;
+    }
+  TagBuffer tag = TagBuffer (&m_data->data[m_used], 
+			     &m_data->data[spaceNeeded]);
+  tag.WriteU32 (tid.GetUid ());
+  tag.WriteU32 (bufferSize);
+  tag.WriteU32 (start);
+  tag.WriteU32 (end);
+  m_used = spaceNeeded;
+  m_data->dirty = m_used;
+  return tag;
+}
+
+void 
+ByteTagList::Add (const ByteTagList &o)
+{
+  NS_LOG_FUNCTION (this << &o);
+  ByteTagList::Iterator i = o.BeginAll ();
+  while (i.HasNext ())
+    {
+      ByteTagList::Iterator::Item item = i.Next ();
+      TagBuffer buf = Add (item.tid, item.size, item.start, item.end);
+      buf.CopyFrom (item.buf);
+    }
+}
+
+void 
+ByteTagList::RemoveAll (void)
+{
+  NS_LOG_FUNCTION (this);
+  Deallocate (m_data);
+  m_data = 0;
+  m_used = 0;
+}
+
+ByteTagList::Iterator 
+ByteTagList::BeginAll (void) const
+{
+  NS_LOG_FUNCTION (this);
+  // I am not totally sure but I might need to use 
+  // INT32_MIN instead of zero below.
+  return Begin (0, OFFSET_MAX);
+}
+
+ByteTagList::Iterator 
+ByteTagList::Begin (int32_t offsetStart, int32_t offsetEnd) const
+{
+  NS_LOG_FUNCTION (this << offsetStart << offsetEnd);
+  if (m_data == 0)
+    {
+      return Iterator (0, 0, offsetStart, offsetEnd);
+    }
+  else
+    {
+      return Iterator (m_data->data, &m_data->data[m_used], offsetStart, offsetEnd);
+    }
+}
+
+bool 
+ByteTagList::IsDirtyAtEnd (int32_t appendOffset)
+{
+  NS_LOG_FUNCTION (this << appendOffset);
+  ByteTagList::Iterator i = BeginAll ();
+  while (i.HasNext ())
+    {
+      ByteTagList::Iterator::Item item = i.Next ();
+      if (item.end > appendOffset)
+	{
+	  return true;
+	}
+    }
+  return false;
+}
+
+bool 
+ByteTagList::IsDirtyAtStart (int32_t prependOffset)
+{
+  NS_LOG_FUNCTION (this << prependOffset);
+  ByteTagList::Iterator i = BeginAll ();
+  while (i.HasNext ())
+    {
+      ByteTagList::Iterator::Item item = i.Next ();
+      if (item.start < prependOffset)
+	{
+	  return true;
+	}
+    }
+  return false;
+}
+
+void 
+ByteTagList::AddAtEnd (int32_t adjustment, int32_t appendOffset)
+{
+  NS_LOG_FUNCTION (this << adjustment << appendOffset);
+  if (adjustment == 0 && !IsDirtyAtEnd (appendOffset))
+    {
+      return;
+    }
+  ByteTagList list;
+  ByteTagList::Iterator i = BeginAll ();
+  while (i.HasNext ())
+    {
+      ByteTagList::Iterator::Item item = i.Next ();
+      item.start += adjustment;
+      item.end += adjustment;
+
+      if (item.start >= appendOffset)
+	{
+	  continue;
+	}
+      else if (item.start < appendOffset && item.end > appendOffset)
+	{
+	  item.end = appendOffset;
+	}
+      else
+	{
+	  // nothing to do.
+	}
+      TagBuffer buf = list.Add (item.tid, item.size, item.start, item.end);
+      buf.CopyFrom (item.buf);
+    }
+  *this = list;  
+}
+
+void 
+ByteTagList::AddAtStart (int32_t adjustment, int32_t prependOffset)
+{
+  NS_LOG_FUNCTION (this << adjustment << prependOffset);
+  if (adjustment == 0 && !IsDirtyAtStart (prependOffset))
+    {
+      return;
+    }
+  ByteTagList list;
+  ByteTagList::Iterator i = BeginAll ();
+  while (i.HasNext ())
+    {
+      ByteTagList::Iterator::Item item = i.Next ();
+      item.start += adjustment;
+      item.end += adjustment;
+
+      if (item.end <= prependOffset)
+	{
+	  continue;
+	}
+      else if (item.end > prependOffset && item.start < prependOffset)
+	{
+	  item.start = prependOffset;
+	}
+      else
+	{
+	  // nothing to do.
+	}
+      TagBuffer buf = list.Add (item.tid, item.size, item.start, item.end);
+      buf.CopyFrom (item.buf);
+    }
+  *this = list;
+}
+
+#ifdef USE_FREE_LIST
+
+struct ByteTagListData *
+ByteTagList::Allocate (uint32_t size)
+{
+  NS_LOG_FUNCTION (this << size);
+  while (!g_freeList.empty ())
+    {
+      struct ByteTagListData *data = g_freeList.back ();
+      g_freeList.pop_back ();
+      NS_ASSERT (data != 0);
+      if (data->size >= size)
+	{
+	  data->count = 1;
+	  data->dirty = 0;
+	  return data;
+	}
+      uint8_t *buffer = (uint8_t *)data;
+      delete [] buffer;
+    }
+  uint8_t *buffer = new uint8_t [std::max (size, g_maxSize) + sizeof (struct ByteTagListData) - 4];
+  struct ByteTagListData *data = (struct ByteTagListData *)buffer;
+  data->count = 1;
+  data->size = size;
+  data->dirty = 0;
+  return data;
+}
+
+void 
+ByteTagList::Deallocate (struct ByteTagListData *data)
+{
+  NS_LOG_FUNCTION (this << data);
+  if (data == 0)
+    {
+      return;
+    }
+  g_maxSize = std::max (g_maxSize, data->size);
+  data->count--;
+  if (data->count == 0)
+    {
+      if (g_freeList.size () > FREE_LIST_SIZE ||
+	  data->size < g_maxSize)
+	{
+	  uint8_t *buffer = (uint8_t *)data;
+	  delete [] buffer;
+	}
+      else
+	{
+	  g_freeList.push_back (data);
+	}
+    }
+}
+
+#else /* USE_FREE_LIST */
+
+struct ByteTagListData *
+ByteTagList::Allocate (uint32_t size)
+{
+  NS_LOG_FUNCTION (this << size);
+  uint8_t *buffer = new uint8_t [size + sizeof (struct ByteTagListData) - 4];
+  struct ByteTagListData *data = (struct ByteTagListData *)buffer;
+  data->count = 1;
+  data->size = size;
+  data->dirty = 0;
+  return data;
+}
+
+void 
+ByteTagList::Deallocate (struct ByteTagListData *data)
+{
+  NS_LOG_FUNCTION (this << data);
+  if (data == 0)
+    {
+      return;
+    }
+  data->count--;
+  if (data->count == 0)
+    {
+      uint8_t *buffer = (uint8_t *)data;
+      delete [] buffer;
+    }
+}
+
+#endif /* USE_FREE_LIST */
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/byte-tag-list.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,170 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * 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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef BYTE_TAG_LIST_H
+#define BYTE_TAG_LIST_H
+
+#include <stdint.h>
+#include "ns3/type-id.h"
+#include "tag-buffer.h"
+
+namespace ns3 {
+
+struct ByteTagListData;
+
+/**
+ * \ingroup packet
+ *
+ * \brief keep track of the tags stored in a packet.
+ *
+ * This class is mostly private to the Packet implementation and users
+ * should never have to access it directly.
+ *
+ * \internal
+ * The implementation of this class is a bit tricky so, there are a couple
+ * of things to keep in mind here:
+ *
+ *   - it stores all tags in a single byte buffer: each tag is stored
+ *     as 4 32bit integers (TypeId, tag data size, start, end) followed 
+ *     by the tag data as generated by Tag::Serialize.
+ *
+ *   - the struct ByteTagListData structure which contains the tag byte buffer
+ *     is shared and, thus, reference-counted. This data structure is unshared
+ *     as-needed to emulate COW semantics.
+ *
+ *   - each tag tags a unique set of bytes identified by the pair of offsets 
+ *     (start,end). These offsets are provided by Buffer::GetCurrentStartOffset
+ *     and Buffer::GetCurrentEndOffset which means that they are relative to 
+ *     the start of the 'virtual byte buffer' as explained in the documentation
+ *     for the ns3::Buffer class. Whenever the origin of the offset of the Buffer
+ *     instance associated to this ByteTagList instance changes, the Buffer class
+ *     reports this to its container Packet class as a bool return value
+ *     in Buffer::AddAtStart and Buffer::AddAtEnd. In both cases, when this happens
+ *     the Packet class calls ByteTagList::AddAtEnd and ByteTagList::AddAtStart to update
+ *     the byte offsets of each tag in the ByteTagList.
+ *
+ *   - whenever bytes are removed from the packet byte buffer, the ByteTagList offsets 
+ *     are never updated because we rely on the fact that they will be updated in
+ *     either the next call to Packet::AddHeader or Packet::AddTrailer or when
+ *     the user iterates the tag list with Packet::GetTagIterator and 
+ *     TagIterator::Next.
+ */
+class ByteTagList
+{
+public:
+
+  class Iterator
+  {
+  public:
+    struct Item 
+    {
+      TypeId tid;
+      uint32_t size;
+      int32_t start;
+      int32_t end;
+      TagBuffer buf;
+      Item (TagBuffer buf);
+    private:
+      friend class ByteTagList;
+      friend class ByteTagList::Iterator;
+    };
+    bool HasNext (void) const;
+    struct ByteTagList::Iterator::Item Next (void);
+    uint32_t GetOffsetStart (void) const;
+  private:
+    friend class ByteTagList;
+    Iterator (uint8_t *start, uint8_t *end, int32_t offsetStart, int32_t offsetEnd);
+    void PrepareForNext (void);
+    uint8_t *m_current;
+    uint8_t *m_end;
+    int32_t m_offsetStart;
+    int32_t m_offsetEnd;
+    uint32_t m_nextTid;
+    uint32_t m_nextSize;
+    int32_t m_nextStart;
+    int32_t m_nextEnd;
+  };
+
+  ByteTagList ();
+  ByteTagList (const ByteTagList &o);
+  ByteTagList &operator = (const ByteTagList &o);
+  ~ByteTagList ();
+
+  /**
+   * \param tid the typeid of the tag added
+   * \param bufferSize the size of the tag when its serialization will 
+   *        be completed. Typically, the return value of Tag::GetSerializedSize
+   * \param start offset which uniquely identifies the first byte tagged by this tag.
+   * \param end offset which uniquely identifies the last byte tagged by this tag.
+   * \returns a buffer which can be used to write the tag data.     
+   *
+   * 
+   */
+  TagBuffer Add (TypeId tid, uint32_t bufferSize, int32_t start, int32_t end);
+
+  /**
+   * \param o the other list of tags to aggregate.
+   *
+   * Aggregate the two lists of tags.
+   */
+  void Add (const ByteTagList &o);
+
+  void RemoveAll (void);
+
+  /**
+   * \param offsetStart the offset which uniquely identifies the first data byte 
+   *        present in the byte buffer associated to this ByteTagList.
+   * \param offsetEnd the offset which uniquely identifies the last data byte 
+   *        present in the byte buffer associated to this ByteTagList.
+   * \returns an iterator
+   *
+   * The returned iterator will allow you to loop through the set of tags present
+   * in this list: the boundaries of each tag as reported by their start and
+   * end offsets will be included within the input offsetStart and offsetEnd.
+   */
+  ByteTagList::Iterator Begin (int32_t offsetStart, int32_t offsetEnd) const;
+
+  /**
+   * Adjust the offsets stored internally by the adjustment delta and
+   * make sure that all offsets are smaller than appendOffset which represents
+   * the location where new bytes have been added to the byte buffer.
+   */
+  void AddAtEnd (int32_t adjustment, int32_t appendOffset);
+  /**
+   * Adjust the offsets stored internally by the adjustment delta and
+   * make sure that all offsets are bigger than prependOffset which represents
+   * the location where new bytes have been added to the byte buffer.
+   */
+  void AddAtStart (int32_t adjustment, int32_t prependOffset);
+
+private:
+  bool IsDirtyAtEnd (int32_t appendOffset);
+  bool IsDirtyAtStart (int32_t prependOffset);
+  ByteTagList::Iterator BeginAll (void) const;
+
+  struct ByteTagListData *Allocate (uint32_t size);
+  void Deallocate (struct ByteTagListData *data);
+
+  uint16_t m_used;
+  struct ByteTagListData *m_data;
+};
+
+} // namespace ns3
+
+#endif /* BYTE_TAG_LIST_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-tag-list.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,177 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ *
+ * 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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "packet-tag-list.h"
+#include "tag-buffer.h"
+#include "tag.h"
+#include "ns3/fatal-error.h"
+#include "ns3/log.h"
+#include <string.h>
+
+NS_LOG_COMPONENT_DEFINE ("PacketTagList");
+
+namespace ns3 {
+
+#ifdef USE_FREE_LIST
+
+struct PacketTagList::TagData *PacketTagList::g_free = 0;
+uint32_t PacketTagList::g_nfree = 0;
+
+struct PacketTagList::TagData *
+PacketTagList::AllocData (void) const
+{
+  NS_LOG_FUNCTION (g_nfree);
+  struct PacketTagList::TagData *retval;
+  if (g_free != 0) 
+    {
+      retval = g_free;
+      g_free = g_free->m_next;
+      g_nfree--;
+    } 
+  else 
+    {
+      retval = new struct PacketTagList::TagData ();
+    }
+  return retval;
+}
+
+void
+PacketTagList::FreeData (struct TagData *data) const
+{
+  NS_LOG_FUNCTION (g_nfree << data);
+  if (g_nfree > 1000) 
+    {
+      delete data;
+      return;
+    }
+  g_nfree++;
+  data->next = g_free;
+  data->tid = TypeId ();
+  g_free = data;
+}
+#else
+struct PacketTagList::TagData *
+PacketTagList::AllocData (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  struct PacketTagList::TagData *retval;
+  retval = new struct PacketTagList::TagData ();
+  return retval;
+}
+
+void
+PacketTagList::FreeData (struct TagData *data) const
+{
+  NS_LOG_FUNCTION (data);
+  delete data;
+}
+#endif
+
+bool
+PacketTagList::Remove (Tag &tag)
+{
+  NS_LOG_FUNCTION (this << tag.GetInstanceTypeId ());
+  TypeId tid = tag.GetInstanceTypeId ();
+  bool found = false;
+  for (struct TagData *cur = m_next; cur != 0; cur = cur->next) 
+    {
+      if (cur->tid == tid) 
+        {
+          found = true;
+          tag.Deserialize (TagBuffer (cur->data, cur->data+PACKET_TAG_MAX_SIZE));
+        }
+    }
+  if (!found) 
+    {
+      return false;
+    }
+  struct TagData *start = 0;
+  struct TagData **prevNext = &start;
+  for (struct TagData *cur = m_next; cur != 0; cur = cur->next) 
+    {
+      if (cur->tid == tid) 
+        {
+          /**
+           * XXX
+           * Note: I believe that we could optimize this to
+           * avoid copying each TagData located after the target id
+           * and just link the already-copied list to the next tag.
+           */
+          continue;
+        }
+      struct TagData *copy = AllocData ();
+      copy->tid = cur->tid;
+      copy->count = 1;
+      copy->next = 0;
+      memcpy (copy->data, cur->data, PACKET_TAG_MAX_SIZE);
+      *prevNext = copy;
+      prevNext = &copy->next;
+    }
+  *prevNext = 0;
+  RemoveAll ();
+  m_next = start;
+  return true;
+}
+
+void 
+PacketTagList::Add (const Tag &tag) const
+{
+  NS_LOG_FUNCTION (this << tag.GetInstanceTypeId ());
+  // ensure this id was not yet added
+  for (struct TagData *cur = m_next; cur != 0; cur = cur->next) 
+    {
+      NS_ASSERT (cur->tid != tag.GetInstanceTypeId ());
+    }
+  struct TagData *head = AllocData ();
+  head->count = 1;
+  head->next = 0;
+  head->tid = tag.GetInstanceTypeId ();
+  head->next = m_next;
+  NS_ASSERT (tag.GetSerializedSize () < PACKET_TAG_MAX_SIZE);
+  tag.Serialize (TagBuffer (head->data, head->data+tag.GetSerializedSize ()));
+
+  const_cast<PacketTagList *> (this)->m_next = head;
+}
+
+bool
+PacketTagList::Peek (Tag &tag) const
+{
+  NS_LOG_FUNCTION (this << tag.GetInstanceTypeId ());
+  TypeId tid = tag.GetInstanceTypeId ();
+  for (struct TagData *cur = m_next; cur != 0; cur = cur->next) 
+    {
+      if (cur->tid == tid) 
+        {
+          /* found tag */
+          tag.Deserialize (TagBuffer (cur->data, cur->data+PACKET_TAG_MAX_SIZE));
+          return true;
+        }
+    }
+  /* no tag found */
+  return false;
+}
+
+const struct PacketTagList::TagData *
+PacketTagList::Head (void) const
+{
+  return m_next;
+}
+
+} // namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-tag-list.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,142 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ *
+ * 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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef PACKET_TAG_LIST_H
+#define PACKET_TAG_LIST_H
+
+#include <stdint.h>
+#include <ostream>
+#include "ns3/type-id.h"
+
+namespace ns3 {
+
+class Tag;
+
+/**
+ * \ingroup constants
+ * \brief Tag maximum size
+ * The maximum size (in bytes) of a Tag is stored
+ * in this constant.
+ */
+#define PACKET_TAG_MAX_SIZE 20
+
+class PacketTagList 
+{
+public:
+  struct TagData {
+    uint8_t data[PACKET_TAG_MAX_SIZE];
+    struct TagData *next;
+    TypeId tid;
+    uint32_t count;
+  };
+
+  inline PacketTagList ();
+  inline PacketTagList (PacketTagList const &o);
+  inline PacketTagList &operator = (PacketTagList const &o);
+  inline ~PacketTagList ();
+
+  void Add (Tag const&tag) const;
+  bool Remove (Tag &tag);
+  bool Peek (Tag &tag) const;
+  inline void RemoveAll (void);
+
+  const struct PacketTagList::TagData *Head (void) const;
+
+private:
+
+  bool Remove (TypeId tid);
+  struct PacketTagList::TagData *AllocData (void) const;
+  void FreeData (struct TagData *data) const;
+
+  static struct PacketTagList::TagData *g_free;
+  static uint32_t g_nfree;
+
+  struct TagData *m_next;
+};
+
+} // namespace ns3
+
+/****************************************************
+ *  Implementation of inline methods for performance
+ ****************************************************/
+
+namespace ns3 {
+
+PacketTagList::PacketTagList ()
+  : m_next ()
+{}
+
+PacketTagList::PacketTagList (PacketTagList const &o)
+  : m_next (o.m_next)
+{
+  if (m_next != 0) 
+    {
+      m_next->count++;
+    }
+}
+
+PacketTagList &
+PacketTagList::operator = (PacketTagList const &o)
+{
+  // self assignment
+  if (m_next == o.m_next) 
+    {
+      return *this;
+    }
+  RemoveAll ();
+  m_next = o.m_next;
+  if (m_next != 0) 
+    {
+      m_next->count++;
+    }
+  return *this;
+}
+
+PacketTagList::~PacketTagList ()
+{
+  RemoveAll ();
+}
+
+void
+PacketTagList::RemoveAll (void)
+{
+  struct TagData *prev = 0;
+  for (struct TagData *cur = m_next; cur != 0; cur = cur->next) 
+    {
+      cur->count--;
+      if (cur->count > 0) 
+        {
+          break;
+        }
+      if (prev != 0) 
+        {
+          FreeData (prev);
+        }
+      prev = cur;
+    }
+  if (prev != 0) 
+    {
+      FreeData (prev);
+    }
+  m_next = 0;
+}
+
+} // namespace ns3
+
+#endif /* PACKET_TAG_LIST_H */
--- a/src/common/packet.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/common/packet.cc	Fri May 29 10:15:19 2009 +0400
@@ -28,22 +28,22 @@
 uint32_t Packet::m_globalUid = 0;
 
 TypeId 
-TagIterator::Item::GetTypeId (void) const
+ByteTagIterator::Item::GetTypeId (void) const
 {
   return m_tid;
 }
 uint32_t 
-TagIterator::Item::GetStart (void) const
+ByteTagIterator::Item::GetStart (void) const
 {
   return m_start;
 }
 uint32_t 
-TagIterator::Item::GetEnd (void) const
+ByteTagIterator::Item::GetEnd (void) const
 {
   return m_end;
 }
 void 
-TagIterator::Item::GetTag (Tag &tag) const
+ByteTagIterator::Item::GetTag (Tag &tag) const
 {
   if (tag.GetInstanceTypeId () != GetTypeId ())
     {
@@ -51,31 +51,64 @@
     }
   tag.Deserialize (m_buffer);
 }
-TagIterator::Item::Item (TypeId tid, uint32_t start, uint32_t end, TagBuffer buffer)
+ByteTagIterator::Item::Item (TypeId tid, uint32_t start, uint32_t end, TagBuffer buffer)
   : m_tid (tid),
     m_start (start),
     m_end (end),
     m_buffer (buffer)
 {}
 bool 
-TagIterator::HasNext (void) const
+ByteTagIterator::HasNext (void) const
 {
   return m_current.HasNext ();
 }
-TagIterator::Item 
-TagIterator::Next (void)
+ByteTagIterator::Item 
+ByteTagIterator::Next (void)
 {
-  TagList::Iterator::Item i = m_current.Next ();
-  return TagIterator::Item (i.tid, 
-                            i.start-m_current.GetOffsetStart (), 
-                            i.end-m_current.GetOffsetStart (), 
-                            i.buf);
+  ByteTagList::Iterator::Item i = m_current.Next ();
+  return ByteTagIterator::Item (i.tid, 
+                                i.start-m_current.GetOffsetStart (), 
+                                i.end-m_current.GetOffsetStart (), 
+                                i.buf);
 }
-TagIterator::TagIterator (TagList::Iterator i)
+ByteTagIterator::ByteTagIterator (ByteTagList::Iterator i)
   : m_current (i)
 {}
 
 
+PacketTagIterator::PacketTagIterator (const struct PacketTagList::TagData *head)
+  : m_current (head)
+{}
+bool 
+PacketTagIterator::HasNext (void) const
+{
+  return m_current != 0;
+}
+PacketTagIterator::Item 
+PacketTagIterator::Next (void)
+{
+  NS_ASSERT (HasNext ());
+  const struct PacketTagList::TagData *prev = m_current;
+  m_current = m_current->next;
+  return PacketTagIterator::Item (prev);
+}
+
+PacketTagIterator::Item::Item (const struct PacketTagList::TagData *data)
+  : m_data (data)
+{}
+TypeId 
+PacketTagIterator::Item::GetTypeId (void) const
+{
+  return m_data->tid;
+}
+void 
+PacketTagIterator::Item::GetTag (Tag &tag) const
+{
+  NS_ASSERT (tag.GetInstanceTypeId () == m_data->tid);
+  tag.Deserialize (TagBuffer ((uint8_t*)m_data->data, (uint8_t*)m_data->data+PACKET_TAG_MAX_SIZE));
+}
+
+
 void 
 Packet::Ref (void) const
 {
@@ -102,7 +135,8 @@
 
 Packet::Packet ()
   : m_buffer (),
-    m_tagList (),
+    m_byteTagList (),
+    m_packetTagList (),
     m_metadata (m_globalUid, 0),
     m_refCount (1)
 {
@@ -111,7 +145,8 @@
 
 Packet::Packet (const Packet &o)
   : m_buffer (o.m_buffer),
-    m_tagList (o.m_tagList),
+    m_byteTagList (o.m_byteTagList),
+    m_packetTagList (o.m_packetTagList),
     m_metadata (o.m_metadata),
     m_refCount (1)
 {}
@@ -124,14 +159,16 @@
       return *this;
     }
   m_buffer = o.m_buffer;
-  m_tagList = o.m_tagList;
+  m_byteTagList = o.m_byteTagList;
+  m_packetTagList = o.m_packetTagList;
   m_metadata = o.m_metadata;
   return *this;
 }
 
 Packet::Packet (uint32_t size)
   : m_buffer (size),
-    m_tagList (),
+    m_byteTagList (),
+    m_packetTagList (),
     m_metadata (m_globalUid, size),
     m_refCount (1)
 {
@@ -139,7 +176,8 @@
 }
 Packet::Packet (uint8_t const*buffer, uint32_t size)
   : m_buffer (),
-    m_tagList (),
+    m_byteTagList (),
+    m_packetTagList (),
     m_metadata (m_globalUid, size),
     m_refCount (1)
 {
@@ -149,9 +187,11 @@
   i.Write (buffer, size);
 }
 
-Packet::Packet (const Buffer &buffer,  const TagList &tagList, const PacketMetadata &metadata)
+Packet::Packet (const Buffer &buffer,  const ByteTagList &byteTagList, 
+                const PacketTagList &packetTagList, const PacketMetadata &metadata)
   : m_buffer (buffer),
-    m_tagList (tagList),
+    m_byteTagList (byteTagList),
+    m_packetTagList (packetTagList),
     m_metadata (metadata),
     m_refCount (1)
 {}
@@ -166,7 +206,7 @@
   PacketMetadata metadata = m_metadata.CreateFragment (start, end);
   // again, call the constructor directly rather than
   // through Create because it is private.
-  return Ptr<Packet> (new Packet (buffer, m_tagList, metadata), false);
+  return Ptr<Packet> (new Packet (buffer, m_byteTagList, m_packetTagList, metadata), false);
 }
 
 uint32_t 
@@ -184,8 +224,8 @@
   bool resized = m_buffer.AddAtStart (size);
   if (resized)
     {
-      m_tagList.AddAtStart (m_buffer.GetCurrentStartOffset () + size - orgStart,
-                            m_buffer.GetCurrentStartOffset () + size);
+      m_byteTagList.AddAtStart (m_buffer.GetCurrentStartOffset () + size - orgStart,
+                                m_buffer.GetCurrentStartOffset () + size);
     }
   header.Serialize (m_buffer.Begin ());
   m_metadata.AddHeader (header, size);
@@ -215,8 +255,8 @@
   bool resized = m_buffer.AddAtEnd (size);
   if (resized)
     {
-      m_tagList.AddAtEnd (m_buffer.GetCurrentStartOffset () - orgStart,
-                          m_buffer.GetCurrentEndOffset () - size);
+      m_byteTagList.AddAtEnd (m_buffer.GetCurrentStartOffset () - orgStart,
+                              m_buffer.GetCurrentEndOffset () - size);
     }
   Buffer::Iterator end = m_buffer.End ();
   trailer.Serialize (end);
@@ -247,12 +287,12 @@
   uint32_t bEnd = packet->m_buffer.GetCurrentEndOffset ();
   m_buffer.AddAtEnd (packet->m_buffer);
   uint32_t appendPrependOffset = m_buffer.GetCurrentEndOffset () - packet->m_buffer.GetSize ();
-  m_tagList.AddAtEnd (m_buffer.GetCurrentStartOffset () - aStart, 
-                      appendPrependOffset);
-  TagList copy = packet->m_tagList;
+  m_byteTagList.AddAtEnd (m_buffer.GetCurrentStartOffset () - aStart, 
+                          appendPrependOffset);
+  ByteTagList copy = packet->m_byteTagList;
   copy.AddAtStart (m_buffer.GetCurrentEndOffset () - bEnd,
                    appendPrependOffset);
-  m_tagList.Add (copy);
+  m_byteTagList.Add (copy);
   m_metadata.AddAtEnd (packet->m_metadata);
 }
 void
@@ -263,8 +303,8 @@
   bool resized = m_buffer.AddAtEnd (size);
   if (resized)
     {
-      m_tagList.AddAtEnd (m_buffer.GetCurrentEndOffset () - orgEnd,
-                          m_buffer.GetCurrentEndOffset () - size);
+      m_byteTagList.AddAtEnd (m_buffer.GetCurrentEndOffset () - orgEnd,
+                              m_buffer.GetCurrentEndOffset () - size);
     }
   m_metadata.AddPaddingAtEnd (size);
 }
@@ -284,10 +324,10 @@
 }
 
 void 
-Packet::RemoveAllTags (void)
+Packet::RemoveAllByteTags (void)
 {
   NS_LOG_FUNCTION (this);
-  m_tagList.RemoveAll ();
+  m_byteTagList.RemoveAll ();
 }
 
 uint8_t const *
@@ -316,12 +356,12 @@
 }
 
 void 
-Packet::PrintTags (std::ostream &os) const
+Packet::PrintByteTags (std::ostream &os) const
 {
-  TagIterator i = GetTagIterator ();
+  ByteTagIterator i = GetByteTagIterator ();
   while (i.HasNext ())
     {
-      TagIterator::Item item = i.Next ();
+      ByteTagIterator::Item item = i.Next ();
       os << item.GetTypeId ().GetName () << " [" << item.GetStart () << "-" << item.GetEnd () << "]";
       Callback<ObjectBase *> constructor = item.GetTypeId ().GetConstructor ();
       if (constructor.IsNull ())
@@ -537,29 +577,29 @@
 }
 
 void 
-Packet::AddTag (const Tag &tag) const
+Packet::AddByteTag (const Tag &tag) const
 {
   NS_LOG_FUNCTION (this << &tag);
-  TagList *list = const_cast<TagList *> (&m_tagList);
+  ByteTagList *list = const_cast<ByteTagList *> (&m_byteTagList);
   TagBuffer buffer = list->Add (tag.GetInstanceTypeId (), tag.GetSerializedSize (), 
-                                 m_buffer.GetCurrentStartOffset (),
-                                 m_buffer.GetCurrentEndOffset ());
+                                m_buffer.GetCurrentStartOffset (),
+                                m_buffer.GetCurrentEndOffset ());
   tag.Serialize (buffer);
 }
-TagIterator 
-Packet::GetTagIterator (void) const
+ByteTagIterator 
+Packet::GetByteTagIterator (void) const
 {
-  return TagIterator (m_tagList.Begin (m_buffer.GetCurrentStartOffset (), m_buffer.GetCurrentEndOffset ()));
+  return ByteTagIterator (m_byteTagList.Begin (m_buffer.GetCurrentStartOffset (), m_buffer.GetCurrentEndOffset ()));
 }
 
 bool 
-Packet::FindFirstMatchingTag (Tag &tag) const
+Packet::FindFirstMatchingByteTag (Tag &tag) const
 {
   TypeId tid = tag.GetInstanceTypeId ();
-  TagIterator i = GetTagIterator ();
+  ByteTagIterator i = GetByteTagIterator ();
   while (i.HasNext ())
     {
-      TagIterator::Item item = i.Next ();
+      ByteTagIterator::Item item = i.Next ();
       if (tid == item.GetTypeId ())
         {
           item.GetTag (tag);
@@ -569,6 +609,59 @@
   return false;
 }
 
+void 
+Packet::AddPacketTag (const Tag &tag) const
+{
+  m_packetTagList.Add (tag);
+}
+bool 
+Packet::RemovePacketTag (Tag &tag)
+{
+  bool found = m_packetTagList.Remove (tag);
+  return found;
+}
+bool 
+Packet::PeekPacketTag (Tag &tag) const
+{
+  bool found = m_packetTagList.Peek (tag);
+  return found;
+}
+void 
+Packet::RemoveAllPacketTags (void)
+{
+  m_packetTagList.RemoveAll ();
+}
+
+void 
+Packet::PrintPacketTags (std::ostream &os) const
+{
+  PacketTagIterator i = GetPacketTagIterator ();
+  while (i.HasNext ())
+    {
+      PacketTagIterator::Item item = i.Next ();
+      NS_ASSERT (item.GetTypeId ().HasConstructor ());
+      Callback<ObjectBase *> constructor = item.GetTypeId ().GetConstructor ();
+      NS_ASSERT (!constructor.IsNull ());
+      ObjectBase *instance = constructor ();
+      Tag *tag = dynamic_cast<Tag *> (instance);
+      NS_ASSERT (tag != 0);
+      item.GetTag (*tag);
+      tag->Print (os);
+      delete tag;
+      if (i.HasNext ())
+        {
+          os << " ";
+        }
+    }
+}
+
+PacketTagIterator 
+Packet::GetPacketTagIterator (void) const
+{
+  return PacketTagIterator (m_packetTagList.Head ());
+}
+
+
 std::ostream& operator<< (std::ostream& os, const Packet &packet)
 {
   packet.Print (os);
@@ -578,8 +671,6 @@
 
 } // namespace ns3
 
-
-
 #ifdef RUN_SELF_TESTS
 
 #include "ns3/test.h"
@@ -766,14 +857,14 @@
 namespace ns3 {
 
 
-class PacketTest: public Test 
+static class PacketTest: public Test 
 {
 public:
   PacketTest ();
   virtual bool RunTests (void);
 private:
   bool DoCheck (Ptr<const Packet> p, const char *file, int line, uint32_t n, ...);
-};
+} g_packetTest;
 
 
 PacketTest::PacketTest ()
@@ -795,11 +886,11 @@
     }
   va_end (ap);
 
-  TagIterator i = p->GetTagIterator ();
+  ByteTagIterator i = p->GetByteTagIterator ();
   uint32_t j = 0;
   while (i.HasNext () && j < expected.size ())
     {
-      TagIterator::Item item = i.Next ();
+      ByteTagIterator::Item item = i.Next ();
       struct Expected e = expected[j];
       std::ostringstream oss;
       oss << "anon::ATestTag<" << e.n << ">";
@@ -838,12 +929,12 @@
 
   Ptr<const Packet> p = Create<Packet> (1000);
 
-  p->AddTag (ATestTag<1> ());
+  p->AddByteTag (ATestTag<1> ());
   CHECK (p, 1, E (1, 0, 1000));
   Ptr<const Packet> copy = p->Copy ();
   CHECK (copy, 1, E (1, 0, 1000));
 
-  p->AddTag (ATestTag<2> ());
+  p->AddByteTag (ATestTag<2> ());
   CHECK (p, 2, E (1, 0, 1000), E(2, 0, 1000));
   CHECK (copy, 1, E (1, 0, 1000));
 
@@ -854,7 +945,7 @@
     CHECK (&c0, 1, E (1, 0, 1000));
     CHECK (&c1, 1, E (1, 0, 1000));
     CHECK (copy, 1, E (1, 0, 1000));
-    c0.AddTag (ATestTag<10> ());
+    c0.AddByteTag (ATestTag<10> ());
     CHECK (&c0, 2, E (1, 0, 1000), E (10, 0, 1000));
     CHECK (&c1, 1, E (1, 0, 1000));
     CHECK (copy, 1, E (1, 0, 1000));
@@ -863,11 +954,11 @@
   Ptr<Packet> frag0 = p->CreateFragment (0, 10);
   Ptr<Packet> frag1 = p->CreateFragment (10, 90);
   Ptr<const Packet> frag2 = p->CreateFragment (100, 900);
-  frag0->AddTag (ATestTag<3> ());
+  frag0->AddByteTag (ATestTag<3> ());
   CHECK (frag0, 3, E (1, 0, 10), E(2, 0, 10), E (3, 0, 10));
-  frag1->AddTag (ATestTag<4> ());
+  frag1->AddByteTag (ATestTag<4> ());
   CHECK (frag1, 3, E (1, 0, 90), E(2, 0, 90), E (4, 0, 90));
-  frag2->AddTag (ATestTag<5> ());
+  frag2->AddByteTag (ATestTag<5> ());
   CHECK (frag2, 3, E (1, 0, 900), E(2, 0, 900), E (5, 0, 900));
 
   frag1->AddAtEnd (frag2);
@@ -887,7 +978,7 @@
   frag0 = 0;
 
   p = Create<Packet> (1000);
-  p->AddTag (ATestTag<20> ());
+  p->AddByteTag (ATestTag<20> ());
   CHECK (p, 1, E (20, 0, 1000));
   frag0 = p->CreateFragment (10, 90);
   CHECK (p, 1, E (20, 0, 1000));
@@ -898,7 +989,7 @@
 
   {
     Ptr<Packet> tmp = Create<Packet> (100);
-    tmp->AddTag (ATestTag<20> ());
+    tmp->AddByteTag (ATestTag<20> ());
     CHECK (tmp, 1, E (20, 0, 100));
     tmp->AddHeader (ATestHeader<10> ());
     CHECK (tmp, 1, E (20, 10, 110));
@@ -909,7 +1000,7 @@
     CHECK (tmp, 1, E (20, 10, 110));
 
     tmp = Create<Packet> (100);
-    tmp->AddTag (ATestTag<20> ());
+    tmp->AddByteTag (ATestTag<20> ());
     CHECK (tmp, 1, E (20, 0, 100));
     tmp->AddTrailer (ATestTrailer<10> ());
     CHECK (tmp, 1, E (20, 0, 100));
@@ -924,7 +1015,7 @@
   {
     Ptr<Packet> tmp = Create<Packet> (0);
     tmp->AddHeader (ATestHeader<156> ());
-    tmp->AddTag (ATestTag<20> ());
+    tmp->AddByteTag (ATestTag<20> ());
     CHECK (tmp, 1, E (20, 0, 156));
     tmp->RemoveAtStart (120);
     CHECK (tmp, 1, E (20, 0, 36));
@@ -935,29 +1026,56 @@
 
   {
     Ptr<Packet> tmp = Create<Packet> (0);
-    tmp->AddTag (ATestTag<20> ());
+    tmp->AddByteTag (ATestTag<20> ());
     CHECK (tmp, 0, E (20, 0, 0));
   }
   {
     Ptr<Packet> tmp = Create<Packet> (1000);
-    tmp->AddTag (ATestTag<20> ());
+    tmp->AddByteTag (ATestTag<20> ());
     CHECK (tmp, 1, E (20, 0, 1000));
     tmp->RemoveAtStart (1000);
     CHECK (tmp, 0,  E (0,0,0));
     Ptr<Packet> a = Create<Packet> (10);
-    a->AddTag (ATestTag<10> ());
+    a->AddByteTag (ATestTag<10> ());
     CHECK (a, 1, E (10, 0, 10));
     tmp->AddAtEnd (a);
     CHECK (tmp, 1, E (10, 0, 10));
   }
-  
+
+  {
+    Packet p;
+    ATestTag<10> a;
+    p.AddPacketTag (a);
+    NS_TEST_ASSERT (p.PeekPacketTag (a));
+    ATestTag<11> b;
+    p.AddPacketTag (b);
+    NS_TEST_ASSERT (p.PeekPacketTag (b));
+    NS_TEST_ASSERT (p.PeekPacketTag (a));
+    Packet copy = p;
+    NS_TEST_ASSERT (copy.PeekPacketTag (b));
+    NS_TEST_ASSERT (copy.PeekPacketTag (a));
+    ATestTag<12> c;
+    NS_TEST_ASSERT (!copy.PeekPacketTag (c));
+    copy.AddPacketTag (c);
+    NS_TEST_ASSERT (copy.PeekPacketTag (c));
+    NS_TEST_ASSERT (copy.PeekPacketTag (b));
+    NS_TEST_ASSERT (copy.PeekPacketTag (a));
+    NS_TEST_ASSERT (!p.PeekPacketTag (c));
+    copy.RemovePacketTag (b);
+    NS_TEST_ASSERT (!copy.PeekPacketTag (b));
+    NS_TEST_ASSERT (p.PeekPacketTag (b));
+    p.RemovePacketTag (a);
+    NS_TEST_ASSERT (!p.PeekPacketTag (a));
+    NS_TEST_ASSERT (copy.PeekPacketTag (a));
+    NS_TEST_ASSERT (!p.PeekPacketTag (c));
+    NS_TEST_ASSERT (copy.PeekPacketTag (c));
+    p.RemoveAllPacketTags ();
+    NS_TEST_ASSERT (!p.PeekPacketTag (b));
+  }
 
   return result;
 }
 
-
-static PacketTest g_packetTest;
-
-}; // namespace ns3
+} // namespace ns3
 
 #endif /* RUN_SELF_TESTS */
--- a/src/common/packet.h	Thu May 28 21:41:45 2009 -0700
+++ b/src/common/packet.h	Fri May 29 10:15:19 2009 +0400
@@ -26,7 +26,8 @@
 #include "trailer.h"
 #include "packet-metadata.h"
 #include "tag.h"
-#include "tag-list.h"
+#include "byte-tag-list.h"
+#include "packet-tag-list.h"
 #include "ns3/callback.h"
 #include "ns3/assert.h"
 #include "ns3/ptr.h"
@@ -45,7 +46,7 @@
  *
  * This is a java-style iterator.
  */
-class TagIterator
+class ByteTagIterator
 {
 public:
   /**
@@ -81,7 +82,7 @@
      */
     void GetTag (Tag &tag) const;
   private:
-    friend class TagIterator;
+    friend class ByteTagIterator;
     Item (TypeId tid, uint32_t start, uint32_t end, TagBuffer buffer);
     TypeId m_tid;
     uint32_t m_start;
@@ -98,16 +99,63 @@
   Item Next (void);
 private:
   friend class Packet;
-  TagIterator (TagList::Iterator i);
-  TagList::Iterator m_current;
+  ByteTagIterator (ByteTagList::Iterator i);
+  ByteTagList::Iterator m_current;
+};
+
+/**
+ * \ingroup packet
+ * \brief Iterator over the set of 'packet' tags in a packet
+ *
+ * This is a java-style iterator.
+ */
+class PacketTagIterator
+{
+public:
+  /**
+   * Identifies a tag within a packet.
+   */
+  class Item 
+  {
+  public:
+    /**
+     * \returns the ns3::TypeId associated to this tag.
+     */
+    TypeId GetTypeId (void) const;
+    /**
+     * \param tag the user tag to which the data should be copied.
+     *
+     * Read the requested tag and store it in the user-provided
+     * tag instance. This method will crash if the type of the
+     * tag provided by the user does not match the type of
+     * the underlying tag.
+     */
+    void GetTag (Tag &tag) const;
+  private:
+    friend class PacketTagIterator;
+    Item (const struct PacketTagList::TagData *data);
+    const struct PacketTagList::TagData *m_data;
+  };
+  /**
+   * \returns true if calling Next is safe, false otherwise.
+   */
+  bool HasNext (void) const;
+  /**
+   * \returns the next item found and prepare for the next one.
+   */
+  Item Next (void);
+private:
+  friend class Packet;
+  PacketTagIterator (const struct PacketTagList::TagData *head);
+  const struct PacketTagList::TagData *m_current;
 };
 
 /**
  * \ingroup packet
  * \brief network packets
  *
- * Each network packet contains a byte buffer, a set of tags, and
- * metadata.
+ * Each network packet contains a byte buffer, a set of byte tags, a set of
+ * packet tags, and metadata.
  *
  * - The byte buffer stores the serialized content of the headers and trailers 
  * added to a packet. The serialized representation of these headers is expected
@@ -115,17 +163,23 @@
  * forces you to do this) which means that the content of a packet buffer
  * is expected to be that of a real packet.
  *
- * - Each tag tags a subset of the bytes in the packet byte buffer with the 
- * information stored in the tag. A classic example of a tag is a FlowIdTag 
- * which contains a flow id: the set of bytes tagged by this tag implicitely 
- * belong to the attached flow id.
- *
  * - The metadata describes the type of the headers and trailers which
  * were serialized in the byte buffer. The maintenance of metadata is
  * optional and disabled by default. To enable it, you must call
  * Packet::EnableMetadata and this will allow you to get non-empty
  * output from Packet::Print and Packet::Print.
  *
+ * - The set of tags contain simulation-specific information which cannot
+ * be stored in the packet byte buffer because the protocol headers or trailers
+ * have no standard-conformant field for this information. So-called
+ * 'byte' tags are used to tag a subset of the bytes in the packet byte buffer
+ * while 'packet' tags are used to tag the packet itself. The main difference
+ * between these two kinds of tags is what happens when packets are copied,
+ * fragmented, and reassembled: 'byte' tags follow bytes while 'packet' tags
+ * follow packets. A classic example of a 'byte' tag is a FlowIdTag 
+ * which contains a flow id: the set of bytes tagged by this tag implicitely 
+ * belong to the attached flow id.
+ *
  * Implementing a new type of Header or Trailer for a new protocol is 
  * pretty easy and is a matter of creating a subclass of the ns3::Header 
  * or of the ns3::Trailer base class, and implementing the methods
@@ -236,13 +290,6 @@
    * \returns the number of bytes read from the end of the packet.
    */
   uint32_t PeekTrailer (Trailer &trailer);
-  /**
-   * \param os output stream in which the data should be printed.
-   *
-   * Iterate over the tags present in this packet, and
-   * invoke the Print method of each tag stored in the packet.
-   */
-  void PrintTags (std::ostream &os) const;
 
   /**
    * Concatenate the input packet at the end of the current
@@ -388,11 +435,11 @@
    * totally evil to allow a trace sink to modify the content of a
    * packet).
    */
-  void AddTag (const Tag &tag) const;
+  void AddByteTag (const Tag &tag) const;
   /**
-   * \returns an iterator over the set of tags included in this packet.
+   * \returns an iterator over the set of byte tags included in this packet.
    */
-  TagIterator GetTagIterator (void) const;
+  ByteTagIterator GetByteTagIterator (void) const;
   /**
    * \param tag the tag to search in this packet
    * \returns true if the requested tag type was found, false otherwise.
@@ -400,17 +447,78 @@
    * If the requested tag type is found, it is copied in the user's 
    * provided tag instance.
    */
-  bool FindFirstMatchingTag (Tag &tag) const;
+  bool FindFirstMatchingByteTag (Tag &tag) const;
 
   /**
    * Remove all the tags stored in this packet.
    */
-  void RemoveAllTags (void);
+  void RemoveAllByteTags (void);
+
+  /**
+   * \param os output stream in which the data should be printed.
+   *
+   * Iterate over the tags present in this packet, and
+   * invoke the Print method of each tag stored in the packet.
+   */
+  void PrintByteTags (std::ostream &os) const;
+
+  /**
+   * \param tag the tag to store in this packet
+   *
+   * Add a tag to this packet. This method calls the
+   * Tag::GetSerializedSize and, then, Tag::Serialize.
+   *
+   * Note that this method is const, that is, it does not
+   * modify the state of this packet, which is fairly
+   * un-intuitive.
+   *
+   * \sa AddTag
+   */
+  void AddPacketTag (const Tag &tag) const;
+  /**
+   * \param tag the tag to remove from this packet
+   * \returns true if the requested tag is found, false
+   *          otherwise.
+   *
+   * Remove a tag from this packet. This method calls
+   * Tag::Deserialize if the tag is found.
+   */
+  bool RemovePacketTag (Tag &tag);
+  /**
+   * \param tag the tag to search in this packet
+   * \returns true if the requested tag is found, false
+   *          otherwise.
+   *
+   * Search a matching tag and call Tag::Deserialize if it is found.
+   */
+  bool PeekPacketTag (Tag &tag) const;
+  /**
+   * Remove all packet tags.
+   */
+  void RemoveAllPacketTags (void);
+
+  /**
+   * \param os the stream in which we want to print data.
+   *
+   * Print the list of 'packet' tags.
+   *
+   * \sa Packet::AddPacketTag, Packet::RemovePacketTag, Packet::PeekPacketTag,
+   *  Packet::RemoveAllPacketTags
+   */
+  void PrintPacketTags (std::ostream &os) const;
+
+  /**
+   * \returns an object which can be used to iterate over the list of
+   *  packet tags.
+   */
+  PacketTagIterator GetPacketTagIterator (void) const;
 
 private:
-  Packet (const Buffer &buffer, const TagList &tagList, const PacketMetadata &metadata);
+  Packet (const Buffer &buffer, const ByteTagList &byteTagList, 
+          const PacketTagList &packetTagList, const PacketMetadata &metadata);
   Buffer m_buffer;
-  TagList m_tagList;
+  ByteTagList m_byteTagList;
+  PacketTagList m_packetTagList;
   PacketMetadata m_metadata;
   mutable uint32_t m_refCount;
   static uint32_t m_globalUid;
@@ -435,11 +543,14 @@
  *   - ns3::Packet::AddHeader
  *   - ns3::Packet::AddTrailer
  *   - both versions of ns3::Packet::AddAtEnd
+ *   - ns3::Packet::RemovePacketTag
  *
  * Non-dirty operations:
  *   - ns3::Packet::AddTag
  *   - ns3::Packet::RemoveAllTags
  *   - ns3::Packet::PeekTag
+ *   - ns3::Packet::RemoveAllPacketTags
+ *   - ns3::Packet::PeekPacketTag
  *   - ns3::Packet::RemoveHeader
  *   - ns3::Packet::RemoveTrailer
  *   - ns3::Packet::CreateFragment
--- a/src/common/tag-list.cc	Thu May 28 21:41:45 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,421 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2008 INRIA
- *
- * 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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "tag-list.h"
-#include "ns3/log.h"
-#include <vector>
-#include <string.h>
-
-NS_LOG_COMPONENT_DEFINE ("TagList");
-
-#define USE_FREE_LIST 1
-#define FREE_LIST_SIZE 1000
-#define OFFSET_MAX (2147483647)
-
-namespace ns3 {
-
-struct TagListData {
-  uint32_t size;
-  uint32_t count;
-  uint32_t dirty;
-  uint8_t data[4];
-};
-
-#ifdef USE_FREE_LIST
-static class TagListDataFreeList : public std::vector<struct TagListData *>
-{
-public:
-  ~TagListDataFreeList ();
-} g_freeList;
-static uint32_t g_maxSize = 0;
-
-TagListDataFreeList::~TagListDataFreeList ()
-{
-  for (TagListDataFreeList::iterator i = begin ();
-       i != end (); i++)
-    {
-      uint8_t *buffer = (uint8_t *)(*i);
-      delete [] buffer;
-    }
-}
-#endif /* USE_FREE_LIST */
-
-TagList::Iterator::Item::Item (TagBuffer buf_)
-    : buf (buf_)
-{}
-
-bool 
-TagList::Iterator::HasNext (void) const
-{
-  return m_current < m_end;
-}
-struct TagList::Iterator::Item 
-TagList::Iterator::Next (void)
-{
-  NS_ASSERT (HasNext ());
-  struct Item item = Item (TagBuffer (m_current+16, m_end));
-  item.tid.SetUid (m_nextTid);
-  item.size = m_nextSize;
-  item.start = std::max (m_nextStart, m_offsetStart);
-  item.end = std::min (m_nextEnd, m_offsetEnd);
-  m_current += 4 + 4 + 4 + 4 + item.size;
-  item.buf.TrimAtEnd (m_end - m_current);
-  PrepareForNext ();
-  return item;
-}
-void
-TagList::Iterator::PrepareForNext (void)
-{
-  while (m_current < m_end)
-    {
-      TagBuffer buf = TagBuffer (m_current, m_end);
-      m_nextTid = buf.ReadU32 ();
-      m_nextSize = buf.ReadU32 ();
-      m_nextStart = buf.ReadU32 ();
-      m_nextEnd = buf.ReadU32 ();
-      if (m_nextStart >= m_offsetEnd || m_nextEnd <= m_offsetStart)
-	{
-	  m_current += 4 + 4 + 4 + 4 + m_nextSize;
-	}
-      else
-	{
-	  break;
-	}
-    }
-}
-TagList::Iterator::Iterator (uint8_t *start, uint8_t *end, int32_t offsetStart, int32_t offsetEnd)
-  : m_current (start),
-    m_end (end),
-    m_offsetStart (offsetStart),
-    m_offsetEnd (offsetEnd)
-{
-  PrepareForNext ();
-}
-
-uint32_t 
-TagList::Iterator::GetOffsetStart (void) const
-{
-  return m_offsetStart;
-}
-
-
-TagList::TagList ()
-  : m_used (0),
-    m_data (0)
-{
-  NS_LOG_FUNCTION (this);
-}
-TagList::TagList (const TagList &o)
-  : m_used (o.m_used),
-    m_data (o.m_data)
-{
-  NS_LOG_FUNCTION (this << &o);
-  if (m_data != 0)
-    {
-      m_data->count++;
-    }
-}
-TagList &
-TagList::operator = (const TagList &o)
-{
-  NS_LOG_FUNCTION (this << &o);
-  if (this == &o)
-    {
-      return *this;
-    }
-
-  Deallocate (m_data);
-  m_data = o.m_data;
-  m_used = o.m_used;
-  if (m_data != 0)
-    {
-      m_data->count++;
-    }
-  return *this;
-}
-TagList::~TagList ()
-{
-  NS_LOG_FUNCTION (this);
-  Deallocate (m_data);
-  m_data = 0;
-  m_used = 0;
-}
-
-TagBuffer
-TagList::Add (TypeId tid, uint32_t bufferSize, int32_t start, int32_t end)
-{
-  NS_LOG_FUNCTION (this << tid << bufferSize << start << end);
-  uint32_t spaceNeeded = m_used + bufferSize + 4 + 4 + 4 + 4;
-  NS_ASSERT (m_used <= spaceNeeded);
-  if (m_data == 0)
-    {
-      m_data = Allocate (spaceNeeded);
-      m_used = 0;
-    } 
-  else if (m_data->size < spaceNeeded ||
-	   (m_data->count != 1 && m_data->dirty != m_used))
-    {
-      struct TagListData *newData = Allocate (spaceNeeded);
-      memcpy (&newData->data, &m_data->data, m_used);
-      Deallocate (m_data);
-      m_data = newData;
-    }
-  TagBuffer tag = TagBuffer (&m_data->data[m_used], 
-			     &m_data->data[spaceNeeded]);
-  tag.WriteU32 (tid.GetUid ());
-  tag.WriteU32 (bufferSize);
-  tag.WriteU32 (start);
-  tag.WriteU32 (end);
-  m_used = spaceNeeded;
-  m_data->dirty = m_used;
-  return tag;
-}
-
-void 
-TagList::Add (const TagList &o)
-{
-  NS_LOG_FUNCTION (this << &o);
-  TagList::Iterator i = o.BeginAll ();
-  while (i.HasNext ())
-    {
-      TagList::Iterator::Item item = i.Next ();
-      TagBuffer buf = Add (item.tid, item.size, item.start, item.end);
-      buf.CopyFrom (item.buf);
-    }
-}
-
-void 
-TagList::RemoveAll (void)
-{
-  NS_LOG_FUNCTION (this);
-  Deallocate (m_data);
-  m_data = 0;
-  m_used = 0;
-}
-
-TagList::Iterator 
-TagList::BeginAll (void) const
-{
-  NS_LOG_FUNCTION (this);
-  // I am not totally sure but I might need to use 
-  // INT32_MIN instead of zero below.
-  return Begin (0, OFFSET_MAX);
-}
-
-TagList::Iterator 
-TagList::Begin (int32_t offsetStart, int32_t offsetEnd) const
-{
-  NS_LOG_FUNCTION (this << offsetStart << offsetEnd);
-  if (m_data == 0)
-    {
-      return Iterator (0, 0, offsetStart, offsetEnd);
-    }
-  else
-    {
-      return Iterator (m_data->data, &m_data->data[m_used], offsetStart, offsetEnd);
-    }
-}
-
-bool 
-TagList::IsDirtyAtEnd (int32_t appendOffset)
-{
-  NS_LOG_FUNCTION (this << appendOffset);
-  TagList::Iterator i = BeginAll ();
-  while (i.HasNext ())
-    {
-      TagList::Iterator::Item item = i.Next ();
-      if (item.end > appendOffset)
-	{
-	  return true;
-	}
-    }
-  return false;
-}
-
-bool 
-TagList::IsDirtyAtStart (int32_t prependOffset)
-{
-  NS_LOG_FUNCTION (this << prependOffset);
-  TagList::Iterator i = BeginAll ();
-  while (i.HasNext ())
-    {
-      TagList::Iterator::Item item = i.Next ();
-      if (item.start < prependOffset)
-	{
-	  return true;
-	}
-    }
-  return false;
-}
-
-void 
-TagList::AddAtEnd (int32_t adjustment, int32_t appendOffset)
-{
-  NS_LOG_FUNCTION (this << adjustment << appendOffset);
-  if (adjustment == 0 && !IsDirtyAtEnd (appendOffset))
-    {
-      return;
-    }
-  TagList list;
-  TagList::Iterator i = BeginAll ();
-  while (i.HasNext ())
-    {
-      TagList::Iterator::Item item = i.Next ();
-      item.start += adjustment;
-      item.end += adjustment;
-
-      if (item.start >= appendOffset)
-	{
-	  continue;
-	}
-      else if (item.start < appendOffset && item.end > appendOffset)
-	{
-	  item.end = appendOffset;
-	}
-      else
-	{
-	  // nothing to do.
-	}
-      TagBuffer buf = list.Add (item.tid, item.size, item.start, item.end);
-      buf.CopyFrom (item.buf);
-    }
-  *this = list;  
-}
-
-void 
-TagList::AddAtStart (int32_t adjustment, int32_t prependOffset)
-{
-  NS_LOG_FUNCTION (this << adjustment << prependOffset);
-  if (adjustment == 0 && !IsDirtyAtStart (prependOffset))
-    {
-      return;
-    }
-  TagList list;
-  TagList::Iterator i = BeginAll ();
-  while (i.HasNext ())
-    {
-      TagList::Iterator::Item item = i.Next ();
-      item.start += adjustment;
-      item.end += adjustment;
-
-      if (item.end <= prependOffset)
-	{
-	  continue;
-	}
-      else if (item.end > prependOffset && item.start < prependOffset)
-	{
-	  item.start = prependOffset;
-	}
-      else
-	{
-	  // nothing to do.
-	}
-      TagBuffer buf = list.Add (item.tid, item.size, item.start, item.end);
-      buf.CopyFrom (item.buf);
-    }
-  *this = list;
-}
-
-#ifdef USE_FREE_LIST
-
-struct TagListData *
-TagList::Allocate (uint32_t size)
-{
-  NS_LOG_FUNCTION (this << size);
-  while (!g_freeList.empty ())
-    {
-      struct TagListData *data = g_freeList.back ();
-      g_freeList.pop_back ();
-      NS_ASSERT (data != 0);
-      if (data->size >= size)
-	{
-	  data->count = 1;
-	  data->dirty = 0;
-	  return data;
-	}
-      uint8_t *buffer = (uint8_t *)data;
-      delete [] buffer;
-    }
-  uint8_t *buffer = new uint8_t [std::max (size, g_maxSize) + sizeof (struct TagListData) - 4];
-  struct TagListData *data = (struct TagListData *)buffer;
-  data->count = 1;
-  data->size = size;
-  data->dirty = 0;
-  return data;
-}
-
-void 
-TagList::Deallocate (struct TagListData *data)
-{
-  NS_LOG_FUNCTION (this << data);
-  if (data == 0)
-    {
-      return;
-    }
-  g_maxSize = std::max (g_maxSize, data->size);
-  data->count--;
-  if (data->count == 0)
-    {
-      if (g_freeList.size () > FREE_LIST_SIZE ||
-	  data->size < g_maxSize)
-	{
-	  uint8_t *buffer = (uint8_t *)data;
-	  delete [] buffer;
-	}
-      else
-	{
-	  g_freeList.push_back (data);
-	}
-    }
-}
-
-#else /* USE_FREE_LIST */
-
-struct TagListData *
-TagList::Allocate (uint32_t size)
-{
-  NS_LOG_FUNCTION (this << size);
-  uint8_t *buffer = new uint8_t [size + sizeof (struct TagListData) - 4];
-  struct TagListData *data = (struct TagListData *)buffer;
-  data->count = 1;
-  data->size = size;
-  data->dirty = 0;
-  return data;
-}
-
-void 
-TagList::Deallocate (struct TagListData *data)
-{
-  NS_LOG_FUNCTION (this << data);
-  if (data == 0)
-    {
-      return;
-    }
-  data->count--;
-  if (data->count == 0)
-    {
-      uint8_t *buffer = (uint8_t *)data;
-      delete [] buffer;
-    }
-}
-
-#endif /* USE_FREE_LIST */
-
-
-} // namespace ns3
--- a/src/common/tag-list.h	Thu May 28 21:41:45 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,170 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2008 INRIA
- *
- * 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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef TAG_LIST_H
-#define TAG_LIST_H
-
-#include <stdint.h>
-#include "ns3/type-id.h"
-#include "tag-buffer.h"
-
-namespace ns3 {
-
-struct TagListData;
-
-/**
- * \ingroup packet
- *
- * \brief keep track of the tags stored in a packet.
- *
- * This class is mostly private to the Packet implementation and users
- * should never have to access it directly.
- *
- * \internal
- * The implementation of this class is a bit tricky so, there are a couple
- * of things to keep in mind here:
- *
- *   - it stores all tags in a single byte buffer: each tag is stored
- *     as 4 32bit integers (TypeId, tag data size, start, end) followed 
- *     by the tag data as generated by Tag::Serialize.
- *
- *   - the struct TagListData structure which contains the tag byte buffer
- *     is shared and, thus, reference-counted. This data structure is unshared
- *     as-needed to emulate COW semantics.
- *
- *   - each tag tags a unique set of bytes identified by the pair of offsets 
- *     (start,end). These offsets are provided by Buffer::GetCurrentStartOffset
- *     and Buffer::GetCurrentEndOffset which means that they are relative to 
- *     the start of the 'virtual byte buffer' as explained in the documentation
- *     for the ns3::Buffer class. Whenever the origin of the offset of the Buffer
- *     instance associated to this TagList instance changes, the Buffer class
- *     reports this to its container Packet class as a bool return value
- *     in Buffer::AddAtStart and Buffer::AddAtEnd. In both cases, when this happens
- *     the Packet class calls TagList::AddAtEnd and TagList::AddAtStart to update
- *     the byte offsets of each tag in the TagList.
- *
- *   - whenever bytes are removed from the packet byte buffer, the TagList offsets 
- *     are never updated because we rely on the fact that they will be updated in
- *     either the next call to Packet::AddHeader or Packet::AddTrailer or when
- *     the user iterates the tag list with Packet::GetTagIterator and 
- *     TagIterator::Next.
- */
-class TagList
-{
-public:
-
-  class Iterator
-  {
-  public:
-    struct Item 
-    {
-      TypeId tid;
-      uint32_t size;
-      int32_t start;
-      int32_t end;
-      TagBuffer buf;
-      Item (TagBuffer buf);
-    private:
-      friend class TagList;
-      friend class TagList::Iterator;
-    };
-    bool HasNext (void) const;
-    struct TagList::Iterator::Item Next (void);
-    uint32_t GetOffsetStart (void) const;
-  private:
-    friend class TagList;
-    Iterator (uint8_t *start, uint8_t *end, int32_t offsetStart, int32_t offsetEnd);
-    void PrepareForNext (void);
-    uint8_t *m_current;
-    uint8_t *m_end;
-    int32_t m_offsetStart;
-    int32_t m_offsetEnd;
-    uint32_t m_nextTid;
-    uint32_t m_nextSize;
-    int32_t m_nextStart;
-    int32_t m_nextEnd;
-  };
-
-  TagList ();
-  TagList (const TagList &o);
-  TagList &operator = (const TagList &o);
-  ~TagList ();
-
-  /**
-   * \param tid the typeid of the tag added
-   * \param bufferSize the size of the tag when its serialization will 
-   *        be completed. Typically, the return value of Tag::GetSerializedSize
-   * \param start offset which uniquely identifies the first byte tagged by this tag.
-   * \param end offset which uniquely identifies the last byte tagged by this tag.
-   * \returns a buffer which can be used to write the tag data.     
-   *
-   * 
-   */
-  TagBuffer Add (TypeId tid, uint32_t bufferSize, int32_t start, int32_t end);
-
-  /**
-   * \param o the other list of tags to aggregate.
-   *
-   * Aggregate the two lists of tags.
-   */
-  void Add (const TagList &o);
-
-  void RemoveAll (void);
-
-  /**
-   * \param offsetStart the offset which uniquely identifies the first data byte 
-   *        present in the byte buffer associated to this TagList.
-   * \param offsetEnd the offset which uniquely identifies the last data byte 
-   *        present in the byte buffer associated to this TagList.
-   * \returns an iterator
-   *
-   * The returned iterator will allow you to loop through the set of tags present
-   * in this list: the boundaries of each tag as reported by their start and
-   * end offsets will be included within the input offsetStart and offsetEnd.
-   */
-  TagList::Iterator Begin (int32_t offsetStart, int32_t offsetEnd) const;
-
-  /**
-   * Adjust the offsets stored internally by the adjustment delta and
-   * make sure that all offsets are smaller than appendOffset which represents
-   * the location where new bytes have been added to the byte buffer.
-   */
-  void AddAtEnd (int32_t adjustment, int32_t appendOffset);
-  /**
-   * Adjust the offsets stored internally by the adjustment delta and
-   * make sure that all offsets are bigger than prependOffset which represents
-   * the location where new bytes have been added to the byte buffer.
-   */
-  void AddAtStart (int32_t adjustment, int32_t prependOffset);
-
-private:
-  bool IsDirtyAtEnd (int32_t appendOffset);
-  bool IsDirtyAtStart (int32_t prependOffset);
-  TagList::Iterator BeginAll (void) const;
-
-  struct TagListData *Allocate (uint32_t size);
-  void Deallocate (struct TagListData *data);
-
-  uint16_t m_used;
-  struct TagListData *m_data;
-};
-
-} // namespace ns3
-
-#endif /* TAG_LIST_H */
--- a/src/common/tag.h	Thu May 28 21:41:45 2009 -0700
+++ b/src/common/tag.h	Fri May 29 10:15:19 2009 +0400
@@ -41,8 +41,8 @@
   /**
    * \returns the number of bytes required to serialize the data of the tag.
    *
-   * This method is typically invoked by Packet::AddTag just prior to calling
-   * Tag::Serialize.
+   * This method is typically invoked by Packet::AddPacketTag or Packet::AddByteTag
+   * just prior to calling Tag::Serialize.
    */
   virtual uint32_t GetSerializedSize (void) const = 0;
   /**
@@ -65,7 +65,8 @@
   /**
    * \param os the stream to print to
    *
-   * This method is typically invoked from the Packet::PrintTags method
+   * This method is typically invoked from the Packet::PrintByteTags
+   * or Packet::PrintPacketTags methods.
    */
   virtual void Print (std::ostream &os) const = 0;
 };
--- a/src/common/wscript	Thu May 28 21:41:45 2009 -0700
+++ b/src/common/wscript	Fri May 29 10:15:19 2009 +0400
@@ -14,8 +14,9 @@
         'data-rate.cc',
         'error-model.cc',
         'tag.cc',
-        'tag-list.cc',
+        'byte-tag-list.cc',
         'tag-buffer.cc',
+        'packet-tag-list.cc',
         ]
 
     headers = bld.new_task_gen('ns3header')
@@ -31,6 +32,7 @@
         'data-rate.h',
         'error-model.h',
         'tag.h',
-        'tag-list.h',
+        'byte-tag-list.h',
         'tag-buffer.h',
+        'packet-tag-list.h',
         ]
--- a/src/contrib/delay-jitter-estimation.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/contrib/delay-jitter-estimation.cc	Fri May 29 10:15:19 2009 +0400
@@ -83,14 +83,14 @@
 DelayJitterEstimation::PrepareTx (Ptr<const Packet> packet)
 {
   DelayJitterEstimationTimestampTag tag;
-  packet->AddTag (tag);
+  packet->AddByteTag (tag);
 }
 void 
 DelayJitterEstimation::RecordRx (Ptr<const Packet> packet)
 {
   DelayJitterEstimationTimestampTag tag;
   bool found;
-  found = packet->FindFirstMatchingTag (tag);
+  found = packet->FindFirstMatchingByteTag (tag);
   if (!found)
     {
       return;
--- a/src/core/test.h	Thu May 28 21:41:45 2009 -0700
+++ b/src/core/test.h	Fri May 29 10:15:19 2009 +0400
@@ -110,7 +110,7 @@
 
 #define NS_TEST_ASSERT_EQUAL_FILELINE(got, expected, file, line)    \
   do {                                                              \
-    if ((got) != (expected))                                        \
+    if (! ((got) == (expected)))                                    \
       {                                                             \
         Failure () << file << ":" <<line                            \
                    << ": expected " << (expected)                   \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/airtime-metric.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,38 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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
+ * 
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ */
+
+#include "airtime-metric.h"
+#include "ns3/wifi-remote-station-manager.h"
+#include "ns3/wifi-mode.h"
+namespace ns3 {
+namespace dot11s {
+uint32_t
+AirtimeLinkMetricCalculator::CalculateMetric(Mac48Address peerAddress, Ptr<MeshWifiInterfaceMac> mac)
+{
+  WifiRemoteStation * station = mac->GetStationManager ()->Lookup(peerAddress);
+  NS_ASSERT(station != 0);
+  Ptr<Packet> test_frame = Create<Packet> (test_length);
+  uint32_t rate = station->GetDataMode(test_frame, test_length+header_length).GetDataRate ();
+  uint32_t payload_nanosec = (uint32_t) ((double) (test_length * 8) * 1e9 / ((double)rate));
+  uint32_t metric = (uint32_t) (((double) (payload_nanosec + overhead_nanosec)) / 102.4 * (station->GetAvgSlrc () + 1));
+  return metric;
+}
+} //namespace dot11s
+} //namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/airtime-metric.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,44 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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
+ * 
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ */
+
+#ifndef AIRTIME_METRIC_H
+#define AIRTIME_METRIC_H
+#include "ns3/mesh-wifi-interface-mac.h"
+namespace ns3 {
+namespace dot11s {
+class AirtimeLinkMetricCalculator : public RefCountBase
+{
+  public:
+    friend class MeshWifiInterfaceMac;
+    uint32_t CalculateMetric(Mac48Address peerAddress, Ptr<MeshWifiInterfaceMac> mac);
+  private:
+    ///\Microseconds of overhead:
+    static const uint32_t overhead_nanosec = 
+      (34   //DIFS
+      +9*2  //SIFS
+      +16*2 //Preamble
+      +24)  //Ack
+      *1000; //nanoseconds
+    static const uint32_t test_length = 1024;
+    static const uint32_t header_length = 36;
+};
+} //namespace dot11s
+} //namespace ns3
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/dot11s-helper.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,194 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ *         Pavel Boyko <boyko@iitp.ru>
+ */
+
+
+#include "dot11s-helper.h"
+#include "ns3/simulator.h"
+#include "ns3/mesh-point-device.h"
+#include "ns3/wifi-net-device.h"
+#include "ns3/wifi-phy.h"
+#include "ns3/wifi-channel.h"
+#include "ns3/wifi-remote-station-manager.h"
+#include "ns3/mesh-wifi-interface-mac.h"
+#include "ns3/aarf-wifi-manager.h"
+#include "airtime-metric.h"
+namespace ns3 {
+namespace dot11s {
+
+MeshWifiHelper::MeshWifiHelper () : 
+    m_randomStartDelay (Seconds (0)),
+    m_spreadInterfaceChannels (false)
+{
+}
+void 
+MeshWifiHelper::SetRandomStartDelay (Time t)
+{
+  m_randomStartDelay = t;
+}
+
+void 
+MeshWifiHelper::SetSpreadInterfaceChannels (bool s)
+{
+  m_spreadInterfaceChannels = s;
+}
+
+
+Ptr<WifiNetDevice> 
+MeshWifiHelper::CreateInterface (const WifiPhyHelper &phyHelper, Ptr<Node> node) const
+{
+  Ptr<WifiNetDevice> device = CreateObject<WifiNetDevice> ();
+  
+  // Creating MAC for this interface
+  Ptr<MeshWifiInterfaceMac> mac = CreateObject<MeshWifiInterfaceMac> ();
+  mac->SetSsid (Ssid ());
+  if (m_randomStartDelay > Seconds (0))
+    mac->SetRandomStartDelay (m_randomStartDelay);
+  Ptr<WifiRemoteStationManager> manager = CreateObject<AarfWifiManager> ();
+  Ptr<WifiPhy> phy = phyHelper.Create (node, device);
+  mac->SetAddress (Mac48Address::Allocate ());
+  device->SetMac (mac);
+  device->SetPhy (phy);
+  device->SetRemoteStationManager (manager);
+  Ptr<AirtimeLinkMetricCalculator> metric = Create <AirtimeLinkMetricCalculator> ();
+  mac->SetLinkMetricCallback (MakeCallback(&AirtimeLinkMetricCalculator::CalculateMetric, metric));
+  /*
+  if (channel > 0)
+    mac->SwitchFrequencyChannel (channel);
+  */
+  return device;
+}
+  
+NetDeviceContainer
+MeshWifiHelper::Install (const WifiPhyHelper &phyHelper, NodeContainer c,  std::vector<uint32_t> roots, uint32_t nInterfaces) const
+{
+  NetDeviceContainer devices;
+  uint32_t node_index = 0;
+  for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
+  {
+    Ptr<Node> node = *i;
+    
+    // Create a mesh point device
+    Ptr<MeshPointDevice> mp = CreateObject<MeshPointDevice> ();
+    node->AddDevice (mp);
+    
+    // Create wifi interfaces (single interface by default)
+    for (uint32_t i = 0; i < nInterfaces; ++i)
+      {
+        Ptr<WifiNetDevice> iface = CreateInterface (phyHelper, node);
+        
+        node->AddDevice (iface);
+        mp->AddInterface (iface);
+      }
+    
+    // Set different channels on different ifaces
+    if (m_spreadInterfaceChannels)
+      {
+        std::vector<Ptr<NetDevice> > ifaces = mp->GetInterfaces ();
+        for (size_t i = 0; i < ifaces.size(); ++i)
+          {
+            uint32_t channel = i * 5;
+            
+            Ptr<WifiNetDevice> iface = ifaces[i]->GetObject<WifiNetDevice> ();
+            NS_ASSERT (iface);
+            Ptr<MeshWifiInterfaceMac> mac = iface->GetMac ()->GetObject<MeshWifiInterfaceMac> ();
+            NS_ASSERT (mac);
+            
+            mac->SwitchFrequencyChannel (channel);
+          }
+      }
+    
+    // Install 802.11s protocols
+    Ptr<PeerManagementProtocol> pmp = CreateObject<PeerManagementProtocol> ();
+    pmp->SetMeshId("mesh",4);
+    bool install_ok = pmp->Install (mp);
+    NS_ASSERT (install_ok);
+    
+    Ptr<HwmpProtocol> hwmp = CreateObject<HwmpProtocol> ();
+    install_ok = hwmp->Install (mp);
+    NS_ASSERT (install_ok);
+    
+    pmp->SetPeerLinkStatusCallback(MakeCallback(&HwmpProtocol::PeerLinkStatus, hwmp));
+    hwmp->SetNeighboursCallback(MakeCallback(&PeerManagementProtocol::GetActiveLinks, pmp));
+    // Setting root mesh point
+    for(std::vector<uint32_t>::const_iterator root_iterator = roots.begin (); root_iterator != roots.end (); root_iterator ++)
+      //if(*root_iterator == i.GetDistanceFrom(c.Begin ()))
+      if(*root_iterator == node_index)
+        hwmp->SetRoot ();
+    devices.Add (mp);
+    node_index ++;
+  }
+  return devices;
+}
+
+NetDeviceContainer
+MeshWifiHelper::Install (const WifiPhyHelper &phy, Ptr<Node> node,  std::vector<uint32_t> roots, uint32_t nInterfaces) const
+{
+  return Install (phy, NodeContainer (node), roots, nInterfaces);
+}
+void
+MeshWifiHelper::Report (const ns3::Ptr<ns3::NetDevice>& device, std::ostream& os)
+{
+  Ptr <MeshPointDevice> mp = device->GetObject<MeshPointDevice> ();
+  NS_ASSERT (mp != 0);
+  std::vector<Ptr<NetDevice> > ifaces = mp->GetInterfaces ();
+  os << "<MeshPointDevice ReportTime=\"" << Simulator::Now().GetSeconds() << "s\" MpAddress=\"" << mp->GetAddress () << "\">\n";
+  for (std::vector<Ptr<NetDevice> >::const_iterator i = ifaces.begin(); i != ifaces.end(); ++i)
+  {
+    Ptr<WifiNetDevice> device = (*i)->GetObject<WifiNetDevice> ();
+    NS_ASSERT (device != 0);
+    Ptr<MeshWifiInterfaceMac> mac = device->GetMac()->GetObject<MeshWifiInterfaceMac> ();
+    NS_ASSERT (mac != 0);
+    mac->Report(os);
+  }
+  Ptr <HwmpProtocol> hwmp = mp->GetObject<HwmpProtocol> ();
+  NS_ASSERT(hwmp != 0);
+  hwmp->Report (os);
+
+  Ptr <PeerManagementProtocol> pmp = mp->GetObject<PeerManagementProtocol> ();
+  NS_ASSERT(pmp != 0);
+  pmp->Report (os);
+  os << "</MeshPointDevice>\n";
+}
+void
+MeshWifiHelper::ResetStats (const ns3::Ptr<ns3::NetDevice>& device)
+{
+  Ptr <MeshPointDevice> mp = device->GetObject<MeshPointDevice> ();
+  NS_ASSERT (mp != 0);
+  std::vector<Ptr<NetDevice> > ifaces = mp->GetInterfaces ();
+  for (std::vector<Ptr<NetDevice> >::const_iterator i = ifaces.begin(); i != ifaces.end(); ++i)
+  {
+    Ptr<WifiNetDevice> device = (*i)->GetObject<WifiNetDevice> ();
+    NS_ASSERT (device != 0);
+    Ptr<MeshWifiInterfaceMac> mac = device->GetMac()->GetObject<MeshWifiInterfaceMac> ();
+    NS_ASSERT (mac != 0);
+    mac->ResetStats ();
+  }
+  Ptr <HwmpProtocol> hwmp = mp->GetObject<HwmpProtocol> ();
+  NS_ASSERT(hwmp != 0);
+  hwmp->ResetStats ();
+
+  Ptr <PeerManagementProtocol> pmp = mp->GetObject<PeerManagementProtocol> ();
+  NS_ASSERT(pmp != 0);
+  pmp->ResetStats ();
+}
+} // namespace dot11s
+} //namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/dot11s-helper.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,92 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ *         Pavel Boyko <boyko@iitp.ru>
+ */
+
+
+#ifndef _MESHWIFIHELPER_H
+#define _MESHWIFIHELPER_H
+
+#include "ns3/wifi-helper.h"
+#include "ns3/nstime.h"
+#include "ns3/peer-management-protocol.h"
+#include "ns3/hwmp-protocol.h"
+#include "ie-dot11s-id.h"
+
+namespace ns3 {
+namespace dot11s {
+
+class WifiChannel;
+
+/** 
+ * \ingroup dot11s
+ * 
+ * \brief Helper to create IEEE 802.11s mesh networks
+ */
+class MeshWifiHelper
+{
+public:
+  MeshWifiHelper (); 
+  /// Set maximum random start delay
+  void SetRandomStartDelay (Time delay);
+  /** 
+   *  \brief Spread/not spread frequency channels of MP interfaces. 
+   * 
+   *  If set to true different non-overlaping 20MHz frequency 
+   *  channels will be assigned to different mesh point interfaces.
+   */ 
+  void SetSpreadInterfaceChannels (bool); 
+  
+  /** 
+   * \brief Install 802.11s mesh device & protocols on given node
+   * 
+   * \param phy                 Wifi PHY helper
+   * \param nodes               List of nodes to install
+   * \param roots               List of root mesh points
+   * \param nInterfaces         Number of mesh point radio interfaces (= WiFi NICs)
+   * 
+   * \return list of created mesh point devices, see MeshPointDevice
+   */
+  NetDeviceContainer Install (const WifiPhyHelper &phyHelper, NodeContainer c, std::vector<uint32_t> roots = std::vector<uint32_t> (), uint32_t nInterfaces = 1) const;
+  /** 
+   * \brief Install 802.11s mesh device & protocols on given node
+   * 
+   * \param phy                 Wifi PHY helper
+   * \param node                Node to install
+   * \param roots               List of root mesh points
+   * \param nInterfaces         Number of mesh point radio interfaces (= WiFi NICs)
+   * 
+   * \return list of created mesh point devices, see MeshPointDevice
+   */ 
+  NetDeviceContainer Install (const WifiPhyHelper &phy, Ptr<Node> node,  std::vector<uint32_t> roots = std::vector<uint32_t> (), uint32_t nInterfaces = 1) const;
+  static void Report (const ns3::Ptr<ns3::NetDevice>&, std::ostream&);
+  static void ResetStats (const ns3::Ptr<ns3::NetDevice>&);
+private:
+  Time m_randomStartDelay;
+  bool m_spreadInterfaceChannels;
+  
+  /// Create single mesh interface NIC
+  Ptr<WifiNetDevice> CreateInterface (const WifiPhyHelper &phyHelper, Ptr<Node> node) const;
+  
+};
+} // namespace dot11s
+} //namespace ns3
+
+#endif /* _MESHWIFIHELPER_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/dot11s-mac-header.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,381 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#include "ns3/assert.h"
+#include "ns3/address-utils.h"
+#include "dot11s-mac-header.h"
+#include "ns3/packet.h"
+#include "ns3/test.h"
+
+namespace ns3 {
+namespace dot11s {
+/***********************************************************
+ *  Here Mesh Mac Header functionality is defined.
+ ***********************************************************/
+TypeId
+MeshHeader::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::Dot11sMacHeader")
+    .SetParent<Header> ()
+    .AddConstructor<MeshHeader> ()
+    ;
+  return tid;
+}
+MeshHeader::MeshHeader ():
+  m_meshFlags (0),
+  m_meshTtl (0),
+  m_meshSeqno (0),
+  m_addr4 (Mac48Address ()),
+  m_addr5 (Mac48Address ()),
+  m_addr6 (Mac48Address ())
+{
+}
+MeshHeader::~MeshHeader ()
+{
+}
+TypeId
+MeshHeader::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+void
+MeshHeader::SetAddr4 (Mac48Address address)
+{
+  m_addr4 = address;
+}
+void
+MeshHeader::SetAddr5 (Mac48Address address)
+{
+  m_addr5 = address;
+}
+void
+MeshHeader::SetAddr6 (Mac48Address address)
+{
+  m_addr6 = address;
+}
+Mac48Address
+MeshHeader::GetAddr4 () const
+{
+  return m_addr4;
+}
+Mac48Address
+MeshHeader::GetAddr5 () const
+{
+  return m_addr5;
+}
+Mac48Address
+MeshHeader::GetAddr6 () const
+{
+  return m_addr6;
+}
+void
+MeshHeader::SetMeshSeqno (uint32_t seqno)
+{
+  m_meshSeqno = seqno;
+}
+uint32_t
+MeshHeader::GetMeshSeqno () const
+{
+  return m_meshSeqno;
+}
+void
+MeshHeader::SetMeshTtl (uint8_t TTL)
+{
+  m_meshTtl = TTL;
+}
+uint8_t
+MeshHeader::GetMeshTtl () const
+{
+  return m_meshTtl;
+}
+void
+MeshHeader::SetAddressExt (uint8_t num_of_addresses)
+{
+  if (num_of_addresses > 3)
+    return;
+  m_meshFlags |= 0xc0 & (num_of_addresses << 6);
+}
+uint8_t
+MeshHeader::GetAddressExt () const
+{
+  return ((0xc0 & m_meshFlags) >> 6);
+}
+uint32_t
+MeshHeader::GetSerializedSize () const
+{
+  return 6 + GetAddressExt () * 6;
+}
+void
+MeshHeader::Serialize (Buffer::Iterator start) const
+{
+  Buffer::Iterator i = start;
+  i.WriteU8 (m_meshFlags);
+  i.WriteU8 (m_meshTtl);
+  i.WriteU32 (m_meshSeqno);
+  uint8_t addresses_to_add = GetAddressExt ();
+  //Writing Address extensions:
+  if ((addresses_to_add == 1) || (addresses_to_add == 3))
+    WriteTo (i, m_addr4);
+  if (addresses_to_add > 1)
+    WriteTo (i, m_addr5);
+  if (addresses_to_add > 1)
+    WriteTo (i, m_addr6);
+}
+uint32_t
+MeshHeader::Deserialize (Buffer::Iterator start)
+{
+  Buffer::Iterator i = start;
+  uint8_t addresses_to_read = 0;
+  m_meshFlags = i.ReadU8 ();
+  m_meshTtl = i.ReadU8 ();
+  m_meshSeqno = i.ReadU32 ();
+  addresses_to_read = (m_meshFlags & 0xc0) >> 6;
+  if ((addresses_to_read == 1) || (addresses_to_read == 3))
+    ReadFrom (i, m_addr4);
+  if (addresses_to_read > 1)
+    ReadFrom (i, m_addr5);
+  if (addresses_to_read > 1)
+    ReadFrom (i, m_addr6);
+  return i.GetDistanceFrom (start);
+}
+void
+MeshHeader::Print (std::ostream &os) const
+{
+  os << "flags = " << (uint16_t)m_meshFlags
+  << "\nttl = " << (uint16_t)m_meshTtl
+  << "\nseqno = " << m_meshSeqno
+  << "\naddr4 = " << m_addr4
+  << "\naddr5 = " << m_addr5
+  << "\naddr6 = " << m_addr6;
+}
+bool operator== (const MeshHeader & a, const MeshHeader & b)
+{
+  return (
+      (a.m_meshFlags == b.m_meshFlags) &&
+      (a.m_meshTtl == b.m_meshTtl) &&
+      (a.m_meshSeqno == b.m_meshSeqno) &&
+      (a.m_addr4 == b.m_addr4) &&
+      (a.m_addr5 == b.m_addr5) &&
+      (a.m_addr6 == b.m_addr6)
+      );
+}
+/**********************************************************
+ *   ActionFrame
+ **********************************************************/
+WifiMeshActionHeader::WifiMeshActionHeader ()
+{
+}
+WifiMeshActionHeader::~WifiMeshActionHeader ()
+{
+}
+void
+WifiMeshActionHeader::SetAction (
+  WifiMeshActionHeader::CategoryValue type,
+  WifiMeshActionHeader::ActionValue action)
+{
+  m_category = type;
+  
+  switch (type)
+    {
+    case MESH_PEER_LINK_MGT:
+      {
+        m_actionValue = action.peerLink;
+        break;
+      }
+    case MESH_PATH_SELECTION:
+      {
+        m_actionValue = action.pathSelection;
+        break;
+      }
+    case MESH_LINK_METRIC:
+    case MESH_INTERWORK_ACTION:
+    case MESH_RESOURCE_COORDINATION:
+      break;
+    };
+}
+WifiMeshActionHeader::CategoryValue
+WifiMeshActionHeader::GetCategory ()
+{
+  switch (m_category)
+    {
+    case MESH_PEER_LINK_MGT:
+      return MESH_PEER_LINK_MGT;
+    case MESH_LINK_METRIC:
+      return MESH_LINK_METRIC;
+    case MESH_PATH_SELECTION:
+      return MESH_PATH_SELECTION;
+    case MESH_INTERWORK_ACTION:
+      return MESH_INTERWORK_ACTION;
+    case MESH_RESOURCE_COORDINATION:
+      return MESH_RESOURCE_COORDINATION;
+    default:
+      NS_ASSERT (false);
+      return MESH_PEER_LINK_MGT;
+    }
+}
+WifiMeshActionHeader::ActionValue
+WifiMeshActionHeader::GetAction ()
+{
+  ActionValue retval;
+  switch (m_category)
+    {
+    case MESH_PEER_LINK_MGT:
+      switch (m_actionValue)
+        {
+        case PEER_LINK_OPEN:
+          retval.peerLink = PEER_LINK_OPEN;
+          return retval;
+        case PEER_LINK_CONFIRM:
+          retval.peerLink = PEER_LINK_CONFIRM;
+          return retval;
+        case PEER_LINK_CLOSE:
+          retval.peerLink = PEER_LINK_CLOSE;
+          return retval;
+        default:
+          NS_ASSERT (false);
+          return retval;
+        }
+    case MESH_PATH_SELECTION:
+      switch (m_actionValue)
+        {
+        case PATH_REQUEST:
+          retval.pathSelection = PATH_REQUEST;
+          return retval;
+        case PATH_REPLY:
+          retval.pathSelection = PATH_REPLY;
+          return retval;
+        case PATH_ERROR:
+          retval.pathSelection = PATH_ERROR;
+          return retval;
+        case ROOT_ANNOUNCEMENT:
+          retval.pathSelection = ROOT_ANNOUNCEMENT;
+          return retval;
+        default:
+          NS_ASSERT (false);
+          return retval;
+        }
+    case MESH_LINK_METRIC:
+      // ???
+    case MESH_INTERWORK_ACTION:
+      // ???
+    case MESH_RESOURCE_COORDINATION:
+      // ???
+    default:
+      NS_ASSERT (false);
+      return retval;
+    }
+}
+TypeId
+WifiMeshActionHeader::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::WifiMeshActionHeader")
+                      .SetParent<Header> ()
+                      .AddConstructor<WifiMeshActionHeader> ()
+                      ;
+  return tid;
+}
+TypeId
+WifiMeshActionHeader::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+void
+WifiMeshActionHeader::Print (std::ostream &os) const
+{
+}
+uint32_t
+WifiMeshActionHeader::GetSerializedSize () const
+{
+  return 2;
+}
+void
+WifiMeshActionHeader::Serialize (Buffer::Iterator start) const
+{
+  start.WriteU8 (m_category);
+  start.WriteU8 (m_actionValue);
+}
+uint32_t
+WifiMeshActionHeader::Deserialize (Buffer::Iterator start)
+{
+  Buffer::Iterator i = start;
+  m_category = i.ReadU8 ();
+  m_actionValue = i.ReadU8 ();
+  return i.GetDistanceFrom (start);
+}
+#ifdef RUN_SELF_TESTS
+
+/// Built-in self test for Dot11sMacHeader
+struct Dot11sMacHeaderBist : public Test 
+{
+  Dot11sMacHeaderBist () : Test ("Mesh/802.11s/MeshHeader") {}
+  virtual bool RunTests(); 
+};
+
+/// Test instance
+static Dot11sMacHeaderBist g_Dot11sMacHeaderBist;
+
+bool Dot11sMacHeaderBist::RunTests ()
+{
+  bool result (true);
+  {
+    MeshHeader a;
+    a.SetAddressExt(3);
+    a.SetAddr4(Mac48Address ("11:22:33:44:55:66"));
+    a.SetAddr5(Mac48Address ("11:00:33:00:55:00"));
+    a.SetAddr6(Mac48Address ("00:22:00:44:00:66"));
+    a.SetMeshTtl (122);
+    a.SetMeshSeqno (321);
+    Ptr<Packet> packet = Create<Packet> ();
+    packet->AddHeader (a);
+    MeshHeader b;
+    packet->RemoveHeader (b);
+    NS_TEST_ASSERT_EQUAL (a, b);
+  } 
+  {
+    MeshHeader a;
+    a.SetAddressExt(2);
+    a.SetAddr5(Mac48Address ("11:00:33:00:55:00"));
+    a.SetAddr6(Mac48Address ("00:22:00:44:00:66"));
+    a.SetMeshTtl (122);
+    a.SetMeshSeqno (321);
+    Ptr<Packet> packet = Create<Packet> ();
+    packet->AddHeader (a);
+    MeshHeader b;
+    packet->RemoveHeader (b);
+    NS_TEST_ASSERT_EQUAL (a, b);
+  }
+  {
+    MeshHeader a;
+    a.SetAddressExt(1);
+    a.SetAddr4(Mac48Address ("11:22:33:44:55:66"));
+    a.SetMeshTtl (122);
+    a.SetMeshSeqno (321);
+    Ptr<Packet> packet = Create<Packet> ();
+    packet->AddHeader (a);
+    MeshHeader b;
+    packet->RemoveHeader (b);
+    NS_TEST_ASSERT_EQUAL (a, b);
+  }
+  return result;
+}
+#endif
+} //namespace dot11s
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/dot11s-mac-header.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,159 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#ifndef MESH_WIFI_MAC_HEADER_H
+#define MESH_WIFI_MAC_HEADER_H
+
+#include "ns3/header.h"
+#include "ns3/mac48-address.h"
+
+namespace ns3 {
+namespace dot11s {
+/**
+ * \ingroup dot11s
+ * 
+ * \brief Mesh Control field, see IEEE 802.11s draft 3.0 section 7.1.3.5b
+ * 
+ * Header format: | Mesh flags: 1 | TTL: 1 | Sequence number: 4 | Address ext.: 0, 6, 12 or 18 | 
+ */
+class MeshHeader : public Header
+{
+public:
+  MeshHeader ();
+  ~MeshHeader ();
+  static TypeId GetTypeId ();
+  virtual TypeId GetInstanceTypeId () const;
+  virtual void Print (std::ostream &os) const;
+
+  void   SetAddr4 (Mac48Address address);
+  void   SetAddr5 (Mac48Address address);
+  void   SetAddr6 (Mac48Address address);
+  Mac48Address  GetAddr4 () const;
+  Mac48Address  GetAddr5 () const;
+  Mac48Address  GetAddr6 () const;
+
+  void   SetMeshSeqno (uint32_t seqno);
+  uint32_t  GetMeshSeqno () const;
+
+  void   SetMeshTtl (uint8_t TTL);
+  uint8_t  GetMeshTtl () const;
+
+  void   SetAddressExt (uint8_t num_of_addresses);
+  uint8_t  GetAddressExt () const;
+
+  virtual uint32_t GetSerializedSize () const;
+  virtual void  Serialize (Buffer::Iterator start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator start);
+private:
+  uint8_t  m_meshFlags;
+  uint8_t  m_meshTtl;
+  uint32_t m_meshSeqno;
+  Mac48Address m_addr4;
+  Mac48Address m_addr5;
+  Mac48Address m_addr6;
+  friend bool operator== (const MeshHeader & a, const MeshHeader & b);
+};
+bool operator== (const MeshHeader & a, const MeshHeader & b);
+
+/**
+ * \ingroup dot11s
+ * 
+ * \brief See IEEE 802.11s draft 3.0 section 7.2.3.14
+ * 
+ * Header format: | category: 1 | action value: 1 | 
+ */
+class WifiMeshActionHeader : public Header 
+{
+public:
+  WifiMeshActionHeader ();
+  ~WifiMeshActionHeader ();
+      
+  /* Compatible with open80211s implementation */
+  enum CategoryValue //table 7-24 staring from 4
+  {
+    MESH_PEER_LINK_MGT          = 30,
+    MESH_LINK_METRIC            = 31,
+    MESH_PATH_SELECTION         = 32,
+    MESH_INTERWORK_ACTION       = 33,
+    MESH_RESOURCE_COORDINATION  = 34,
+  };
+  /* Compatible with open80211s implementation */
+  enum PeerLinkMgtActionValue
+  {
+    PEER_LINK_OPEN              = 0,
+    PEER_LINK_CONFIRM           = 1,
+    PEER_LINK_CLOSE             = 2,
+  };
+  enum LinkMetricActionValue
+  {
+    LINK_METRIC_REQUEST         = 0,
+    LINK_METRIC_REPORT,
+  };
+  /* Compatible with open80211s implementation */
+  enum PathSelectionActionValue
+  {
+    PATH_REQUEST                = 0,
+    PATH_REPLY                  = 1,
+    PATH_ERROR                  = 2,
+    ROOT_ANNOUNCEMENT           = 3,
+  };
+  enum InterworkActionValue
+  {
+    PORTAL_ANNOUNCEMENT         = 0,
+  };
+  enum ResourceCoordinationActionValue
+  {
+    CONGESTION_CONTROL_NOTIFICATION = 0,
+    MDA_SETUP_REQUEST,
+    MDA_SETUP_REPLY,
+    MDAOP_ADVERTISMENT_REQUEST,
+    MDAOP_ADVERTISMENTS,
+    MDAOP_SET_TEARDOWN,
+    BEACON_TIMING_REQUEST,
+    BEACON_TIMING_RESPONSE,
+    TBTT_ADJASTMENT_REQUEST,
+    MESH_CHANNEL_SWITCH_ANNOUNCEMENT,
+  };
+  typedef union
+  {
+    enum PeerLinkMgtActionValue  peerLink;
+    enum LinkMetricActionValue  linkMetrtic;
+    enum PathSelectionActionValue  pathSelection;
+    enum InterworkActionValue  interwork;
+    enum ResourceCoordinationActionValue resourceCoordination;
+  } ActionValue;
+  void   SetAction (enum CategoryValue type,ActionValue action);
+  
+  CategoryValue GetCategory ();
+  ActionValue  GetAction ();
+  static TypeId  GetTypeId ();
+  virtual TypeId  GetInstanceTypeId () const;
+  virtual void  Print (std::ostream &os) const;
+  virtual uint32_t GetSerializedSize () const;
+  virtual void  Serialize (Buffer::Iterator start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator start);
+private:
+  uint8_t m_category;
+  uint8_t m_actionValue;
+};
+} //namespace dot11s
+} // namespace ns3
+#endif /* MESH_WIFI_MAC_HEADER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/dot11s.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,34 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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: Pavel Boyko <boyko@iitp.ru>
+ * 
+ * This is doxygen module description, don't include 
+ */
+/**
+ * \ingroup mesh 
+ * \defgroup dot11s IEEE 802.11s draft
+ * 
+ * \brief IEEE 802.11s (mesh) draft standard implementation
+ * 
+ * Current model conforms IEEE 802.11s D3.0 draft version and includes
+ * Peer Management Protocol and HWMP (routing) Protocol implementations.
+ * 
+ * The multi-interface (aka multi radio) mesh points are supported as an 
+ * extensions of ieee draft version 3.0. Note that corresponding helper
+ * creates single interface station by default.  
+ */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/hwmp-mac-plugin.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,348 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+#include "ns3/mesh-wifi-interface-mac.h"
+#include "ns3/packet.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/log.h"
+#include "hwmp-mac-plugin.h"
+#include "dot11s-mac-header.h"
+#include "hwmp-protocol.h"
+#include "hwmp-tag.h"
+#include "ie-dot11s-preq.h"
+#include "ie-dot11s-prep.h"
+
+namespace ns3 {
+namespace dot11s {
+
+NS_LOG_COMPONENT_DEFINE ("HwmpMacPlugin");
+HwmpMacPlugin::HwmpMacPlugin (uint32_t ifIndex, Ptr<HwmpProtocol> protocol):
+  m_ifIndex (ifIndex),
+  m_protocol (protocol)
+{
+}
+HwmpMacPlugin::~HwmpMacPlugin ()
+{
+}
+void
+HwmpMacPlugin::SetParent (Ptr<MeshWifiInterfaceMac> parent)
+{
+  m_parent = parent;
+}
+bool
+HwmpMacPlugin::Receive (Ptr<Packet> packet, const WifiMacHeader & header)
+{
+  //TODO: here we fix only mesh header
+  if(header.IsData())
+  {
+    MeshHeader meshHdr;
+    HwmpTag tag;
+    if(packet->PeekPacketTag (tag))
+    {
+      NS_ASSERT (false);
+    }
+    packet->RemoveHeader(meshHdr);
+    m_stats.recvData ++;
+    m_stats.recvDataBytes += packet->GetSize ();
+    //TODO: address extension
+    Mac48Address destination;
+    switch (meshHdr.GetAddressExt ())
+    {
+      case 0:
+        destination = header.GetAddr3 ();
+        break;
+      default:
+        NS_ASSERT(false);
+    };
+    tag.SetSeqno (meshHdr.GetMeshSeqno ());
+    if(meshHdr.GetMeshTtl () == 0)
+    {
+      NS_ASSERT(false);
+      return false;
+    }
+    tag.SetTtl (meshHdr.GetMeshTtl () - 1);
+    if(m_protocol->GetAddress() != destination)
+      packet->AddPacketTag(tag);
+    if (destination == Mac48Address::GetBroadcast ())
+      if(m_protocol->DropDataFrame (meshHdr.GetMeshSeqno (), header.GetAddr4 ()) )
+        return false;
+  }
+  if(header.IsAction())
+  {
+    m_stats.recvMgt ++;
+    m_stats.recvMgtBytes += packet->GetSize ();
+    WifiMeshActionHeader actionHdr;
+    packet->RemoveHeader (actionHdr);
+    WifiMeshActionHeader::ActionValue actionValue = actionHdr.GetAction ();
+    if(actionHdr.GetCategory () != WifiMeshActionHeader::MESH_PATH_SELECTION)
+      return true;
+    switch (actionValue.pathSelection)
+    {
+      case WifiMeshActionHeader::PATH_REQUEST:
+        {
+          IePreq preq;
+          m_stats.recvPreq ++;
+          packet->RemoveHeader (preq);
+          if(preq.GetOriginatorAddress () == m_protocol->GetAddress ())
+            return false;
+          if (preq.GetTtl () == 0)
+            return false;
+          preq.DecrementTtl ();
+          m_protocol->ReceivePreq (preq, header.GetAddr2 (), m_ifIndex, header.GetAddr3 (), m_parent->GetLinkMetric(header.GetAddr2 ()));
+          return false;
+        }
+      case WifiMeshActionHeader::PATH_REPLY:
+        {
+          IePrep prep;
+          m_stats.recvPrep ++;
+          packet->RemoveHeader (prep);
+          if(prep.GetTtl () == 0)
+            return false;
+          prep.DecrementTtl ();
+          m_protocol->ReceivePrep (prep, header.GetAddr2 (), m_ifIndex, header.GetAddr3 (), m_parent->GetLinkMetric(header.GetAddr2 ()));
+          return false;
+        }
+      case WifiMeshActionHeader::PATH_ERROR:
+        {
+          IePerr perr;
+          m_stats.recvPerr ++;
+          packet->RemoveHeader (perr);
+          m_protocol->ReceivePerr (perr, header.GetAddr2 (), m_ifIndex, header.GetAddr3 ());
+          return false;
+        }
+      case WifiMeshActionHeader::ROOT_ANNOUNCEMENT:
+        return false;
+    }
+  }
+  return true;
+}
+bool
+HwmpMacPlugin::UpdateOutcomingFrame (Ptr<Packet> packet, WifiMacHeader & header, Mac48Address from, Mac48Address to)
+{
+  if(!header.IsData ())
+    return true;
+  HwmpTag tag;
+  bool tagExists = packet->RemovePacketTag(tag);
+  if (!tagExists)
+  {
+     //do it this way to silence compiler
+     NS_ASSERT (false);
+  }
+  m_stats.sentData ++;
+  m_stats.sentDataBytes += packet->GetSize ();
+  MeshHeader meshHdr;
+  meshHdr.SetMeshSeqno(tag.GetSeqno());
+  meshHdr.SetMeshTtl(tag.GetTtl());
+  packet->AddHeader(meshHdr);
+  header.SetAddr1(tag.GetAddress());
+  return true;
+}
+void
+HwmpMacPlugin::SendPreq(IePreq preq)
+{
+  m_preqQueue.push_back (preq);
+  SendOnePreq ();
+}
+void
+HwmpMacPlugin::RequestDestination (Mac48Address dst, uint32_t originator_seqno, uint32_t dst_seqno)
+{
+  for(std::vector<IePreq>::iterator i = m_preqQueue.begin (); i != m_preqQueue.end (); i ++)
+    if(i->MayAddAddress(m_protocol->GetAddress ()))
+    {
+      i->AddDestinationAddressElement (m_protocol->GetDoFlag(), m_protocol->GetRfFlag(), dst, dst_seqno);
+      return;
+    }
+  IePreq preq;
+  //fill PREQ:
+  preq.SetHopcount (0);
+  preq.SetTTL (m_protocol->GetMaxTtl ());
+  preq.SetPreqID (m_protocol->GetNextPreqId ());
+  preq.SetOriginatorAddress (m_protocol->GetAddress ());
+  preq.SetOriginatorSeqNumber (originator_seqno);
+  preq.SetLifetime (m_protocol->GetActivePathLifetime ());
+  preq.AddDestinationAddressElement (m_protocol->GetDoFlag (), m_protocol->GetRfFlag (), dst, dst_seqno);
+  m_preqQueue.push_back (preq);
+  //set iterator position to my preq:
+  SendOnePreq ();
+}
+void
+HwmpMacPlugin::SendOnePreq ()
+{
+  if(m_preqTimer.IsRunning ())
+    return;
+  if (m_preqQueue.size () == 0)
+    return;
+  //reschedule sending PREQ
+  NS_ASSERT (!m_preqTimer.IsRunning());
+  m_preqTimer = Simulator::Schedule (m_protocol->GetPreqMinInterval (), &HwmpMacPlugin::SendOnePreq, this);
+  Ptr<Packet> packet  = Create<Packet> ();
+  packet->AddHeader(m_preqQueue[0]);
+  //Action header:
+  WifiMeshActionHeader actionHdr;
+  WifiMeshActionHeader::ActionValue action;
+  action.pathSelection = WifiMeshActionHeader::PATH_REQUEST;
+  actionHdr.SetAction (WifiMeshActionHeader::MESH_PATH_SELECTION, action);
+  packet->AddHeader (actionHdr);
+  //create 802.11 header:
+  WifiMacHeader hdr;
+  hdr.SetAction ();
+  hdr.SetDsNotFrom ();
+  hdr.SetDsNotTo ();
+  hdr.SetAddr2 (m_parent->GetAddress ());
+  hdr.SetAddr3 (m_protocol->GetAddress ());
+  //Send Management frame
+  std::vector <Mac48Address> receivers = m_protocol->GetPreqReceivers (m_ifIndex);
+  for(std::vector<Mac48Address>::const_iterator i = receivers.begin (); i != receivers.end (); i ++)
+  {
+    hdr.SetAddr1 (*i);
+    m_stats.sentPreq ++;
+    m_stats.sentMgt ++;
+    m_stats.sentMgtBytes += packet->GetSize ();
+    m_parent->SendManagementFrame(packet, hdr);
+  }
+  //erase queue
+  m_preqQueue.erase (m_preqQueue.begin());
+}
+void
+HwmpMacPlugin::SendOnePerr()
+{
+  if(m_perrTimer.IsRunning ())
+    return;
+  if(m_myPerr.receivers.size () >= m_protocol->GetUnicastPerrThreshold ())
+  {
+    m_myPerr.receivers.clear ();
+    m_myPerr.receivers.push_back (Mac48Address::GetBroadcast ());
+  }
+  m_perrTimer = Simulator::Schedule (m_protocol->GetPerrMinInterval (), &HwmpMacPlugin::SendOnePerr, this);
+//Create packet
+  Ptr<Packet> packet  = Create<Packet> ();
+  packet->AddHeader(m_myPerr.perr);
+  //Action header:
+  WifiMeshActionHeader actionHdr;
+  WifiMeshActionHeader::ActionValue action;
+  action.pathSelection = WifiMeshActionHeader::PATH_ERROR;
+  actionHdr.SetAction (WifiMeshActionHeader::MESH_PATH_SELECTION, action);
+  packet->AddHeader (actionHdr);
+  //create 802.11 header:
+  WifiMacHeader hdr;
+  hdr.SetAction ();
+  hdr.SetDsNotFrom ();
+  hdr.SetDsNotTo ();
+  hdr.SetAddr2 (m_parent->GetAddress ());
+  hdr.SetAddr3 (m_protocol->GetAddress ());
+  //Send Management frame
+  for(std::vector<Mac48Address>::const_iterator i = m_myPerr.receivers.begin (); i != m_myPerr.receivers.end (); i ++)
+  {
+    hdr.SetAddr1 (*i);
+    m_stats.sentPerr ++;
+    m_stats.sentMgt ++;
+    m_stats.sentMgtBytes += packet->GetSize ();
+    m_parent->SendManagementFrame(packet, hdr);
+  }
+  m_myPerr.perr.ResetPerr ();
+  m_myPerr.receivers.clear ();
+}
+void
+HwmpMacPlugin::SendPrep (IePrep prep, Mac48Address receiver)
+{
+  //Create packet
+  Ptr<Packet> packet  = Create<Packet> ();
+  packet->AddHeader(prep);
+  //Action header:
+  WifiMeshActionHeader actionHdr;
+  WifiMeshActionHeader::ActionValue action;
+  action.pathSelection = WifiMeshActionHeader::PATH_REPLY;
+  actionHdr.SetAction (WifiMeshActionHeader::MESH_PATH_SELECTION, action);
+  packet->AddHeader (actionHdr);
+  //create 802.11 header:
+  WifiMacHeader hdr;
+  hdr.SetAction ();
+  hdr.SetDsNotFrom ();
+  hdr.SetDsNotTo ();
+  hdr.SetAddr1 (receiver);
+  hdr.SetAddr2 (m_parent->GetAddress ());
+  hdr.SetAddr3 (m_protocol->GetAddress ());
+  //Send Management frame
+  m_stats.sentPrep ++;
+  m_stats.sentMgt ++;
+  m_stats.sentMgtBytes += packet->GetSize ();
+  m_parent->SendManagementFrame(packet, hdr);
+}
+void
+HwmpMacPlugin::SendPerr(IePerr perr, std::vector<Mac48Address> receivers)
+{
+  m_myPerr.perr.Merge(perr);
+  for(unsigned int i = 0; i < receivers.size (); i ++)
+  {
+    bool should_add = true;
+    for (unsigned int j = 0; j < m_myPerr.receivers.size (); j ++)
+      if(receivers[j] == m_myPerr.receivers[i])
+        should_add = false;
+    if(should_add)
+      m_myPerr.receivers.push_back(receivers[i]);
+  }
+  SendOnePerr ();
+}
+uint32_t
+HwmpMacPlugin::GetLinkMetric(Mac48Address peerAddress) const
+{
+  return m_parent->GetLinkMetric(peerAddress);
+}
+uint16_t
+HwmpMacPlugin::GetChannelId () const
+{
+  return m_parent->GetFrequencyChannel ();
+}
+void
+HwmpMacPlugin::Statistics::Print (std::ostream & os) const
+{
+  os << "<Statistics "
+    "sentPreq= \"" << sentPreq << "\"\n"
+    "sentPrep=\"" << sentPrep << "\"\n"
+    "sentPerr=\"" << sentPerr << "\"\n"
+    "recvPreq=\"" << recvPreq << "\"\n"
+    "recvPrep=\"" << recvPrep << "\"\n"
+    "recvPerr=\"" << recvPerr << "\"\n"
+    "sentMgt=\"" << sentMgt << "\"\n"
+    "sentMgtBytes=\"" << (double)sentMgtBytes  / 1024.0 << "K\"\n"
+    "recvMgt=\"" << recvMgt << "\"\n"
+    "recvMgtBytes=\"" << (double)recvMgtBytes / 1204.0 << "K\"\n"
+    "sentData=\"" << sentData << "\"\n"
+    "sentDataBytes=\"" << (double)sentDataBytes / 1024.0 << "K\"\n"
+    "recvData=\"" << recvData << "\"\n"
+    "recvDataBytes=\"" << (double)recvDataBytes / 1024.0 << "K\"/>\n";
+}
+void
+HwmpMacPlugin::Report (std::ostream & os) const
+{
+  os << "<HwmpMacPlugin\n"
+    "address =\""<< m_parent->GetAddress () <<"\">\n";
+  m_stats.Print(os);
+  os << "</HwmpMacPlugin>\n";
+}
+void
+HwmpMacPlugin::ResetStats ()
+{
+  m_stats = Statistics::Statistics ();
+}
+
+} //namespace dot11s
+}//namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/hwmp-mac-plugin.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,144 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#ifndef HWMP_STATE_H
+#define HWMP_STATE_H
+
+#include "ns3/mesh-wifi-interface-mac-plugin.h"
+#include "ie-dot11s-perr.h"
+
+namespace ns3 {
+
+class MeshWifiInterfaceMac;
+
+namespace dot11s {
+
+class HwmpProtocol;
+class IePreq;
+class IePrep;
+class IePerr;
+
+/**
+ * \ingroup dot11s
+ * 
+ * \brief Interface MAC plugin for HWMP -- 802.11s routing protocol
+ */
+class HwmpMacPlugin : public MeshWifiInterfaceMacPlugin
+{
+public:
+  HwmpMacPlugin (uint32_t, Ptr<HwmpProtocol>);
+  ~HwmpMacPlugin ();
+  ///\name Inherited from MAC plugin
+  //\{
+  void SetParent (Ptr<MeshWifiInterfaceMac> parent);
+  bool Receive (Ptr<Packet> packet, const WifiMacHeader & header);
+  bool UpdateOutcomingFrame (Ptr<Packet> packet, WifiMacHeader & header, Mac48Address from, Mac48Address to);
+  /// Update beacon is empty, because HWMP does not know anything about beacons
+  void UpdateBeacon (MeshWifiBeacon & beacon) const {};
+  //\}
+  
+private:
+  friend class HwmpProtocol;
+  
+  ///\name Intercation with HWMP:
+  //\{
+  void SendPreq(IePreq preq);
+  void SendPrep(IePrep prep, Mac48Address receiver);
+  void SendPerr(IePerr perr, std::vector<Mac48Address> receivers);
+  ///\brief Request a destination. If can not send preq immediately -
+  //add a destination to exisying PREQ generated by me and stored in
+  //PREQ queue
+  ///\param originator_seqno is a sequence number that shall be preq
+  //originator sequenece number
+  ///\param dst_seqno is a sequence number taken from routing table
+  void RequestDestination (Mac48Address dest, uint32_t originator_seqno, uint32_t dst_seqno);
+  //\}
+  
+  /// Sends one PREQ when PreqMinInterval after last PREQ expires (if any PREQ exists in rhe queue)
+  void SendOnePreq ();
+  void SendOnePerr ();
+  /// \return metric to HWMP protocol, needed only by metrics to add
+  //peer as routing entry
+  uint32_t GetLinkMetric (Mac48Address peerAddress) const;
+  uint16_t GetChannelId () const;
+  ///\brief Statistics:
+  void Report (std::ostream &) const;
+  void ResetStats ();
+private:
+  Ptr<MeshWifiInterfaceMac> m_parent;
+  uint32_t m_ifIndex;
+  Ptr<HwmpProtocol> m_protocol;
+  
+  ///\name PREQ queue and PREQ timer:
+  //\{
+  EventId  m_preqTimer;
+  std::vector<IePreq>  m_preqQueue;
+  //\}
+  ///\name PERR timer and stored path error
+  //{
+  EventId m_perrTimer;
+  struct MyPerr {
+    IePerr perr;
+    std::vector<Mac48Address> receivers;
+  };
+  MyPerr m_myPerr;
+  ///\name Statistics:
+  ///\{
+  struct Statistics
+  {
+    uint16_t sentPreq;
+    uint16_t recvPreq;
+    uint16_t sentPrep;
+    uint16_t recvPrep;
+    uint16_t sentPerr;
+    uint16_t recvPerr;
+    uint16_t sentMgt;
+    uint32_t sentMgtBytes;
+    uint16_t recvMgt;
+    uint32_t recvMgtBytes;
+    uint16_t sentData;
+    uint32_t sentDataBytes;
+    uint16_t recvData;
+    uint32_t recvDataBytes;
+    void Print (std::ostream & os) const;
+    Statistics () : 
+      sentPreq (0), 
+      recvPreq (0),
+      sentPrep (0),
+      recvPrep (0),
+      sentPerr (0),
+      recvPerr (0),
+      sentMgt (0),
+      sentMgtBytes (0),
+      recvMgt (0),
+      recvMgtBytes (0),
+      sentData (0),
+      sentDataBytes (0),
+      recvData (0),
+      recvDataBytes (0)
+      {}
+  };
+  Statistics m_stats;
+  ///\}
+};
+} //namespace dot11s
+} //namespace ns3
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/hwmp-protocol.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,986 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#include "hwmp-protocol.h"
+#include "hwmp-mac-plugin.h"
+#include "hwmp-tag.h"
+#include "hwmp-rtable.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/packet.h"
+#include "ns3/mesh-point-device.h"
+#include "ns3/wifi-net-device.h"
+#include "ns3/mesh-point-device.h"
+#include "ns3/mesh-wifi-interface-mac.h"
+#include "ns3/random-variable.h"
+#include "ie-dot11s-preq.h"
+#include "ie-dot11s-prep.h"
+#include "ie-dot11s-perr.h"
+
+NS_LOG_COMPONENT_DEFINE ("HwmpProtocol");
+
+namespace ns3 {
+namespace dot11s {
+
+NS_OBJECT_ENSURE_REGISTERED (HwmpProtocol);
+TypeId
+HwmpProtocol::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::dot11s::HwmpProtocol")
+    .SetParent<MeshL2RoutingProtocol> ()
+    .AddConstructor<HwmpProtocol> ()
+    .AddAttribute ("RandomStart", "Random delay at first proactive PREQ",
+        TimeValue (Seconds (0.1)),
+        MakeTimeAccessor (&HwmpProtocol::m_randomStart),
+        MakeTimeChecker ()
+        )
+    .AddAttribute ("maxQueueSize",
+        "Maximum number of packets we can store when resolving route",
+        UintegerValue (255),
+        MakeUintegerAccessor (&HwmpProtocol::m_maxQueueSize),
+        MakeUintegerChecker<uint16_t> (1)
+        )
+    .AddAttribute ("dot11MeshHWMPmaxPREQretries",
+        "Maximum number of retries before we suppose the destination to be unreachable",
+        UintegerValue (3),
+        MakeUintegerAccessor (&HwmpProtocol::m_dot11MeshHWMPmaxPREQretries),
+        MakeUintegerChecker<uint8_t> (1)
+        )
+    .AddAttribute ("dot11MeshHWMPnetDiameterTraversalTime",
+        "Time we suppose the packet to go from one edge of the network to another",
+        TimeValue (MicroSeconds (1024*100)),
+        MakeTimeAccessor (&HwmpProtocol::m_dot11MeshHWMPnetDiameterTraversalTime),
+        MakeTimeChecker ()
+        )
+    .AddAttribute ("dot11MeshHWMPpreqMinInterval",
+        "Minimal interval between to successive PREQs",
+        TimeValue (MicroSeconds (1024*100)),
+        MakeTimeAccessor (&HwmpProtocol::m_dot11MeshHWMPpreqMinInterval),
+        MakeTimeChecker ()
+        )
+    .AddAttribute ("dot11MeshHWMPperrMinInterval",
+        "Minimal interval between to successive PREQs",
+        TimeValue (MicroSeconds (1024*100)),
+        MakeTimeAccessor (&HwmpProtocol::m_dot11MeshHWMPperrMinInterval),
+        MakeTimeChecker ()
+        )
+    .AddAttribute ("dot11MeshHWMPactiveRootTimeout",
+        "Lifetime of poractive routing information",
+        TimeValue (MicroSeconds (1024*5000)),
+        MakeTimeAccessor (&HwmpProtocol::m_dot11MeshHWMPactiveRootTimeout),
+        MakeTimeChecker ()
+        )
+    .AddAttribute ("dot11MeshHWMPactivePathTimeout",
+        "Lifetime of reactive routing information",
+        TimeValue (MicroSeconds (1024*5000)),
+        MakeTimeAccessor (&HwmpProtocol::m_dot11MeshHWMPactivePathTimeout),
+        MakeTimeChecker ()
+        )
+    .AddAttribute ("dot11MeshHWMPpathToRootInterval",
+        "Interval between two successive proactive PREQs",
+        TimeValue (MicroSeconds (1024*2000)),
+        MakeTimeAccessor (&HwmpProtocol::m_dot11MeshHWMPpathToRootInterval),
+        MakeTimeChecker ()
+        )
+    .AddAttribute ("dot11MeshHWMPrannInterval",
+        "Lifetime of poractive routing information",
+        TimeValue (MicroSeconds (1024*5000)),
+        MakeTimeAccessor (&HwmpProtocol::m_dot11MeshHWMPrannInterval),
+        MakeTimeChecker ()
+        )
+    .AddAttribute ("maxTtl",
+        "Initial value of Time To Live field",
+        UintegerValue (32),
+        MakeUintegerAccessor (&HwmpProtocol::m_maxTtl),
+        MakeUintegerChecker<uint8_t> (2)
+        )
+    .AddAttribute ("unicastPerrThreshold",
+        "Maximum number of PERR receivers, when we send a PERR as a chain of unicasts",
+        UintegerValue (32),
+        MakeUintegerAccessor (&HwmpProtocol::m_unicastPerrThreshold),
+        MakeUintegerChecker<uint8_t> (1)
+        )
+    .AddAttribute ("unicastPreqThreshold",
+        "Maximum number of PREQ receivers, when we send a PREQ as a chain of unicasts",
+        UintegerValue (1),
+        MakeUintegerAccessor (&HwmpProtocol::m_unicastPreqThreshold),
+        MakeUintegerChecker<uint8_t> (1)
+        )
+    .AddAttribute ("unicastDataThreshold",
+        "Maximum number ofbroadcast receivers, when we send a broadcast as a chain of unicasts",
+        UintegerValue (1),
+        MakeUintegerAccessor (&HwmpProtocol::m_unicastDataThreshold),
+        MakeUintegerChecker<uint8_t> (1)
+        )
+    .AddAttribute ("doFlag",
+        "Destination only HWMP flag",
+        BooleanValue (false),
+        MakeUintegerAccessor (&HwmpProtocol::m_doFlag),
+        MakeUintegerChecker<bool> ()
+        )
+    .AddAttribute ("rfFlag",
+        "Reply and forward flag",
+        BooleanValue (true),
+        MakeUintegerAccessor (&HwmpProtocol::m_rfFlag),
+        MakeUintegerChecker<bool> ()
+        );
+  return tid;
+}
+HwmpProtocol::HwmpProtocol ():
+    m_dataSeqno (1),
+    m_hwmpSeqno (1),
+    m_preqId (0),
+    m_rtable (CreateObject<HwmpRtable> ()),
+    m_randomStart(Seconds (0.1)),
+    m_maxQueueSize (255),
+    m_dot11MeshHWMPmaxPREQretries (3),
+    m_dot11MeshHWMPnetDiameterTraversalTime (MicroSeconds (1024*100)),
+    m_dot11MeshHWMPpreqMinInterval (MicroSeconds (1024*100)),
+    m_dot11MeshHWMPperrMinInterval (MicroSeconds (1024*100)),
+    m_dot11MeshHWMPactiveRootTimeout (MicroSeconds (1024*5000)),
+    m_dot11MeshHWMPactivePathTimeout (MicroSeconds (1024*5000)),
+    m_dot11MeshHWMPpathToRootInterval (MicroSeconds (1024*2000)),
+    m_dot11MeshHWMPrannInterval (MicroSeconds (1024*5000)),
+    m_isRoot (false),
+    m_maxTtl (32),
+    m_unicastPerrThreshold (32),
+    m_unicastPreqThreshold (1),
+    m_unicastDataThreshold (1),
+    m_doFlag (false),
+    m_rfFlag (false)
+{
+  if(m_isRoot)
+    SetRoot ();
+}
+
+HwmpProtocol::~HwmpProtocol ()
+{
+}
+
+void
+HwmpProtocol::DoDispose ()
+{
+  for (std::map<Mac48Address, EventId>::iterator i = m_preqTimeouts.begin (); i != m_preqTimeouts.end(); i ++)
+    i->second.Cancel ();
+  m_preqTimeouts.clear ();
+  m_lastDataSeqno.clear ();
+  m_lastHwmpSeqno.clear ();
+  m_rqueue.clear ();
+  m_rtable = 0;
+
+  //TODO: clear plugins
+}
+
+bool
+HwmpProtocol::RequestRoute (
+  uint32_t sourceIface,
+  const Mac48Address source,
+  const Mac48Address destination,
+  Ptr<Packet> packet,
+  uint16_t protocolType, //ethrnet 'Protocol' field
+  MeshL2RoutingProtocol::RouteReplyCallback routeReply
+)
+{
+  HwmpTag tag;
+  if (sourceIface == GetMeshPoint ()->GetIfIndex())
+    // packet from level 3
+  {
+    if(packet->PeekPacketTag(tag))
+    {
+      NS_ASSERT (false);
+    }
+    //Filling TAG:
+    if(destination == Mac48Address::GetBroadcast ())
+      tag.SetSeqno (m_dataSeqno++);
+    tag.SetTtl (m_maxTtl+1);
+  }
+  else
+  {
+    if(!packet->RemovePacketTag(tag))
+    {
+      NS_ASSERT(false);
+      return false;
+    }
+    if (tag.GetTtl () == 0)
+      return false;
+    tag.DecrementTtl ();
+  }
+  if (destination == Mac48Address::GetBroadcast ())
+  {
+    m_stats.forwardedBroadcast ++;
+    m_stats.forwardedBytes += packet->GetSize ();
+    //channel IDs where we have already sent broadcast:
+    std::vector<uint16_t> channels;
+    for(HwmpPluginMap::const_iterator plugin = m_interfaces.begin (); plugin != m_interfaces.end (); plugin ++)
+    {
+      bool should_send = true;
+      for(std::vector<uint16_t>::const_iterator chan = channels.begin(); chan != channels.end(); chan ++)
+        if(*chan == plugin->second->GetChannelId ())
+          should_send = false;
+      if(!should_send)
+        continue;
+      channels.push_back(plugin->second->GetChannelId ());
+      std::vector<Mac48Address> receivers = GetBroadcastReceivers (plugin->first);
+      for (std::vector<Mac48Address>::const_iterator i = receivers.begin (); i != receivers.end(); i ++)
+      {
+        Ptr<Packet> packet_copy = packet->Copy();
+        tag.SetAddress (*i);
+        packet_copy->AddPacketTag (tag);
+        routeReply (true, packet_copy, source, destination, protocolType, plugin->first);
+      }
+    }
+  }
+  else
+    return ForwardUnicast(sourceIface, source, destination, packet, protocolType, routeReply, tag.GetTtl ());
+  return true;
+}
+bool
+HwmpProtocol::ForwardUnicast(uint32_t  sourceIface, const Mac48Address source, const Mac48Address destination,
+    Ptr<Packet>  packet, uint16_t  protocolType, RouteReplyCallback  routeReply, uint32_t ttl)
+{
+  NS_ASSERT(destination != Mac48Address::GetBroadcast ());
+  HwmpRtable::LookupResult result = m_rtable->LookupReactive(destination);
+  NS_LOG_DEBUG("Requested src = "<<source<<", dst = "<<destination<<", I am "<<GetAddress ()<<", RA = "<<result.retransmitter);
+  if(result.retransmitter == Mac48Address::GetBroadcast ())
+    result = m_rtable->LookupProactive ();
+  HwmpTag tag;
+  tag.SetAddress (result.retransmitter);
+  tag.SetTtl (ttl);
+    //seqno and metric is not used;
+  packet->AddPacketTag(tag);
+  if(result.retransmitter != Mac48Address::GetBroadcast ())
+  {
+    //reply immediately:
+    routeReply (true, packet, source, destination, protocolType, result.ifIndex);
+    m_stats.forwardedUnicast ++;
+    m_stats.forwardedBytes += packet->GetSize ();
+    return true;
+  }
+  if (sourceIface != GetMeshPoint ()->GetIfIndex())
+  {
+    //Start path error procedure:
+    NS_LOG_DEBUG ("Must Send PERR");
+    result = m_rtable->LookupReactiveExpired (destination);
+    //1.  Lookup expired reactive path. If exists - start path error
+    //    procedure towards a next hop of this path
+    //2.  If there was no reactive path, we lookup expired proactive
+    //    path. If exist - start path error procedure towards path to
+    //    root
+    if(result.retransmitter == Mac48Address::GetBroadcast ())
+      result = m_rtable->LookupProactiveExpired ();
+    if(result.retransmitter != Mac48Address::GetBroadcast ())
+    {
+      std::vector<IePerr::FailedDestination> destinations = m_rtable->GetUnreachableDestinations (result.retransmitter);
+      MakePathError (destinations);
+    }
+    m_stats.totalDropped ++;
+    return false;
+  }
+  //Request a destination:
+  result = m_rtable->LookupReactiveExpired (destination);
+  if(ShouldSendPreq(destination))
+  {
+    uint32_t originator_seqno = GetNextHwmpSeqno ();
+    uint32_t dst_seqno = 0;
+    if(result.retransmitter != Mac48Address::GetBroadcast ())
+      dst_seqno = result.seqnum;
+    for(HwmpPluginMap::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i ++)
+      i->second->RequestDestination(destination, originator_seqno, dst_seqno);
+  }
+  QueuedPacket pkt;
+  pkt.pkt = packet;
+  pkt.dst = destination;
+  pkt.src = source;
+  pkt.protocol = protocolType;
+  pkt.reply = routeReply;
+  pkt.inInterface = sourceIface;
+  if(QueuePacket (pkt))
+  {
+    m_stats.totalQueued ++;
+    return true;
+  }
+  else
+  {
+    m_stats.totalDropped ++;
+    return false;
+  }
+}
+void
+HwmpProtocol::ReceivePreq (IePreq preq, Mac48Address from, uint32_t interface, Mac48Address fromMp, uint32_t metric)
+{
+  preq.IncrementMetric (metric);
+  //acceptance cretirea:
+  std::map<Mac48Address, uint32_t>::const_iterator i = m_lastHwmpSeqno.find (preq.GetOriginatorAddress());
+  if (i == m_lastHwmpSeqno.end ())
+    {
+      m_lastHwmpSeqno[preq.GetOriginatorAddress ()] = preq.GetOriginatorSeqNumber();
+      m_lastHwmpMetric[preq.GetOriginatorAddress ()] = preq.GetMetric();
+    }
+  else
+    {
+      if (i->second > preq.GetOriginatorSeqNumber ())
+        return;
+      if (i->second == preq.GetOriginatorSeqNumber ())
+      {
+        //find metric
+        std::map<Mac48Address, uint32_t>::const_iterator j = m_lastHwmpMetric.find (preq.GetOriginatorAddress());
+        NS_ASSERT (j != m_lastHwmpSeqno.end());
+        if (j->second <= preq.GetMetric ())
+          return;
+      }
+      m_lastHwmpSeqno[preq.GetOriginatorAddress ()] = preq.GetOriginatorSeqNumber();
+      m_lastHwmpMetric[preq.GetOriginatorAddress ()] = preq.GetMetric();
+    }
+  NS_LOG_DEBUG("I am "<<GetAddress ()<<"Accepted preq from address"<<from<<", preq:"<<preq);
+  std::vector<Ptr<DestinationAddressUnit> > destinations = preq.GetDestinationList ();
+  //Add reactive path to originator:
+  if (
+      ((m_rtable->LookupReactive(preq.GetOriginatorAddress ())).retransmitter == Mac48Address::GetBroadcast ()) ||
+      ((m_rtable->LookupReactive(preq.GetOriginatorAddress ())).metric > preq.GetMetric ())
+      )
+  {
+    m_rtable->AddReactivePath (
+        preq.GetOriginatorAddress (),
+        from,
+        interface,
+        preq.GetMetric (),
+        MicroSeconds (preq.GetLifetime () *1024),
+        preq.GetOriginatorSeqNumber ()
+        );
+    ReactivePathResolved (preq.GetOriginatorAddress ());
+  }
+  //Add reactive path for precursor:
+  if (
+      ((m_rtable->LookupReactive(fromMp)).retransmitter == Mac48Address::GetBroadcast ()) ||
+      ((m_rtable->LookupReactive(fromMp)).metric > preq.GetMetric ())
+      )
+  {
+    m_rtable->AddReactivePath (
+        fromMp,
+        from,
+        interface,
+        metric,
+        MicroSeconds (preq.GetLifetime () *1024),
+        preq.GetOriginatorSeqNumber ()
+        );
+    ReactivePathResolved (fromMp);
+  }
+  for (std::vector<Ptr<DestinationAddressUnit> >::const_iterator i = destinations.begin (); i != destinations.end(); i++)
+    {
+      if ((*i)->GetDestinationAddress () == Mac48Address::GetBroadcast())
+        {
+          //only proactive PREQ contains destination
+          //address as broadcast! Proactive preq MUST
+          //have destination count equal to 1 and
+          //per destination flags DO and RF
+          NS_ASSERT (preq.GetDestCount() == 1);
+          NS_ASSERT (((*i)->IsDo()) && ((*i)->IsRf()));
+          //Add proactive path only if it is the better then existed
+          //before
+          if(
+              ((m_rtable->LookupProactive ()).retransmitter == Mac48Address::GetBroadcast ()) ||
+              ((m_rtable->LookupProactive ()).metric > preq.GetMetric ())
+            )
+            m_rtable->AddProactivePath (
+                preq.GetMetric (),
+                preq.GetOriginatorAddress (),
+                from,
+                interface,
+                MicroSeconds (preq.GetLifetime () * 1024),
+                preq.GetOriginatorSeqNumber ()
+                );
+          ProactivePathResolved ();
+          if (!preq.IsNeedNotPrep ())
+              SendPrep (
+                  GetAddress (),
+                  preq.GetOriginatorAddress (),
+                  from,
+                  preq.GetMetric (),
+                  preq.GetOriginatorSeqNumber (),
+                  GetNextHwmpSeqno (),
+                  preq.GetLifetime (),
+                  interface
+              );
+          break;
+        }
+      if ((*i)->GetDestinationAddress () == GetAddress ())
+        {
+          SendPrep (
+              GetAddress (),
+              preq.GetOriginatorAddress (),
+              from,
+              (uint32_t)0,
+              preq.GetOriginatorSeqNumber (),
+              GetNextHwmpSeqno (),
+              preq.GetLifetime (),
+              interface
+          );
+          NS_ASSERT(m_rtable->LookupReactive (preq.GetOriginatorAddress ()).retransmitter != Mac48Address::GetBroadcast ());
+          preq.DelDestinationAddressElement ((*i)->GetDestinationAddress());
+          continue;
+        }
+      //check if can answer:
+      HwmpRtable::LookupResult result = m_rtable->LookupReactive ((*i)->GetDestinationAddress());
+      if ((! ((*i)->IsDo())) && (result.retransmitter != Mac48Address::GetBroadcast()))
+        {
+          //have a valid information and can answer
+          //!NB: If there is information from peer - set lifetime as
+          //we have got from PREQ, and set the rest lifetime of the
+          //route if the information is correct
+          uint32_t lifetime = result.lifetime.GetMicroSeconds () / 1024;
+          if(lifetime > 0)
+            SendPrep (
+                (*i)->GetDestinationAddress (),
+                preq.GetOriginatorAddress (),
+                from,
+                result.metric,
+                preq.GetOriginatorSeqNumber (),
+                result.seqnum +1,
+                lifetime,
+                interface
+                );
+          if ((*i)->IsRf ())
+            (*i)->SetFlags (true, false, (*i)->IsUsn ()); //DO = 1, RF = 0
+          else
+            {
+              preq.DelDestinationAddressElement ((*i)->GetDestinationAddress());
+              continue;
+            }
+        }
+    }
+  //chack if must retransmit:
+  if (preq.GetDestCount () == 0)
+    return;
+  //Forward PREQ to all interfaces:
+  NS_LOG_DEBUG("I am "<<GetAddress ()<<"retransmitting PREQ:"<<preq);
+  for(HwmpPluginMap::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i ++)
+    i->second->SendPreq (preq);
+}
+void
+HwmpProtocol::ReceivePrep (IePrep prep, Mac48Address from, uint32_t interface, Mac48Address fromMp, uint32_t metric)
+{
+  prep.IncrementMetric (metric);
+  //acceptance cretirea:
+  std::map<Mac48Address, uint32_t>::const_iterator i = m_lastHwmpSeqno.find (prep.GetOriginatorAddress());
+  if (i == m_lastHwmpSeqno.end ())
+    {
+      m_lastHwmpSeqno[prep.GetOriginatorAddress ()] = prep.GetOriginatorSeqNumber();
+    }
+  else
+  {
+    if (i->second > prep.GetOriginatorSeqNumber ())
+      return;
+    else
+      m_lastHwmpSeqno[prep.GetOriginatorAddress ()] = prep.GetOriginatorSeqNumber();
+  }
+  //update routing info
+  //Now add a path to destination and add precursor to source
+  NS_LOG_DEBUG("I am "<<GetAddress ()<<", received prep from "<<prep.GetOriginatorAddress ()<<", receiver was:"<<from);
+  HwmpRtable::LookupResult result = m_rtable->LookupReactive(prep.GetDestinationAddress());
+  //Add a reactive path only if it is better than existing:
+  if (
+      ((m_rtable->LookupReactive(prep.GetOriginatorAddress ())).retransmitter == Mac48Address::GetBroadcast ()) ||
+      ((m_rtable->LookupReactive(prep.GetOriginatorAddress ())).metric > prep.GetMetric ())
+      )
+  {
+    m_rtable->AddReactivePath (
+        prep.GetOriginatorAddress (),
+        from,
+        interface,
+        prep.GetMetric (),
+        MicroSeconds(prep.GetLifetime () * 1024),
+        prep.GetOriginatorSeqNumber ());
+    m_rtable->AddPrecursor (prep.GetDestinationAddress (), interface, from);
+    if(result.retransmitter != Mac48Address::GetBroadcast ())
+      m_rtable->AddPrecursor (prep.GetOriginatorAddress (), interface, result.retransmitter);
+    ReactivePathResolved (prep.GetOriginatorAddress ());
+  }
+  if (
+      ((m_rtable->LookupReactive(fromMp)).retransmitter == Mac48Address::GetBroadcast ()) ||
+      ((m_rtable->LookupReactive(fromMp)).metric > prep.GetMetric ())
+      )
+  {
+    m_rtable->AddReactivePath (
+        fromMp,
+        from,
+        interface,
+        metric,
+        MicroSeconds(prep.GetLifetime () * 1024),
+        prep.GetOriginatorSeqNumber ());
+    ReactivePathResolved (fromMp);
+  }
+  if(prep.GetDestinationAddress () == GetAddress ())
+  {
+    NS_LOG_DEBUG("I am "<<GetAddress ()<<", resolved "<<prep.GetOriginatorAddress ());
+    return;
+  }
+  if (result.retransmitter == Mac48Address::GetBroadcast ())
+    //try to look for default route
+    result = m_rtable->LookupProactive ();
+  if (result.retransmitter == Mac48Address::GetBroadcast ())
+    return;
+  //Forward PREP
+  HwmpPluginMap::const_iterator prep_sender = m_interfaces.find (result.ifIndex);
+  NS_ASSERT(prep_sender != m_interfaces.end ());
+  prep_sender->second->SendPrep (prep, result.retransmitter);
+}
+void
+HwmpProtocol::ReceivePerr (IePerr perr, Mac48Address from, uint32_t interface, Mac48Address fromMp)
+{
+  //Acceptance cretirea:
+  NS_LOG_DEBUG("I am "<<GetAddress ()<<", received PERR from "<<from);
+  std::vector<IePerr::FailedDestination> destinations = perr.GetAddressUnitVector ();
+  HwmpRtable::LookupResult result;
+  for(unsigned int i = 0; i < destinations.size (); i ++)
+  {
+    result = m_rtable->LookupReactive (destinations[i].destination);
+    if (
+        (result.retransmitter != from) ||
+        (result.ifIndex != interface) ||
+        (result.seqnum > destinations[i].seqnum)
+        )
+    {
+      perr.DeleteAddressUnit(destinations[i].destination);
+      continue;
+    }
+  }
+  if(perr.GetNumOfDest () == 0)
+    return;
+  MakePathError (destinations);
+}
+void
+HwmpProtocol::SendPrep (
+    Mac48Address src,
+    Mac48Address dst,
+    Mac48Address retransmitter,
+    uint32_t initMetric,
+    uint32_t originatorDsn,
+    uint32_t destinationSN,
+    uint32_t lifetime,
+    uint32_t interface)
+{
+  IePrep prep;
+  prep.SetHopcount (0);
+  prep.SetTtl (m_maxTtl);
+  prep.SetDestinationAddress (dst);
+  prep.SetDestinationSeqNumber (destinationSN);
+  prep.SetLifetime (lifetime);
+  prep.SetMetric (0);
+  prep.SetOriginatorAddress (src);
+  prep.SetOriginatorSeqNumber (originatorDsn);
+  HwmpPluginMap::const_iterator prep_sender = m_interfaces.find (interface);
+  NS_ASSERT(prep_sender != m_interfaces.end ());
+  prep_sender->second->SendPrep (prep, retransmitter);
+  //m_prepCallback (prep, retransmitter);
+
+}
+bool
+HwmpProtocol::Install (Ptr<MeshPointDevice> mp)
+{
+  m_mp = mp;
+  std::vector<Ptr<NetDevice> > interfaces = mp->GetInterfaces ();
+  for (std::vector<Ptr<NetDevice> >::const_iterator i = interfaces.begin (); i != interfaces.end(); i++)
+    {
+      // Checking for compatible net device
+      Ptr<WifiNetDevice> wifiNetDev = (*i)->GetObject<WifiNetDevice> ();
+      if (wifiNetDev == 0)
+        return false;
+      Ptr<MeshWifiInterfaceMac>  mac = wifiNetDev->GetMac ()->GetObject<MeshWifiInterfaceMac> ();
+      if (mac == 0)
+        return false;
+      // Installing plugins:
+      Ptr<HwmpMacPlugin> hwmpMac = Create<HwmpMacPlugin> (wifiNetDev->GetIfIndex (), this);
+      m_interfaces[wifiNetDev->GetIfIndex ()] = hwmpMac;
+      mac->InstallPlugin (hwmpMac);
+    }
+  mp->SetRoutingProtocol (this);
+  // Mesh point aggregates all installed protocols
+  mp->AggregateObject (this);
+  m_address = Mac48Address::ConvertFrom (mp->GetAddress ());//* address;
+  return true;
+}
+void
+HwmpProtocol::PeerLinkStatus(Mac48Address meshPointAddress, Mac48Address peerAddress, uint32_t interface, bool status)
+{
+  if(status)
+    return;
+  std::vector<IePerr::FailedDestination> destinations = m_rtable->GetUnreachableDestinations (peerAddress);
+  MakePathError (destinations);
+}
+void
+HwmpProtocol::SetNeighboursCallback(Callback<std::vector<Mac48Address>, uint32_t> cb)
+{
+  m_neighboursCallback = cb;
+}
+bool
+HwmpProtocol::DropDataFrame(uint32_t seqno, Mac48Address source)
+{
+  std::map<Mac48Address, uint32_t,std::less<Mac48Address> >::const_iterator i = m_lastDataSeqno.find (source);
+  if (i == m_lastDataSeqno.end ())
+    m_lastDataSeqno[source] = seqno;
+  else
+  {
+    if (i->second >= seqno)
+      return true;
+    m_lastDataSeqno[source] = seqno;
+  }
+  return false;
+}
+void
+HwmpProtocol::MakePathError (std::vector<IePerr::FailedDestination> destinations)
+{
+  //HwmpRtable increments a sequence number as written in 11B.9.7.2
+  std::vector<std::pair<uint32_t, Mac48Address> > receivers = GetPerrReceivers (destinations);
+  if(receivers.size () == 0)
+    return;
+  IePerr perr;
+  for(unsigned int i = 0; i < destinations.size (); i ++)
+  {
+    perr.AddAddressUnit(destinations[i]);
+    m_rtable->DeleteReactivePath(destinations[i].destination);
+  }
+  for(HwmpPluginMap::const_iterator i =  m_interfaces.begin (); i != m_interfaces.end (); i ++)
+  {
+    std::vector<Mac48Address> receivers_for_interface;
+    for(unsigned int j = 0; j < receivers.size(); j ++)
+      if(i->first == receivers[j].first)
+        receivers_for_interface.push_back(receivers[j].second);
+    i->second->SendPerr (perr, receivers_for_interface);
+  }
+}
+std::vector<std::pair<uint32_t, Mac48Address> >
+HwmpProtocol::GetPerrReceivers (std::vector<IePerr::FailedDestination> failedDest)
+{
+  HwmpRtable::PrecursorList retval;
+  for (unsigned int i = 0; i < failedDest.size (); i ++)
+  {
+    HwmpRtable::PrecursorList precursors = m_rtable->GetPrecursors(failedDest[i].destination);
+    m_rtable->DeleteReactivePath (failedDest[i].destination);
+    m_rtable->DeleteProactivePath(failedDest[i].destination);
+    for (unsigned int j = 0; j < precursors.size (); j ++)
+      retval.push_back(precursors[j]);
+  }
+  //Check if we have dublicates in retval and precursors:
+  for (unsigned int i = 0; i < retval.size(); i ++)
+    for (unsigned int j = i+1; j < retval.size(); j ++)
+      if(retval[i].second == retval[j].second)
+        retval.erase(retval.begin() + j);
+  return retval;
+}
+std::vector<Mac48Address>
+HwmpProtocol::GetPreqReceivers (uint32_t interface)
+{
+  std::vector<Mac48Address> retval;
+  if(!m_neighboursCallback.IsNull ())
+    retval = m_neighboursCallback (interface);
+  if ((retval.size() >= m_unicastPreqThreshold) || (retval.size () == 0))
+  {
+    retval.clear ();
+    retval.push_back (Mac48Address::GetBroadcast ());
+  }
+  return retval;
+}
+std::vector<Mac48Address>
+HwmpProtocol::GetBroadcastReceivers (uint32_t interface)
+{
+  std::vector<Mac48Address> retval;
+  if(!m_neighboursCallback.IsNull ())
+    retval = m_neighboursCallback (interface);
+  if ((retval.size() >= m_unicastDataThreshold) || (retval.size () == 0))
+  {
+    retval.clear ();
+    retval.push_back (Mac48Address::GetBroadcast ());
+  }
+  return retval;
+}
+
+bool
+HwmpProtocol::QueuePacket (QueuedPacket packet)
+{
+  if (m_rqueue.size () > m_maxQueueSize)
+    return false;
+  m_rqueue.push_back (packet);
+  return true;
+}
+
+HwmpProtocol::QueuedPacket
+HwmpProtocol::DequeueFirstPacketByDst (Mac48Address dst)
+{
+  QueuedPacket retval;
+  retval.pkt = NULL;
+  for(std::vector<QueuedPacket>::iterator i = m_rqueue.begin (); i != m_rqueue.end (); i++)
+    if((*i).dst == dst)
+    {
+      retval = (*i);
+      m_rqueue.erase (i);
+      break;
+    }
+  return retval;
+}
+
+HwmpProtocol::QueuedPacket
+HwmpProtocol::DequeueFirstPacket ()
+{
+  QueuedPacket retval;
+  retval.pkt = NULL;
+  if(m_rqueue.size () != 0)
+  {
+    retval = m_rqueue[0];
+    m_rqueue.erase (m_rqueue.begin ());
+  }
+  return retval;
+}
+
+void
+HwmpProtocol::ReactivePathResolved (Mac48Address dst)
+{
+  HwmpRtable::LookupResult result = m_rtable->LookupReactive (dst);
+  NS_ASSERT(result.retransmitter != Mac48Address::GetBroadcast ());
+  //Send all packets stored for this destination    
+  QueuedPacket packet;
+  while (1)
+  {
+    packet = DequeueFirstPacketByDst (dst);
+    if (packet.pkt == NULL)
+      return;
+    //set RA tag for retransmitter:
+    HwmpTag tag;
+    packet.pkt->RemovePacketTag(tag);
+    tag.SetAddress (result.retransmitter);
+    packet.pkt->AddPacketTag (tag);
+    m_stats.forwardedUnicast ++;
+    m_stats.forwardedBytes += packet.pkt->GetSize ();
+    packet.reply (true, packet.pkt, packet.src, packet.dst, packet.protocol, result.ifIndex);
+  }
+}
+void
+HwmpProtocol::ProactivePathResolved ()
+{
+  //send all packets to root
+  HwmpRtable::LookupResult result = m_rtable->LookupProactive ();
+  NS_ASSERT(result.retransmitter != Mac48Address::GetBroadcast ());
+  QueuedPacket packet;
+  while (1)
+  {
+    packet = DequeueFirstPacket ();
+    if (packet.pkt == NULL)
+      return;
+    //set RA tag for retransmitter:
+    HwmpTag tag;
+    NS_ASSERT (packet.pkt->PeekPacketTag(tag));
+    tag.SetAddress (result.retransmitter);
+    packet.pkt->AddPacketTag (tag);
+    m_stats.forwardedUnicast ++;
+    m_stats.forwardedBytes += packet.pkt->GetSize ();
+    packet.reply (true, packet.pkt, packet.src, packet.dst, packet.protocol, result.ifIndex);
+  }
+}
+
+bool
+HwmpProtocol::ShouldSendPreq (Mac48Address dst)
+{
+  std::map<Mac48Address, EventId>::const_iterator i = m_preqTimeouts.find (dst);
+  if (i == m_preqTimeouts.end ())
+    {
+      m_preqTimeouts[dst] = Simulator::Schedule (
+          MilliSeconds (2*(m_dot11MeshHWMPnetDiameterTraversalTime.GetMilliSeconds())),
+          &HwmpProtocol::RetryPathDiscovery, this, dst, 0);
+      return true;
+    }
+  return false;
+}
+void
+HwmpProtocol::RetryPathDiscovery (Mac48Address dst, uint8_t numOfRetry)
+{
+  HwmpRtable::LookupResult result = m_rtable->LookupReactive (dst);
+  if(result.retransmitter == Mac48Address::GetBroadcast ())
+    result = m_rtable->LookupProactive ();
+  if (result.retransmitter != Mac48Address::GetBroadcast ())
+    {
+      std::map<Mac48Address, EventId>::iterator i = m_preqTimeouts.find (dst);
+      NS_ASSERT (i !=  m_preqTimeouts.end());
+      m_preqTimeouts.erase (i);
+      return;
+    }
+  numOfRetry++;
+  if (numOfRetry > m_dot11MeshHWMPmaxPREQretries)
+    {
+      QueuedPacket packet;
+      //purge queue and delete entry from retryDatabase
+      while (1)
+        {
+          packet = DequeueFirstPacketByDst (dst);
+          if (packet.pkt == NULL)
+            break;
+          m_stats.totalDropped ++;
+          packet.reply (false, packet.pkt, packet.src, packet.dst, packet.protocol, HwmpRtable::MAX_METRIC);
+        }
+      std::map<Mac48Address, EventId>::iterator i = m_preqTimeouts.find (dst);
+      NS_ASSERT (i !=  m_preqTimeouts.end());
+      m_preqTimeouts.erase (i);
+      return;
+    }
+  uint32_t originator_seqno = GetNextHwmpSeqno ();
+  uint32_t dst_seqno = 0;
+  if(result.retransmitter != Mac48Address::GetBroadcast ())
+    dst_seqno = result.seqnum;
+  for(HwmpPluginMap::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i ++)
+    i->second->RequestDestination(dst, originator_seqno, dst_seqno);
+  m_preqTimeouts[dst] = Simulator::Schedule (
+      MilliSeconds (2*(m_dot11MeshHWMPnetDiameterTraversalTime.GetMilliSeconds())),
+      &HwmpProtocol::RetryPathDiscovery, this, dst, numOfRetry);
+}
+//Proactive PREQ routines:
+void
+HwmpProtocol::SetRoot ()
+{
+  UniformVariable coefficient (0.0, m_randomStart.GetSeconds());
+  Time randomStart = Seconds (coefficient.GetValue());
+  m_proactivePreqTimer = Simulator::Schedule (randomStart, &HwmpProtocol::SendProactivePreq, this);
+  NS_LOG_UNCOND("ROOT IS: "<<m_address);
+  SendProactivePreq ();
+  m_isRoot = true;
+}
+void
+HwmpProtocol::UnsetRoot ()
+{
+  m_proactivePreqTimer.Cancel ();
+}
+void
+HwmpProtocol::SendProactivePreq ()
+{
+  IePreq preq;
+  //By default: must answer
+  preq.SetHopcount (0);
+  preq.SetTTL (m_maxTtl);
+  preq.SetLifetime (m_dot11MeshHWMPactiveRootTimeout.GetMicroSeconds () /1024);
+  //\attention: do not forget to set originator address, sequence
+  //number and preq ID in HWMP-MAC plugin
+  preq.AddDestinationAddressElement (true, true, Mac48Address::GetBroadcast (), 0);
+  preq.SetOriginatorAddress(GetAddress ());
+  preq.SetPreqID (GetNextPreqId ());
+  preq.SetOriginatorSeqNumber (GetNextHwmpSeqno ());
+  for(HwmpPluginMap::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i ++)
+    i->second->SendPreq(preq);
+  m_proactivePreqTimer = Simulator::Schedule (m_dot11MeshHWMPpathToRootInterval, &HwmpProtocol::SendProactivePreq, this);
+}
+bool
+HwmpProtocol::GetDoFlag ()
+{
+  return m_doFlag;
+}
+bool
+HwmpProtocol::GetRfFlag ()
+{
+  return m_rfFlag;
+}
+Time
+HwmpProtocol::GetPreqMinInterval ()
+{
+  return m_dot11MeshHWMPpreqMinInterval;
+}
+Time
+HwmpProtocol::GetPerrMinInterval ()
+{
+  return m_dot11MeshHWMPperrMinInterval;
+}
+uint8_t
+HwmpProtocol::GetMaxTtl ()
+{
+  return m_maxTtl;
+}
+uint32_t
+HwmpProtocol::GetNextPreqId ()
+{
+  m_preqId ++;
+  return m_preqId;
+}
+uint32_t
+HwmpProtocol::GetNextHwmpSeqno ()
+{
+  m_hwmpSeqno ++;
+  if(m_hwmpSeqno == 0xffffffff)
+    m_hwmpSeqno = 1;
+  return m_hwmpSeqno;
+}
+uint32_t
+HwmpProtocol::GetActivePathLifetime ()
+{
+  return m_dot11MeshHWMPactivePathTimeout.GetMicroSeconds () / 1024;
+}
+uint8_t
+HwmpProtocol::GetUnicastPerrThreshold()
+{
+  return m_unicastPerrThreshold;
+}
+Mac48Address
+HwmpProtocol::GetAddress ()
+{
+  return m_address;
+}
+//Statistics:
+void HwmpProtocol::Statistics::Print (std::ostream & os) const
+{
+  os << "<Statistics "
+    "forwardedUnicast=\"" << forwardedUnicast << "\" "
+    "forwardedBroadcast=\"" << forwardedBroadcast << "\" "
+    "forwardedBytes=\"" << forwardedBytes / 1024 << "K\" "
+    "totalQueued=\"" << totalQueued << "\" "
+    "totalDropped=\"" << totalDropped << "\"/>\n";
+}
+void
+HwmpProtocol::Report (std::ostream & os) const
+{
+  os << "<Hwmp "
+    "address=\"" << m_address << "\"\n"
+    "maxQueueSize=\"" << m_maxQueueSize << "\"\n"
+    "dot11MeshHWMPmaxPREQretries=\"" << (uint16_t)m_dot11MeshHWMPmaxPREQretries << "\"\n"
+    "dot11MeshHWMPnetDiameterTraversalTime=\"" << m_dot11MeshHWMPnetDiameterTraversalTime.GetMilliSeconds () << "ms\"\n"
+    "dot11MeshHWMPpreqMinInterval=\"" << m_dot11MeshHWMPpreqMinInterval.GetMilliSeconds () << "ms\"\n"
+    "dot11MeshHWMPperrMinInterval=\"" << m_dot11MeshHWMPperrMinInterval.GetMilliSeconds () << "ms\"\n"
+    "dot11MeshHWMPactiveRootTimeout=\"" << m_dot11MeshHWMPactiveRootTimeout.GetMilliSeconds () << "ms\"\n"
+    "dot11MeshHWMPactivePathTimeout=\"" << m_dot11MeshHWMPactivePathTimeout.GetMilliSeconds () << "ms\"\n"
+    "dot11MeshHWMPpathToRootInterval=\"" << m_dot11MeshHWMPpathToRootInterval.GetMilliSeconds () << "ms\"\n"
+    "dot11MeshHWMPrannInterval=\"" << m_dot11MeshHWMPrannInterval.GetMilliSeconds () << "ms\"\n"
+    "isRoot=\"" << m_isRoot << "\"\n"
+    "maxTtl=\"" << (uint16_t)m_maxTtl << "\"\n"
+    "unicastPerrThreshold=\"" << (uint16_t)m_unicastPerrThreshold << "\"\n"
+    "unicastPreqThreshold=\"" << (uint16_t)m_unicastPreqThreshold << "\"\n"
+    "unicastDataThreshold=\"" << (uint16_t)m_unicastDataThreshold << "\"\n"
+    "doFlag=\"" << m_doFlag << "\"\n"
+    "rfFlag=\"" << m_rfFlag << "\">\n";
+  m_stats.Print (os);
+  for(HwmpPluginMap::const_iterator plugin = m_interfaces.begin (); plugin != m_interfaces.end (); plugin ++)
+  {
+    plugin->second->Report(os);
+  }
+  os << "</Hwmp>\n";
+}
+void
+HwmpProtocol::ResetStats ()
+{
+  m_stats = Statistics::Statistics ();
+  for(HwmpPluginMap::const_iterator plugin = m_interfaces.begin (); plugin != m_interfaces.end (); plugin ++)
+    plugin->second->ResetStats ();
+}
+
+} //namespace dot11s
+} //namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/hwmp-protocol.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,246 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#ifndef HWMP_PROTOCOL_H
+#define HWMP_PROTOCOL_H
+
+#include "ns3/mesh-l2-routing-protocol.h"
+#include "ns3/nstime.h"
+#include "ns3/ie-dot11s-perr.h"
+#include "ns3/event-id.h"
+#include <vector>
+#include <map>
+
+namespace ns3 {
+class MeshPointDevice;
+class Packet;
+class Mac48Address;
+namespace dot11s {
+class HwmpMacPlugin;
+class HwmpRtable;
+class IePreq;
+class IePrep;
+/**
+ * \ingroup dot11s
+ * 
+ * \brief Hybrid wireless mesh protocol -- a routing protocol of IEEE 802.11s draft. 
+ */
+class HwmpProtocol : public MeshL2RoutingProtocol
+{
+public:
+  static TypeId GetTypeId ();
+  HwmpProtocol ();
+  ~HwmpProtocol ();
+  void DoDispose ();
+  
+  /// Route request, inherited from MeshL2RoutingProtocol
+  bool RequestRoute (uint32_t  sourceIface, const Mac48Address source, const Mac48Address destination,
+      Ptr<Packet>  packet, uint16_t  protocolType, RouteReplyCallback  routeReply);
+  /** 
+   * \brief Install HWMP on given mesh point. 
+   * 
+   * Installing protocol cause installing its interface MAC plugins.
+   *  
+   * Also MP aggregates all installed protocols, HWMP protocol can be accessed 
+   * via MeshPointDevice::GetObject<dot11s::HwmpProtocol>();
+   */
+  bool Install (Ptr<MeshPointDevice>);
+  void PeerLinkStatus(Mac48Address meshPontAddress, Mac48Address peerAddress, uint32_t interface,bool status);
+  ///\brief This callback is used to obtain active neighbours on a
+  //given interface
+  ///\param interface is the interface ID
+  void SetNeighboursCallback(Callback<std::vector<Mac48Address>, uint32_t> cb);
+  ///\name Proactive PREQ mechanism:
+  ///\{
+  void SetRoot ();
+  void UnsetRoot ();
+  ///\}
+  ///\brief Statistics:
+  void Report (std::ostream &) const;
+  void ResetStats ();
+private:
+  friend class HwmpMacPlugin;
+  
+  /// Like RequestRoute, but for unicast packets
+  bool ForwardUnicast (uint32_t  sourceIface, const Mac48Address source, const Mac48Address destination,
+      Ptr<Packet>  packet, uint16_t  protocolType, RouteReplyCallback  routeReply, uint32_t ttl);
+  
+  ///\name Interaction with HWMP MAC plugin
+  //\{
+  void ReceivePreq(IePreq preq, Mac48Address from, uint32_t interface, Mac48Address fromMp, uint32_t metric);
+  void ReceivePrep(IePrep prep, Mac48Address from, uint32_t interface, Mac48Address fromMp, uint32_t metric);
+  void ReceivePerr(IePerr perr, Mac48Address from, uint32_t interface, Mac48Address fromMp);
+  void SendPrep (
+      Mac48Address src,
+      Mac48Address dst,
+      Mac48Address retransmitter,
+      uint32_t initMetric,
+      uint32_t originatorDsn,
+      uint32_t destinationSN,
+      uint32_t lifetime,
+      uint32_t interface);
+  
+  ///\brief forms a path error information element when list of destination fails on a given interface
+  void MakePathError (std::vector<IePerr::FailedDestination> destinations);
+  /// \return list of addresses where a PERR should be sent to
+  std::vector<std::pair<uint32_t, Mac48Address> > GetPerrReceivers (std::vector<IePerr::FailedDestination> failedDest);
+  
+  /// \return list of addresses where a PERR should be sent to
+  std::vector<Mac48Address> GetPreqReceivers (uint32_t interface);
+  /// \return list of addresses where a broadcast should be
+  //retransmitted
+  std::vector<Mac48Address> GetBroadcastReceivers (uint32_t interface); 
+  /**
+   * \brief MAC-plugin asks wether the frame can be dropeed. Protocol automatically updates seqno.
+   * 
+   * \return true if frame can be dropped
+   * \param uint32_t is the seqno
+   * \param Mac48Address is the mesh source addrress of the frame
+   */
+  bool DropDataFrame(uint32_t, Mac48Address);
+  //\}
+private:
+  /// Packet waiting its routing information
+  struct QueuedPacket {
+    Ptr<Packet> pkt; ///< the packet
+    Mac48Address src; ///< src address
+    Mac48Address dst; ///< dst address
+    uint16_t protocol; ///< protocol number
+    uint32_t inInterface; ///< incoming device interface ID. (if packet has come from upper layers, this is Mesh point ID)
+    RouteReplyCallback reply; ///< how to reply
+    
+    QueuedPacket () : pkt(0), protocol(0), inInterface(0) {}
+  };
+  
+  ///\name Methods related to Queue/Dequeue procedures
+  //\{
+  bool QueuePacket (QueuedPacket packet);
+  QueuedPacket  DequeueFirstPacketByDst (Mac48Address dst);
+  QueuedPacket  DequeueFirstPacket ();
+  void ReactivePathResolved (Mac48Address dst);
+  void ProactivePathResolved ();
+  //\}
+  ///\name Statistics:
+  ///\{
+  struct Statistics
+  {
+    uint16_t forwardedUnicast;
+    uint16_t forwardedBroadcast;
+    uint32_t forwardedBytes;
+    uint16_t totalQueued;
+    uint16_t totalDropped;
+
+    void Print (std::ostream & os) const;
+    Statistics () : forwardedUnicast (0), forwardedBroadcast (0), forwardedBytes (0), totalQueued (0), totalDropped (0) {}
+  };
+  Statistics m_stats;
+  ///\}
+  ///\name Methods responsible for path discovery retry procedure:
+  //\{
+  /** 
+   * \brief checks when the last path discovery procedure was started for a given destination. 
+   * 
+   * If the retry counter has not achieved the maximum level - preq should not be sent
+   */
+  bool  ShouldSendPreq (Mac48Address dst);
+  
+  /** 
+   * \brief Generates PREQ retry when retry timeout has expired and route is still unresolved. 
+   * 
+   * When PREQ retry has achieved the maximum level - retry mechanish should be cancelled
+   */
+  void  RetryPathDiscovery (Mac48Address dst, uint8_t numOfRetry);
+  //\}
+  
+  ///\name Proactive Preq routines:
+  //\{
+  void SendProactivePreq ();
+  //\}
+  ///\return address of MeshPointDevice
+  Mac48Address GetAddress (); 
+private:
+  typedef std::map<uint32_t, Ptr<HwmpMacPlugin> > HwmpPluginMap;
+  HwmpPluginMap m_interfaces;
+  Mac48Address m_address;
+  uint32_t m_dataSeqno;
+  uint32_t m_hwmpSeqno;
+  uint32_t m_preqId;
+  ///\name Sequence number filters
+  //\{
+  /// Data sequence number database
+  std::map<Mac48Address, uint32_t> m_lastDataSeqno;
+  /// DSN databse
+  std::map<Mac48Address, uint32_t> m_lastHwmpSeqno;
+  /// Metric database
+  std::map<Mac48Address, uint32_t> m_lastHwmpMetric;
+  //\}
+  
+  /// Routing table
+  Ptr<HwmpRtable> m_rtable;
+  
+  ///\name Timers:
+  //\{
+  std::map<Mac48Address, EventId> m_preqTimeouts;
+  EventId m_proactivePreqTimer;
+  //Random start in Proactive PREQ propagation
+  Time m_randomStart;
+  //\}
+  
+  /// Packet Queue
+  std::vector<QueuedPacket> m_rqueue; 
+private:
+  ///\name HWMP-protocol parameters (attributes of GetTypeId)
+  //\{
+  uint16_t m_maxQueueSize;
+  uint8_t m_dot11MeshHWMPmaxPREQretries;
+  Time m_dot11MeshHWMPnetDiameterTraversalTime;
+  Time m_dot11MeshHWMPpreqMinInterval;
+  Time m_dot11MeshHWMPperrMinInterval;
+  Time m_dot11MeshHWMPactiveRootTimeout;
+  Time m_dot11MeshHWMPactivePathTimeout;
+  Time m_dot11MeshHWMPpathToRootInterval;
+  Time m_dot11MeshHWMPrannInterval;
+  bool m_isRoot;
+  uint8_t m_maxTtl;
+  uint8_t m_unicastPerrThreshold;
+  uint8_t m_unicastPreqThreshold;
+  uint8_t m_unicastDataThreshold;
+  bool m_doFlag;
+  bool m_rfFlag;
+  //\}
+  
+  ///\name Methods needed by HwmpMacLugin to access protocol parameters:
+  //\{
+  bool GetDoFlag ();
+  bool GetRfFlag ();
+  Time GetPreqMinInterval ();
+  Time GetPerrMinInterval ();
+  uint8_t GetMaxTtl ();
+  uint32_t GetNextPreqId ();
+  uint32_t GetNextHwmpSeqno ();
+  uint32_t GetActivePathLifetime ();
+  uint8_t GetUnicastPerrThreshold ();
+  //\}
+  Callback <std::vector<Mac48Address>, uint32_t> m_neighboursCallback;
+};
+} //namespace dot11s
+} //namespace ns3
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/hwmp-rtable.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,368 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#include "ns3/object.h"
+#include "ns3/assert.h"
+#include "ns3/simulator.h"
+#include "ns3/test.h"
+#include "ns3/log.h"
+
+#include "hwmp-rtable.h"
+
+namespace ns3 {
+namespace dot11s {
+
+NS_LOG_COMPONENT_DEFINE ("HwmpRtable");
+  
+NS_OBJECT_ENSURE_REGISTERED (HwmpRtable);
+
+TypeId
+HwmpRtable::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::dot11s::HwmpRtable")
+    .SetParent<Object> ()
+    .AddConstructor<HwmpRtable> ();
+  return tid;
+}
+
+HwmpRtable::HwmpRtable ()
+{
+  DeleteProactivePath ();
+}
+
+HwmpRtable::~HwmpRtable ()
+{
+  DoDispose ();
+}
+
+void
+HwmpRtable::DoDispose ()
+{
+  m_routes.clear ();
+}
+
+void
+HwmpRtable::AddReactivePath (
+  Mac48Address destination,
+  Mac48Address retransmitter,
+  uint32_t interface,
+  uint32_t metric,
+  Time  lifetime,
+  uint32_t seqnum
+)
+{
+  std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find (destination);
+  if (i == m_routes.end ())
+    {
+      ReactiveRoute newroute;
+      m_routes[destination] = newroute;
+    }
+  i = m_routes.find (destination);
+  NS_ASSERT (i != m_routes.end());
+  i->second.retransmitter = retransmitter;
+  i->second.interface = interface;
+  i->second.metric = metric;
+  i->second.whenExpire = Simulator::Now() + lifetime;
+  i->second.seqnum = seqnum;
+}
+
+void
+HwmpRtable::AddProactivePath (
+  uint32_t metric,
+  Mac48Address root,
+  Mac48Address retransmitter,
+  uint32_t interface,
+  Time  lifetime,
+  uint32_t seqnum
+)
+{
+  m_root.root = root;
+  m_root.retransmitter = retransmitter;
+  m_root.metric = metric;
+  m_root.whenExpire = Simulator::Now() + lifetime;
+  m_root.seqnum = seqnum;
+  m_root.interface = interface;
+}
+
+void
+HwmpRtable::AddPrecursor (Mac48Address destination, uint32_t precursorInterface, Mac48Address precursorAddress)
+{
+  std::pair<uint32_t, Mac48Address> precursor;
+  precursor.first = precursorInterface;
+  precursor.second = precursorAddress;
+  std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find (destination);
+  if (i != m_routes.end ())
+    {
+      bool should_add = true;
+      for (unsigned int j = 0 ; j < i->second.precursors.size (); j ++)
+        //NB: Only one active route may exist, so do not check
+        //interface ID, just address
+        if (i->second.precursors[j].second == precursorAddress)
+          {
+            should_add = false;
+            break;
+          }
+      if (should_add)
+        i->second.precursors.push_back (precursor);
+    }
+  if(m_root.root == destination)
+    for (unsigned int j = 0 ; j < m_root.precursors.size (); j ++)
+      if (m_root.precursors[j].second == precursorAddress)
+        return;
+  m_root.precursors.push_back(precursor);
+}
+
+void
+HwmpRtable::DeleteProactivePath ()
+{
+  m_root.precursors.clear ();
+  m_root.interface = INTERFACE_ANY;
+  m_root.metric = MAX_METRIC;
+  m_root.retransmitter = Mac48Address::GetBroadcast ();
+  m_root.seqnum = 0;
+  m_root.whenExpire = Simulator::Now ();
+}
+
+void
+HwmpRtable::DeleteProactivePath (Mac48Address root)
+{
+  if(m_root.root == root)
+    DeleteProactivePath ();
+}
+
+void
+HwmpRtable::DeleteReactivePath (Mac48Address destination)
+{
+  std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find (destination);
+  if (i != m_routes.end ())
+    m_routes.erase (i);
+}
+
+HwmpRtable::LookupResult
+HwmpRtable::LookupReactive (Mac48Address destination)
+{
+  std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find (destination);
+  if (i == m_routes.end ())
+    return LookupResult ();
+  if ((i->second.whenExpire < Simulator::Now ()) && (i->second.whenExpire != Seconds (0)))
+    {
+      NS_LOG_DEBUG ("Reactive route has expired, sorry.");
+      return LookupResult();
+    }
+  return LookupReactiveExpired (destination);
+}
+
+HwmpRtable::LookupResult
+HwmpRtable::LookupReactiveExpired (Mac48Address destination)
+{
+  std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find (destination);
+  if (i == m_routes.end ())
+    return LookupResult ();
+  return LookupResult (
+      i->second.retransmitter,
+      i->second.interface,
+      i->second.metric, i->second.seqnum,
+      i->second.whenExpire - Simulator::Now ()
+      );
+}
+
+HwmpRtable::LookupResult
+HwmpRtable::LookupProactive ()
+{
+  if (m_root.whenExpire < Simulator::Now ())
+    {
+      NS_LOG_DEBUG ("Proactive route has expired and will be deleted, sorry.");
+      DeleteProactivePath ();
+    }
+  return LookupProactiveExpired ();
+}
+
+HwmpRtable::LookupResult
+HwmpRtable::LookupProactiveExpired ()
+{
+  return LookupResult(m_root.retransmitter, m_root.interface, m_root.metric, m_root.seqnum, m_root.whenExpire - Simulator::Now ());
+}
+
+std::vector<IePerr::FailedDestination>
+HwmpRtable::GetUnreachableDestinations (Mac48Address peerAddress)
+{
+  IePerr::FailedDestination dst;
+  std::vector<IePerr::FailedDestination> retval;
+  for (std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.begin (); i != m_routes.end(); i++)
+    if (i->second.retransmitter == peerAddress)
+      {
+        dst.destination = i->first;
+        i->second.seqnum ++;
+        dst.seqnum = i->second.seqnum;
+        retval.push_back (dst);
+      }
+  //Lookup a path to root
+  if (m_root.retransmitter == peerAddress)
+    {
+      dst.destination = m_root.root;
+      dst.seqnum = m_root.seqnum;
+      retval.push_back (dst);
+    }
+  return retval;
+}
+
+HwmpRtable::PrecursorList
+HwmpRtable::GetPrecursors (Mac48Address destination)
+{
+  //We suppose that no dublicates here can be
+  PrecursorList retval;
+  std::map<Mac48Address, ReactiveRoute>::iterator route = m_routes.find (destination);
+  if (route != m_routes.end ())
+    for (unsigned int i = 0; i < route->second.precursors.size (); i ++)
+      retval.push_back(route->second.precursors[i]);
+  if (m_root.root == destination)
+    for (unsigned int i = 0; i < m_root.precursors.size (); i ++)
+    {
+      bool should_add = true;
+      for(unsigned int j = 0; j < retval.size(); j ++)
+        if(retval[j].second == m_root.precursors[i].second)
+         {
+            should_add = false;
+            break;
+         }
+      if(should_add)
+        retval.push_back(m_root.precursors[i]);
+    }
+  return retval;
+}
+
+bool HwmpRtable::LookupResult::operator==(const HwmpRtable::LookupResult & o) const
+{
+  return (retransmitter == o.retransmitter
+      && ifIndex == o.ifIndex 
+      && metric  == o.metric
+      && seqnum  == o.seqnum
+    );
+}
+
+bool HwmpRtable::LookupResult::IsValid() const
+{
+  return !( retransmitter == Mac48Address::GetBroadcast ()
+        &&  ifIndex == INTERFACE_ANY
+        &&  metric == MAX_METRIC
+        &&  seqnum == 0
+      );
+}
+
+#ifdef RUN_SELF_TESTS
+
+/// Unit test for HwmpRtable
+class HwmpRtableTest : public Test 
+{
+public:
+  HwmpRtableTest ();
+  virtual bool RunTests(); 
+  
+private:
+  void Test1 ();
+  void Test2 ();
+  void Test3 ();
+  void Test4 ();
+
+private:
+  bool result;
+  
+  Mac48Address dst;
+  Mac48Address hop;
+  uint32_t iface;
+  uint32_t metric;
+  uint32_t seqnum;
+  Time expire;
+  Ptr<HwmpRtable> table;
+};
+
+/// Test instance
+static HwmpRtableTest g_HwmpRtableTest;
+
+HwmpRtableTest::HwmpRtableTest ()  : Test ("Mesh/802.11s/HwmpRtable"), 
+  result(true),
+  dst ("01:00:00:01:00:01"),
+  hop ("01:00:00:01:00:03"),
+  iface (8010),
+  metric (10),
+  seqnum (1),
+  expire (Seconds (10)) 
+{
+}
+
+void HwmpRtableTest::Test1 ()
+{
+  HwmpRtable::LookupResult correct (hop, iface, metric, seqnum);
+  
+  // Reactive path
+  table->AddReactivePath (dst, hop, iface, metric, expire, seqnum);
+  NS_TEST_ASSERT (table->LookupReactive (dst) == correct);
+  table->DeleteReactivePath (dst);
+  NS_TEST_ASSERT (! table->LookupReactive (dst).IsValid ());
+  
+  // Proactive
+  table->AddProactivePath (metric, dst, hop, iface, expire, seqnum);
+  NS_TEST_ASSERT (table->LookupProactive () == correct);
+  table->DeleteProactivePath (dst);
+  NS_TEST_ASSERT (! table->LookupProactive ().IsValid ());
+}
+
+void HwmpRtableTest::Test2 ()
+{
+  table->AddReactivePath (dst, hop, iface, metric, expire, seqnum);
+  table->AddProactivePath (metric, dst, hop, iface, expire, seqnum);
+}
+
+void HwmpRtableTest::Test3 ()
+{
+  // this is assumed to be called when path records are already expired
+  HwmpRtable::LookupResult correct (hop, iface, metric, seqnum);
+  NS_TEST_ASSERT (table->LookupReactiveExpired (dst) == correct);
+  NS_TEST_ASSERT (table->LookupProactiveExpired () == correct);
+  
+  NS_TEST_ASSERT (! table->LookupReactive (dst).IsValid ());
+  NS_TEST_ASSERT (! table->LookupProactive ().IsValid ());
+}
+
+void HwmpRtableTest::Test4 ()
+{
+  // TODO: test AddPrecursor and GetPrecursors
+}
+
+bool HwmpRtableTest::RunTests ()
+{
+  table = CreateObject<HwmpRtable> ();
+  
+  Simulator::Schedule (Seconds (0), & HwmpRtableTest::Test1, this);
+  Simulator::Schedule (Seconds (1), & HwmpRtableTest::Test2, this);
+  Simulator::Schedule (expire + Seconds (2), & HwmpRtableTest::Test3, this);
+  Simulator::Schedule (expire + Seconds (3), & HwmpRtableTest::Test4, this);
+  
+  Simulator::Run ();
+  Simulator::Destroy ();
+  
+  return result;
+}
+
+#endif // RUN_SELF_TESTS
+
+} //namespace dot11s
+} //namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/hwmp-rtable.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,150 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#ifndef HWMP_RTABLE_H
+#define HWMP_RTABLE_H
+
+#include <map>
+#include "ns3/nstime.h"
+#include "ns3/mac48-address.h"
+#include "ie-dot11s-perr.h"
+namespace ns3 {
+namespace dot11s {
+/**
+ * \ingroup dot11s
+ * 
+ * \brief Routing table for HWMP -- 802.11s routing protocol
+ */
+class HwmpRtable : public Object
+{
+public:
+  /// Means all interfaces
+  const static uint32_t INTERFACE_ANY = 0xffffffff;
+  /// Maximum (the best?) path metric
+  const static uint32_t MAX_METRIC = 0xffffffff;
+  
+  /// Route lookup result, return type of LookupXXX methods
+  struct LookupResult
+  {
+    Mac48Address retransmitter;
+    uint32_t ifIndex;
+    uint32_t metric;
+    uint32_t seqnum;
+    Time lifetime;
+    
+    LookupResult(Mac48Address r = Mac48Address::GetBroadcast (), 
+                 uint32_t i = INTERFACE_ANY, 
+                 uint32_t m = MAX_METRIC, 
+                 uint32_t s = 0,
+                 Time l = Seconds(0.0))
+      : retransmitter (r),
+        ifIndex (i),
+        metric (m),
+        seqnum (s),
+        lifetime (l)
+    {
+    }
+    
+    /// True for valid route 
+    bool IsValid() const;
+    /// Compare route lookup results, used by tests
+    bool operator==(const LookupResult & o) const;
+  };
+  /// Path precursor = {MAC, interface ID}
+  typedef std::vector<std::pair<uint32_t, Mac48Address> > PrecursorList;
+    
+public:
+  static TypeId GetTypeId ();
+  HwmpRtable ();
+  ~HwmpRtable ();
+  void DoDispose ();
+  
+  ///\name Add/delete paths
+  //\{ 
+  void AddReactivePath (
+    Mac48Address destination,
+    Mac48Address retransmitter,
+    uint32_t interface,
+    uint32_t metric,
+    Time  lifetime,
+    uint32_t seqnum
+  );
+  void AddProactivePath (
+    uint32_t metric,
+    Mac48Address root,
+    Mac48Address retransmitter,
+    uint32_t interface,
+    Time  lifetime,
+    uint32_t seqnum
+  );
+  void AddPrecursor (Mac48Address destination, uint32_t precursorInterface, Mac48Address precursorAddress);
+  PrecursorList GetPrecursors (Mac48Address destination);
+  void DeleteProactivePath ();
+  void DeleteProactivePath (Mac48Address root);
+  void DeleteReactivePath (Mac48Address destination);
+  //\}
+  
+  ///\name Lookup
+  //\{
+  /// Lookup path to destination
+  LookupResult LookupReactive (Mac48Address destination);
+  /// Return all reactive paths, including expired
+  LookupResult LookupReactiveExpired (Mac48Address destination);
+  /// Find proactive path to tree root. Note that calling this method has side effect of deleting expired proactive path
+  LookupResult LookupProactive ();
+  /// Return all proactive paths, including expired
+  LookupResult LookupProactiveExpired ();
+  //\}
+  
+  /// When peer link with a given MAC-address fails - it returns list of unreachable destination addresses
+  std::vector<IePerr::FailedDestination> GetUnreachableDestinations (Mac48Address peerAddress);
+  
+private:
+  /// Route found in reactive mode
+  struct ReactiveRoute
+  {
+    Mac48Address retransmitter;
+    uint32_t interface;
+    uint32_t metric;
+    Time whenExpire;
+    uint32_t seqnum;
+    std::vector<std::pair<uint32_t, Mac48Address> > precursors;
+  };
+  /// Route fond in proactive mode
+  struct ProactiveRoute
+  {
+    Mac48Address root;
+    Mac48Address retransmitter;
+    uint32_t interface;
+    uint32_t metric;
+    Time whenExpire;
+    uint32_t seqnum;
+    std::vector<std::pair<uint32_t, Mac48Address> > precursors;
+  };
+  
+  /// List of routes
+  std::map<Mac48Address, ReactiveRoute>  m_routes;
+  /// Path to proactive tree root MP
+  ProactiveRoute  m_root;
+};
+} //namespace dot11s
+} //namespace ns3
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/hwmp-tag.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,154 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#include "hwmp-tag.h"
+
+namespace ns3 {
+namespace dot11s{
+
+NS_OBJECT_ENSURE_REGISTERED (HwmpTag);
+//Class HwmpTag:
+HwmpTag::HwmpTag ():
+  m_address (Mac48Address::GetBroadcast ()),
+  m_ttl (0),
+  m_metric (0),
+  m_seqno (0)
+{
+}
+
+HwmpTag::~HwmpTag ()
+{
+}
+
+void
+HwmpTag::SetAddress (Mac48Address retransmitter)
+{
+  m_address = retransmitter;
+}
+
+Mac48Address
+HwmpTag::GetAddress ()
+{
+  return m_address;
+}
+
+void
+HwmpTag::SetTtl (uint8_t ttl)
+{
+  m_ttl = ttl;
+}
+
+uint8_t
+HwmpTag::GetTtl ()
+{
+  return m_ttl;
+}
+
+void
+HwmpTag::SetMetric (uint32_t metric)
+{
+  m_metric = metric;
+}
+
+uint32_t
+HwmpTag::GetMetric ()
+{
+  return m_metric;
+}
+
+void
+HwmpTag::SetSeqno (uint32_t seqno)
+{
+  m_seqno = seqno;
+}
+
+uint32_t
+HwmpTag::GetSeqno ()
+{
+  return m_seqno;
+}
+
+TypeId
+HwmpTag::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::dot11s::HwmpTag")
+    .SetParent<Tag> ()
+    .AddConstructor<HwmpTag> ();
+  return tid;
+}
+
+TypeId
+HwmpTag::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+
+uint32_t
+HwmpTag::GetSerializedSize () const
+{
+  return
+     6 //address
+    +1 //ttl
+    +4 //metric
+    +4; //seqno
+}
+
+void
+HwmpTag::Serialize (TagBuffer i) const
+{
+  uint8_t address[6];
+  int j;
+  m_address.CopyTo (address);
+  i.WriteU8 (m_ttl);
+  i.WriteU32 (m_metric);
+  i.WriteU32(m_seqno);
+  for (j = 0; j < 6; j ++)
+    i.WriteU8 (address[j]);
+}
+
+void
+HwmpTag::Deserialize (TagBuffer i)
+{
+  uint8_t address[6];
+  int j;
+  m_ttl = i.ReadU8 ();
+  m_metric = i.ReadU32 ();
+  m_seqno = i.ReadU32 ();
+  for (j = 0; j < 6; j ++)
+    address[j] = i.ReadU8 ();
+  m_address.CopyFrom (address);
+}
+
+void
+HwmpTag::Print (std::ostream &os) const
+{
+  os << "address=" << m_address;
+  os << "ttl="  <<  m_ttl;
+  os << "metrc=" << m_metric;
+  os << "seqno=" << m_seqno;
+}
+void
+HwmpTag::DecrementTtl ()
+{
+  m_ttl --;
+}
+} //namespace dot11s
+} //namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/hwmp-tag.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,78 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ *          Aleksey Kovalenko <kovalenko@iitp.ru>
+ *          Pavel Boyko <boyko@iitp.ru>
+ */
+
+
+#ifndef HWMP_TAG_H
+#define HWMP_TAG_H
+
+#include "ns3/tag.h"
+#include "ns3/object.h"
+#include "ns3/mac48-address.h"
+namespace ns3 {
+namespace dot11s {
+/**
+ * \ingroup dot11s
+ *
+ * \brief Hwmp tag implements interaction between HWMP
+ * protocol and MeshWifiMac
+ *
+ * \details Hwmp tag keeps the following:
+ * 1. When packet is passed from Hwmp to 11sMAC:
+ *  - retransmitter address,
+ *  - TTL value,
+ * 2. When packet is passed to Hwmp from 11sMAC:
+ *  - lasthop address,
+ *  - TTL value,
+ *  - metric value (metric of link is recalculated
+ *  at each packet, but routing table stores metric
+ *  obtained during path discovery procedure)
+ */
+class HwmpTag : public Tag
+{
+public:
+  HwmpTag ();
+  ~HwmpTag ();
+  void  SetAddress (Mac48Address retransmitter);
+  Mac48Address GetAddress ();
+  void  SetTtl (uint8_t ttl);
+  uint8_t GetTtl ();
+  void  SetMetric (uint32_t metric);
+  uint32_t GetMetric ();
+  void  SetSeqno (uint32_t seqno);
+  uint32_t GetSeqno ();
+  void  DecrementTtl ();
+
+  static  TypeId  GetTypeId ();
+  virtual TypeId  GetInstanceTypeId () const;
+  virtual uint32_t GetSerializedSize () const;
+  virtual void  Serialize (TagBuffer i) const;
+  virtual void  Deserialize (TagBuffer i);
+  virtual void  Print (std::ostream &os) const;
+private:
+  Mac48Address m_address;
+  uint8_t  m_ttl;
+  uint32_t m_metric;
+  uint32_t m_seqno;
+};
+} //namespace dot11s
+} //namespace ns3
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-beacon-timing.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,251 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#include "ie-dot11s-beacon-timing.h"
+#include "ns3/log.h"
+#include "ns3/test.h"
+#include "ns3/packet.h"
+namespace ns3 {
+namespace dot11s {
+/*******************************************
+ * IeBeaconTimingUnit
+ *******************************************/
+IeBeaconTimingUnit::IeBeaconTimingUnit ():
+  m_aid (0),
+  m_lastBeacon (0),
+  m_beaconInterval (0)
+{
+}
+
+void
+IeBeaconTimingUnit::SetAid (uint8_t aid)
+{
+  m_aid = aid;
+}
+
+void
+IeBeaconTimingUnit::SetLastBeacon (uint16_t lastBeacon)
+{
+  m_lastBeacon = lastBeacon;
+}
+
+void
+IeBeaconTimingUnit::SetBeaconInterval (uint16_t beaconInterval)
+{
+  m_beaconInterval = beaconInterval;
+}
+
+uint8_t
+IeBeaconTimingUnit::GetAid () const
+{
+  return m_aid;
+}
+
+uint16_t
+IeBeaconTimingUnit::GetLastBeacon () const
+{
+  return m_lastBeacon;
+}
+
+uint16_t
+IeBeaconTimingUnit::GetBeaconInterval () const
+{
+  return m_beaconInterval;
+}
+/*******************************************
+ * IeBeaconTiming
+ *******************************************/
+IeBeaconTiming::IeBeaconTiming ():
+  m_numOfUnits (0)
+{
+}
+
+IeBeaconTiming::NeighboursTimingUnitsList
+IeBeaconTiming::GetNeighboursTimingElementsList ()
+{
+  return m_neighbours;
+}
+
+void
+IeBeaconTiming::AddNeighboursTimingElementUnit (
+  uint16_t aid,
+  Time  last_beacon, //MicroSeconds!
+  Time  beacon_interval //MicroSeconds!
+)
+{
+  if (m_numOfUnits == 50)
+    return;
+  //Firs we lookup if this element already exists
+  for (NeighboursTimingUnitsList::const_iterator i = m_neighbours.begin (); i != m_neighbours.end(); i++)
+    if (
+      ((*i)->GetAid () == AidToU8(aid))
+      && ((*i)->GetLastBeacon () == TimestampToU16(last_beacon))
+      && ((*i)->GetBeaconInterval () == BeaconIntervalToU16(beacon_interval))
+    )
+      return;
+  Ptr<IeBeaconTimingUnit>new_element = Create<IeBeaconTimingUnit> ();
+  new_element->SetAid (AidToU8(aid));
+  new_element->SetLastBeacon (TimestampToU16(last_beacon));
+  new_element->SetBeaconInterval (BeaconIntervalToU16(beacon_interval));
+  m_neighbours.push_back (new_element);
+  m_numOfUnits++;
+}
+
+void
+IeBeaconTiming::DelNeighboursTimingElementUnit (
+  uint16_t aid,
+  Time  last_beacon, //MicroSeconds!
+  Time  beacon_interval //MicroSeconds!
+)
+{
+  for (NeighboursTimingUnitsList::iterator i = m_neighbours.begin (); i != m_neighbours.end(); i++)
+    if (
+      ((*i)->GetAid () == AidToU8(aid))
+      && ((*i)->GetLastBeacon () == TimestampToU16(last_beacon))
+      && ((*i)->GetBeaconInterval () == BeaconIntervalToU16(beacon_interval))
+    )
+      {
+        m_neighbours.erase (i);
+        m_numOfUnits--;
+        break;
+      }
+}
+
+void
+IeBeaconTiming::ClearTimingElement ()
+{
+  uint16_t to_delete = 0;
+  uint16_t i;
+  for (NeighboursTimingUnitsList::iterator j = m_neighbours.begin (); j != m_neighbours.end(); j++)
+    {
+      to_delete++;
+      (*j) = 0;
+    }
+  for (i = 0; i < to_delete; i ++)
+    m_neighbours.pop_back ();
+  m_neighbours.clear ();
+
+}
+
+uint8_t
+IeBeaconTiming::GetInformationSize () const
+{
+  return (5*m_numOfUnits);
+}
+
+void
+IeBeaconTiming::PrintInformation (std::ostream& os) const
+{
+  os <<"Number of units: " << (uint16_t)m_numOfUnits << "\n";
+  for (NeighboursTimingUnitsList::const_iterator j = m_neighbours.begin (); j != m_neighbours.end(); j++)
+    os<< "AID=" << (uint16_t)(*j)->GetAid () << ", Last beacon was at "
+      << (*j)->GetLastBeacon ()<<", with beacon interval " << (*j)->GetBeaconInterval () << "\n";
+}
+
+void
+IeBeaconTiming::SerializeInformation (Buffer::Iterator i) const
+{
+  for (NeighboursTimingUnitsList::const_iterator j = m_neighbours.begin (); j != m_neighbours.end(); j++)
+  {
+    i.WriteU8 ((*j)->GetAid ());
+    i.WriteHtolsbU16 ((*j)->GetLastBeacon ());
+    i.WriteHtolsbU16 ((*j)->GetBeaconInterval ());
+  }
+}
+uint8_t 
+IeBeaconTiming::DeserializeInformation (Buffer::Iterator start, uint8_t length)
+{
+  Buffer::Iterator i = start;
+  m_numOfUnits = length/5;
+  for (int j = 0; j < m_numOfUnits; j ++)
+    {
+      Ptr<IeBeaconTimingUnit> new_element = Create<IeBeaconTimingUnit> ();
+      new_element->SetAid (i.ReadU8());
+      new_element->SetLastBeacon (i.ReadLsbtohU16());
+      new_element->SetBeaconInterval (i.ReadLsbtohU16());
+      m_neighbours.push_back (new_element);
+    }
+  return i.GetDistanceFrom (start);
+};
+
+uint16_t
+IeBeaconTiming::TimestampToU16 (Time x)
+{
+  return ((uint16_t) ((x.GetMicroSeconds() >> 8)&0xffff));
+};
+
+uint16_t 
+IeBeaconTiming::BeaconIntervalToU16 (Time x)
+{
+  return ((uint16_t) (x.GetMicroSeconds() >>10)&0xffff);
+};
+
+uint8_t
+IeBeaconTiming::AidToU8 (uint16_t x)
+{
+  return (uint8_t) (x&0xff);
+};
+
+bool operator== (const IeBeaconTimingUnit & a, const IeBeaconTimingUnit & b)
+{
+  return (
+      (a.GetAid () == b.GetAid ()) &&
+      (a.GetLastBeacon () == b.GetLastBeacon()) &&
+      (a.GetBeaconInterval () == b.GetBeaconInterval ())
+      );
+}
+bool operator== (const IeBeaconTiming & a, const IeBeaconTiming& b)
+{
+  if(a.m_numOfUnits != b.m_numOfUnits)
+    return false;
+  for(unsigned int i = 0; i < a.m_neighbours.size (); i ++)
+    if(!(*PeekPointer(a.m_neighbours[i]) == *PeekPointer(b.m_neighbours[i])))
+      return false;
+  return true;
+}
+
+#ifdef RUN_SELF_TESTS  
+struct IeBeaconTimingBist : public IeTest 
+{
+  IeBeaconTimingBist () : IeTest ("Mesh/802.11s/IE/BeaconTiming") {}
+  virtual bool RunTests(); 
+};
+
+/// Test instance
+static IeBeaconTimingBist g_IePerrBist;
+
+bool IeBeaconTimingBist::RunTests ()
+{
+  bool result(true);
+  // create test information element
+  IeBeaconTiming a;
+  a.IeBeaconTiming::AddNeighboursTimingElementUnit (1,Seconds(1.0), Seconds(4.0));
+  a.IeBeaconTiming::AddNeighboursTimingElementUnit (2,Seconds(2.0), Seconds(3.0));
+  a.IeBeaconTiming::AddNeighboursTimingElementUnit (3,Seconds(3.0), Seconds(2.0));
+  a.IeBeaconTiming::AddNeighboursTimingElementUnit (4,Seconds(4.0), Seconds(1.0));
+  
+  result = TestRoundtripSerialization (a);
+  return result;
+}
+#endif
+} // namespace dot11s
+} //namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-beacon-timing.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,118 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#ifndef WIFI_TIMING_ELEMENT_H
+#define WIFI_TIMING_ELEMENT_H
+
+#include <vector>
+#include "ns3/nstime.h"
+#include "ns3/wifi-information-element.h"
+
+namespace ns3 {
+namespace dot11s {
+/**
+ * \ingroup dot11s
+ * \brief Describes one unit of beacon timing element
+ */
+class IeBeaconTimingUnit : public RefCountBase
+{
+public:
+  IeBeaconTimingUnit ();
+  void SetAid (uint8_t aid);
+  void SetLastBeacon (uint16_t last_beacon);
+  void SetBeaconInterval (uint16_t beacon_interval);
+
+  uint8_t GetAid () const;
+  uint16_t GetLastBeacon () const;
+  uint16_t GetBeaconInterval () const;
+  /**
+   * \brief Least significant octet of AID:
+   */
+  uint8_t m_aid;
+  /**
+   * \brief Last time we received a beacon in accordance with a
+   * local TSF measured in 256 microseconds unit:
+   */
+  uint16_t m_lastBeacon;
+  /**
+   * \brief Beacon interval of remote mesh point:
+   */
+  uint16_t m_beaconInterval;
+  friend bool operator== (const IeBeaconTimingUnit & a, const IeBeaconTimingUnit & b);
+};
+
+/**
+ * \ingroup dot11s
+ * \brief See 7.3.2.89 of 802.11s draft 2.07
+ */
+class IeBeaconTiming : public WifiInformationElement
+{
+public:
+  /**
+   * \ingroup dot11s
+   * This type is a list of timing elements obtained from neigbours with their beacons:
+   */
+  typedef std::vector< Ptr<IeBeaconTimingUnit> > NeighboursTimingUnitsList;
+
+  IeBeaconTiming ();
+  /**
+   * This methods are needed for beacon collision
+   * avoidance module:
+   */
+  NeighboursTimingUnitsList GetNeighboursTimingElementsList ();
+  void AddNeighboursTimingElementUnit (
+    uint16_t aid,
+    Time last_beacon,
+    Time beacon_interval
+  );
+  void   DelNeighboursTimingElementUnit (
+    uint16_t aid,
+    Time  last_beacon,
+    Time  beacon_interval
+  );
+  void   ClearTimingElement ();
+private:
+  WifiElementId ElementId () const {
+    return IE11S_BEACON_TIMING;
+  }
+  uint8_t  GetInformationSize () const;
+  void SerializeInformation (Buffer::Iterator i) const;
+  uint8_t DeserializeInformation (Buffer::Iterator i, uint8_t length);
+  void PrintInformation (std::ostream& os) const; 
+  /**
+   * Converters:
+   */
+  static uint16_t TimestampToU16 (Time x);
+  static uint16_t BeaconIntervalToU16 (Time x);
+  static uint8_t AidToU8 (uint16_t x);
+
+  NeighboursTimingUnitsList  m_neighbours;
+  /**
+   * Timing element parameters:
+   */
+  uint16_t  m_numOfUnits;
+  friend bool operator== (const IeBeaconTiming & a, const IeBeaconTiming & b);
+};
+bool operator== (const IeBeaconTiming & a, const IeBeaconTiming & b);
+bool operator== (const IeBeaconTimingUnit & a, const IeBeaconTimingUnit & b);
+} // namespace dot11s
+} //namespace ns3
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-configuration.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,244 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ *          Aleksey Kovalenko <kovalenko@iitp.ru>
+ */
+
+
+#include "ie-dot11s-configuration.h"
+#include "ns3/test.h"
+#include "ns3/packet.h"
+namespace ns3 {
+namespace dot11s {
+
+dot11sMeshCapability::dot11sMeshCapability ():
+    acceptPeerLinks (true),
+    MCCASupported (false),
+    MCCAEnabled (false),
+    forwarding (true),
+    beaconTimingReport (true),
+    TBTTAdjustment (true),
+    powerSaveLevel (false)
+{}
+
+uint8_t dot11sMeshCapability::GetSerializedSize () const
+{
+  return 2;
+}
+
+Buffer::Iterator dot11sMeshCapability::Serialize (Buffer::Iterator i) const
+{
+  uint16_t result = 0;
+  if (acceptPeerLinks)
+    result |= 1 << 0;
+  if (MCCASupported)
+    result |= 1 << 1;
+  if (MCCAEnabled)
+    result |= 1 << 2;
+  if (forwarding)
+    result |= 1 << 3;
+  if (beaconTimingReport)
+    result |= 1 << 4;
+  if (TBTTAdjustment)
+    result |= 1 << 5;
+  if (powerSaveLevel)
+    result |= 1 << 6;
+  i.WriteHtolsbU16 (result);
+  return i;
+}
+
+Buffer::Iterator dot11sMeshCapability::Deserialize (Buffer::Iterator i)
+{
+  uint16_t  cap = i.ReadLsbtohU16 ();
+  acceptPeerLinks    = Is (cap, 0);
+  MCCASupported      = Is (cap, 1);
+  MCCAEnabled        = Is (cap, 2);
+  forwarding         = Is (cap, 3);
+  beaconTimingReport = Is (cap, 4);
+  TBTTAdjustment     = Is (cap, 5);
+  powerSaveLevel     = Is (cap, 6);
+  return i;
+}
+
+bool dot11sMeshCapability::Is (uint16_t cap, uint8_t n) const
+{
+  uint16_t mask = 1<<n;
+  return (cap & mask) == mask;
+}
+
+IeConfiguration::IeConfiguration ():
+    m_APSId (PROTOCOL_HWMP),
+    m_APSMId (METRIC_AIRTIME),
+    m_CCMId (CONGESTION_NULL),
+    m_SPId (SYNC_NEIGHBOUR_OFFSET),
+    m_APId (AUTH_NULL),
+    m_neighbors (0)
+{}
+
+TypeId
+IeConfiguration::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::dot11s::IeConfiguration")
+    .SetParent<WifiInformationElement> ();
+  return tid;
+}
+
+TypeId
+IeConfiguration::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+uint8_t
+IeConfiguration::GetInformationSize () const
+{
+  return 1 // Version
+    + 4 // APSPId
+    + 4 // APSMId
+    + 4 // CCMId
+    + 4 // SPId
+    + 4 // APId
+    + 1 // Mesh formation info (see 7.3.2.86.6 of 802.11s draft 3.0)
+    + m_meshCap.GetSerializedSize ();
+}
+
+void
+IeConfiguration::SerializeInformation (Buffer::Iterator i) const
+{
+  i.WriteU8 (1); //Version
+  // Active Path Selection Protocol ID:
+  i.WriteHtolsbU32 (m_APSId);
+  // Active Path Metric ID:
+  i.WriteHtolsbU32 (m_APSMId);
+  // Congestion Control Mode ID:
+  i.WriteHtolsbU32 (m_CCMId);
+  // Sync:
+  i.WriteHtolsbU32 (m_SPId);
+  // Auth:
+  i.WriteHtolsbU32 (m_APId);
+  i.WriteU8 (m_neighbors << 1);
+  m_meshCap.Serialize (i);
+}
+
+uint8_t
+IeConfiguration::DeserializeInformation (Buffer::Iterator i, uint8_t length)
+{
+  Buffer::Iterator start = i;
+  uint8_t version;
+  version  = i.ReadU8 ();
+  // Active Path Selection Protocol ID:
+  m_APSId  = (dot11sPathSelectionProtocol)i.ReadLsbtohU32 ();
+  // Active Path Metric ID:
+  m_APSMId = (dot11sPathSelectionMetric)i.ReadLsbtohU32 ();
+  // Congestion Control Mode ID:
+  m_CCMId  = (dot11sCongestionControlMode)i.ReadLsbtohU32 ();
+  m_SPId   = (dot11sSynchronizationProtocolIdentifier)i.ReadLsbtohU32 ();
+  m_APId   = (dot11sAuthenticationProtocol)i.ReadLsbtohU32 ();
+  m_neighbors = i.ReadU8 () / 2;
+  i = m_meshCap.Deserialize (i);
+  return i.GetDistanceFrom (start);
+}
+void
+IeConfiguration::PrintInformation (std::ostream& os) const
+{
+  //TODO: print
+}
+void
+IeConfiguration::SetRouting (dot11sPathSelectionProtocol routingId)
+{
+  m_APSId  =  routingId;
+}
+
+void
+IeConfiguration::SetMetric (dot11sPathSelectionMetric metricId)
+{
+  m_APSMId =  metricId;
+}
+
+bool
+IeConfiguration::IsHWMP ()
+{
+  return (m_APSId == PROTOCOL_HWMP);
+}
+
+bool
+IeConfiguration::IsAirtime ()
+{
+  return (m_APSMId  == METRIC_AIRTIME);
+}
+void
+IeConfiguration::SetNeighborCount (uint8_t neighbors)
+{
+  m_neighbors = (neighbors > 31) ? 31 : neighbors;
+}
+uint8_t
+IeConfiguration::GetNeighborCount ()
+{
+  return m_neighbors;
+}
+dot11sMeshCapability const& IeConfiguration::MeshCapability ()
+{
+  return m_meshCap;
+}
+bool operator== (const dot11sMeshCapability & a, const dot11sMeshCapability & b)
+{
+  return (
+      (a.acceptPeerLinks == b.acceptPeerLinks) &&
+      (a.MCCASupported == b.MCCASupported) &&
+      (a.MCCAEnabled == b.MCCAEnabled) &&
+      (a.forwarding == b.forwarding) &&
+      (a.beaconTimingReport == b.beaconTimingReport) &&
+      (a.TBTTAdjustment == b.TBTTAdjustment) &&
+      (a.powerSaveLevel == b.powerSaveLevel)
+      );
+}
+bool operator== (const IeConfiguration & a, const IeConfiguration & b)
+{
+  return (
+      (a.m_APSId == b.m_APSId) &&
+      (a.m_APSMId == b.m_APSMId) &&
+      (a.m_CCMId == b.m_CCMId) &&
+      (a.m_SPId == b.m_SPId) &&
+      (a.m_APId == b.m_APId) &&
+      (a.m_neighbors == b.m_neighbors) &&
+      (a.m_meshCap == b.m_meshCap)
+      );
+}
+#ifdef RUN_SELF_TESTS
+
+/// Built-in self test for IePreq
+struct IeConfigurationBist : public IeTest 
+{
+  IeConfigurationBist () : IeTest ("Mesh/802.11s/IE/Configuration") {}
+  virtual bool RunTests(); 
+};
+
+/// Test instance
+static IeConfigurationBist g_IeConfigurationBist;
+
+bool IeConfigurationBist::RunTests ()
+{
+  bool result(true);
+  IeConfiguration a;
+  
+  result = TestRoundtripSerialization (a);
+  return result;
+}
+#endif
+} // namespace dot11s
+} //namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-configuration.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,143 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ *          Aleksey Kovalenko <kovalenko@iitp.ru>
+ */
+
+
+#ifndef MESH_CONFIGURATION_H
+#define MESH_CONFIGURATION_H
+
+#include "ns3/wifi-information-element.h"
+
+namespace ns3 {
+namespace dot11s {
+/**
+ * \ingroup dot11s
+ * \brief See 7.3.2.86.1 in 802.11s draft 3.0
+ */
+enum dot11sPathSelectionProtocol
+{
+  PROTOCOL_HWMP = 0x000fac00,
+};
+/**
+ * \ingroup dot11s
+ * \brief See 7.3.2.86.2 in 802.11s draft 3.0
+ */
+enum dot11sPathSelectionMetric
+{
+  METRIC_AIRTIME = 0x000fac00,
+};
+/**
+ * \ingroup dot11s
+ * \brief See 7.3.2.86.3 in 802.11s draft 3.0
+ */
+enum dot11sCongestionControlMode
+{
+  CONGESTION_SIGNALING = 0x000fac00,
+  CONGESTION_NULL      = 0x000facff,
+};
+/**
+ * \ingroup dot11s
+ * \brief See 7.3.2.86.4 in 802.11s draft 3.0
+ */
+enum dot11sSynchronizationProtocolIdentifier
+{
+  SYNC_NEIGHBOUR_OFFSET = 0x000fac00,
+  SYNC_NULL             = 0x000facff,
+};
+/**
+ * \ingroup dot11s
+ * \brief See 7.3.2.86.5 in 802.11s draft 3.0
+ */
+enum dot11sAuthenticationProtocol
+{
+  AUTH_NULL = 0x000fac00,
+  AUTH_SAE  = 0x000fac01,
+};
+/**
+ * \ingroup dot11s
+ * \brief See 7.3.2.86.7 in 802.11s draft 3.0
+ */
+class dot11sMeshCapability
+{
+public:
+  dot11sMeshCapability ();
+  uint8_t  GetSerializedSize () const;
+  Buffer::Iterator Serialize (Buffer::Iterator i) const;
+  Buffer::Iterator Deserialize (Buffer::Iterator i);
+  bool acceptPeerLinks;
+  bool MCCASupported;
+  bool MCCAEnabled;
+  bool forwarding;
+  bool beaconTimingReport;
+  bool TBTTAdjustment;
+  bool powerSaveLevel;
+  bool Is (uint16_t cap,uint8_t n) const;
+  friend bool operator== (const dot11sMeshCapability & a, const dot11sMeshCapability & b);
+};
+
+/**
+ * \ingroup dot11s
+ * \brief Describes Mesh Configuration Element 
+ * see 7.3.2.86 of 802.11s draft 3.0
+ */
+class IeConfiguration : public WifiInformationElement
+{
+public:
+  static TypeId GetTypeId ();
+  TypeId GetInstanceTypeId () const;
+
+  IeConfiguration ();
+  void SetRouting (dot11sPathSelectionProtocol routingId);
+  void SetMetric (dot11sPathSelectionMetric metricId);
+  bool IsHWMP ();
+  bool IsAirtime ();
+  void SetNeighborCount (uint8_t neighbors);
+  uint8_t GetNeighborCount ();
+
+  dot11sMeshCapability const& MeshCapability ();
+private:
+  WifiElementId ElementId () const
+  {
+    return IE11S_MESH_CONFIGURATION;
+  }
+  uint8_t  GetInformationSize () const;
+  void SerializeInformation (Buffer::Iterator i) const;
+  uint8_t DeserializeInformation (Buffer::Iterator i, uint8_t length);
+  void PrintInformation (std::ostream& os) const;
+private:
+  /** Active Path Selection Protocol ID */
+  dot11sPathSelectionProtocol m_APSId;
+  /** Active Path Metric ID */
+  dot11sPathSelectionMetric   m_APSMId;
+  /** Congestion Control Mode ID */
+  dot11sCongestionControlMode m_CCMId;
+  /** Sync protocol ID */
+  dot11sSynchronizationProtocolIdentifier m_SPId;
+  /** Auth protocol ID */
+  dot11sAuthenticationProtocol m_APId;
+  dot11sMeshCapability m_meshCap;
+  uint8_t m_neighbors;
+  friend bool operator== (const IeConfiguration & a, const IeConfiguration & b);
+};
+bool operator== (const IeConfiguration & a, const IeConfiguration & b);
+bool operator== (const dot11sMeshCapability & a, const dot11sMeshCapability & b);
+} // namespace dot11s
+} //namespace ns3
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-id.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,157 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+#include "ie-dot11s-id.h"
+#include "ns3/assert.h"
+
+namespace ns3 {
+namespace dot11s {
+IeMeshId::IeMeshId ()
+{
+  for (uint8_t i = 0; i < 32; i++) 
+    {
+      m_meshId[i] = 0;
+    }
+}
+IeMeshId::IeMeshId (char const meshId[32], uint8_t length)
+{
+  NS_ASSERT (length <= 32);
+  uint8_t len = 0;
+  while (len < length) 
+    {
+      m_meshId[len] = meshId[len];
+      len++;
+    }
+  while (len < 32) 
+    {
+      m_meshId[len] = 0;
+      len++;
+    }
+}
+bool 
+IeMeshId::IsEqual (IeMeshId const &o) const
+{
+  uint8_t i = 0;
+  while (i < 32 && 
+         m_meshId[i] == o.m_meshId[i] &&
+         m_meshId[i] != 0) 
+    {
+      i++;
+    }
+  if (m_meshId[i] != o.m_meshId[i]) 
+    {
+      return false;
+    }
+  return true;
+}
+bool 
+IeMeshId::IsBroadcast (void) const
+{
+  if (m_meshId[0] == 0) 
+    {
+      return true;
+    }
+  return false;
+}
+char *
+IeMeshId::PeekString (void) const
+{
+  return (char *)m_meshId;
+}
+uint8_t 
+IeMeshId::GetInformationSize (void) const
+{
+  uint8_t size = 0;
+  while (m_meshId[size] != 0 && size < 32)
+  {
+    size++;
+  }
+  NS_ASSERT (size <= 32);
+  return size;
+}
+void
+IeMeshId::SerializeInformation (Buffer::Iterator i) const
+{
+  uint8_t size = 0;
+  while (m_meshId[size] != 0 && size < 32)
+  {
+    i.WriteU8 (m_meshId [size]);
+    size ++;
+  }
+}
+uint8_t
+IeMeshId::DeserializeInformation (Buffer::Iterator start, uint8_t length)
+{
+  Buffer::Iterator i = start;
+  NS_ASSERT (length <= 32);
+  i.Read (m_meshId, length);
+  m_meshId[length] = 0;
+  return i.GetDistanceFrom(start);
+}
+void 
+IeMeshId::PrintInformation (std::ostream& os) const
+{
+  //TODO
+}
+bool operator== (const IeMeshId & a, const IeMeshId & b)
+{
+  bool result (true);
+  uint8_t size = 0;
+
+  while(size < 32)
+  {
+    result = result && (a.m_meshId[size] == b.m_meshId[size]);
+    if(a.m_meshId[size] == 0)
+      return result;
+    size ++;
+  }
+  return result;
+};
+
+std::ostream &
+operator << (std::ostream &os, const IeMeshId &meshId)
+{
+  os << meshId.PeekString ();
+  return os;
+}
+#ifdef RUN_SELF_TESTS
+
+/// Built-in self test for IeMeshId
+struct IeMeshIdBist : public IeTest 
+{
+  IeMeshIdBist () : IeTest ("Mesh/802.11s/IE/MESH_ID") {}
+  virtual bool RunTests(); 
+};
+
+/// Test instance
+static IeMeshIdBist g_IeMeshIdBist;
+
+bool IeMeshIdBist::RunTests ()
+{
+  bool result(true);
+  
+  // create test information element
+  IeMeshId a("qwerty",6);
+  result = result && TestRoundtripSerialization (a);
+  return result;
+}
+#endif // RUN_SELF_TESTS
+} //namespace dot11s
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-id.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,70 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+#ifndef MESH_ID_H
+#define MESH_ID_H
+
+#include <stdint.h>
+#include "ns3/buffer.h"
+#include "ns3/wifi-information-element.h"
+
+namespace ns3 {
+namespace dot11s {
+/**
+ * \brief a IEEE 802.11s Mesh ID 7.3.287 of 802.11s draft 3.0
+ *
+ */
+class IeMeshId : public WifiInformationElement
+{
+public:
+  // broadcast meshId
+  IeMeshId ();
+  //IeMeshId (char const meshId[32]);
+  IeMeshId (char const meshId[32], uint8_t length);
+
+  bool IsEqual (IeMeshId const &o) const;
+  bool IsBroadcast (void) const;
+
+  uint32_t GetLength (void) const;
+  char *PeekString (void) const;
+private:
+  WifiElementId ElementId () const{
+    return IE11S_MESH_ID;
+  };
+  void SerializeInformation (Buffer::Iterator i) const;
+  uint8_t DeserializeInformation (Buffer::Iterator start, uint8_t length);
+  void PrintInformation (std::ostream& os) const;
+  uint8_t GetInformationSize () const;
+private:
+  uint8_t m_meshId[33];
+  friend bool operator== (const IeMeshId & a, const IeMeshId & b);
+};
+
+std::ostream &operator << (std::ostream &os, const IeMeshId &meshId);
+
+/**
+ * \class ns3::IeMeshIdValue
+ * \brief hold objects of type ns3::IeMeshId
+ */
+
+ATTRIBUTE_HELPER_HEADER (IeMeshId);
+} //namespace dot11s
+} // namespace ns3
+#endif /* MESH_ID_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-peer-management.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,194 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ *          Aleksey Kovalenko <kovalenko@iitp.ru>
+ */
+
+
+#include "ie-dot11s-peer-management.h"
+#include "ns3/assert.h"
+#include "ns3/test.h"
+#include "ns3/packet.h"
+
+namespace ns3 {
+namespace dot11s {
+
+IePeerManagement::IePeerManagement ():
+    m_length (0),
+    m_subtype (PEER_OPEN),
+    m_localLinkId (0),
+    m_peerLinkId (0),
+    m_reasonCode (REASON11S_RESERVED)
+{}
+
+
+void
+IePeerManagement::SetPeerOpen (uint16_t localLinkId)
+{
+  m_length = 3;
+  m_subtype = PEER_OPEN;
+  m_localLinkId = localLinkId;
+}
+void
+IePeerManagement::SetPeerClose (uint16_t localLinkId, uint16_t peerLinkId, PmpReasonCode reasonCode)
+{
+  m_length = 7;
+  m_subtype = PEER_CLOSE;
+  m_localLinkId = localLinkId;
+  m_peerLinkId = peerLinkId;
+  m_reasonCode = reasonCode;
+}
+
+void
+IePeerManagement::SetPeerConfirm (uint16_t localLinkId, uint16_t peerLinkId)
+{
+  m_length = 5;
+  m_subtype = PEER_CONFIRM;
+  m_localLinkId = localLinkId;
+  m_peerLinkId = peerLinkId;
+}
+
+PmpReasonCode
+IePeerManagement::GetReasonCode () const
+{
+  return m_reasonCode;
+}
+
+uint16_t
+IePeerManagement::GetLocalLinkId () const
+{
+  return m_localLinkId;
+}
+
+uint16_t
+IePeerManagement::GetPeerLinkId () const
+{
+  return m_peerLinkId;
+}
+
+uint8_t
+IePeerManagement::GetInformationSize (void) const
+{
+  return m_length;
+}
+
+bool
+IePeerManagement::SubtypeIsOpen () const
+{
+  return (m_subtype == PEER_OPEN);
+}
+bool
+IePeerManagement::SubtypeIsClose () const
+{
+  return (m_subtype == PEER_CLOSE);
+}
+bool
+IePeerManagement::SubtypeIsConfirm () const
+{
+  return (m_subtype == PEER_CONFIRM);
+}
+
+void
+IePeerManagement::SerializeInformation (Buffer::Iterator i) const
+{
+  i.WriteU8 (m_subtype);
+  i.WriteHtolsbU16 (m_localLinkId);
+  if (m_length > 3)
+    i.WriteHtolsbU16 (m_peerLinkId);
+  if (m_length > 5)
+    i.WriteHtolsbU16 (m_reasonCode);
+}
+uint8_t
+IePeerManagement::DeserializeInformation (Buffer::Iterator start, uint8_t length)
+{
+  Buffer::Iterator i = start;
+  m_subtype  = i.ReadU8 ();
+  m_length = length;
+  if (m_subtype == PEER_OPEN)
+  {
+    NS_ASSERT (length == 3);
+  }
+  if (m_subtype == PEER_CONFIRM)
+  {
+    NS_ASSERT (length == 5);
+  }
+  if (m_subtype == PEER_CLOSE)
+  {
+    NS_ASSERT (length == 7);
+  }
+  m_localLinkId  = i.ReadLsbtohU16 ();
+  if (m_length > 3)
+    m_peerLinkId = i.ReadLsbtohU16 ();
+  if (m_length > 5)
+    m_reasonCode = (PmpReasonCode)i.ReadLsbtohU16 ();
+  return i.GetDistanceFrom (start);
+}
+void
+IePeerManagement::PrintInformation (std::ostream& os) const
+{
+
+  os << " Subtype:      = " << (uint16_t)m_subtype << "\n";
+  os << " Length:       = " << (uint16_t)m_length << "\n";
+  os << " LocalLinkId:  = " << m_localLinkId << "\n";
+  os << " PeerLinkId:   = " << m_peerLinkId << "\n";
+  os << " ReasonCode:   = " << m_reasonCode << "\n";
+}
+bool operator== (const IePeerManagement & a, const IePeerManagement & b)
+{
+  return (
+      (a.m_length == b.m_length) &&
+      (a.m_subtype == b.m_subtype) &&
+      (a.m_localLinkId == b.m_localLinkId) &&
+      (a.m_peerLinkId == b.m_peerLinkId) &&
+      (a.m_reasonCode == b.m_reasonCode)
+      );
+}
+#ifdef RUN_SELF_TESTS  
+struct IePeerManagementBist : public IeTest 
+{
+  IePeerManagementBist () : IeTest ("Mesh/802.11s/IE/PeerManagement") {}
+  virtual bool RunTests(); 
+};
+
+/// Test instance
+static IePeerManagementBist g_IePerrBist;
+
+bool IePeerManagementBist::RunTests ()
+{
+  bool result(true);
+  {
+    IePeerManagement a;
+    a.SetPeerOpen (1);
+    result = result && TestRoundtripSerialization (a);
+  }
+  {
+    IePeerManagement a;
+    a.SetPeerConfirm (1,2);
+    result = result && TestRoundtripSerialization (a);
+  }
+  {
+    IePeerManagement a;
+    a.SetPeerClose (1, 2, REASON11S_MESH_CAPABILITY_POLICY_VIOLATION);
+    result = result && TestRoundtripSerialization (a);
+  }
+  return result;
+}
+#endif
+} // namespace dot11s
+} //namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-peer-management.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,97 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ *          Aleksey Kovalenko <kovalenko@iitp.ru>
+ */
+
+
+#ifndef MESH_PEER_MAN_ELEMENT
+#define MESH_PEER_MAN_ELEMENT
+
+#include "ns3/wifi-information-element.h"
+
+namespace ns3 {
+namespace dot11s {
+
+/**
+ * \ingroup dot11s
+ * \brief Codes used by 802.11s Peer Management Protocol 
+ */
+enum PmpReasonCode {
+  REASON11S_PEERING_CANCELLED = 2, // according to open80211s
+  REASON11S_MESH_MAX_PEERS,
+  REASON11S_MESH_CAPABILITY_POLICY_VIOLATION,
+  REASON11S_MESH_CLOSE_RCVD,
+  REASON11S_MESH_MAX_RETRIES,
+  REASON11S_MESH_CONFIRM_TIMEOUT,
+  REASON11S_MESH_INVALID_GTK,
+  REASON11S_MESH_INCONSISTENT_PARAMETERS,
+  REASON11S_MESH_INVALID_SECURITY_CAPABILITY,
+  REASON11S_RESERVED,
+};
+  
+/**
+ * \ingroup dot11s
+ * \brief See 7.3.2.85 of draft 2.07
+ */
+class IePeerManagement : public WifiInformationElement
+{
+public:
+    IePeerManagement ();
+    enum Subtype {
+      PEER_OPEN    = 0,
+      PEER_CONFIRM,
+      PEER_CLOSE,
+    };
+  void   SetPeerOpen (uint16_t localLinkId);
+  void   SetPeerClose (uint16_t localLinkID, uint16_t peerLinkId, PmpReasonCode reasonCode);
+  void   SetPeerConfirm (uint16_t localLinkID, uint16_t peerLinkId);
+
+  PmpReasonCode GetReasonCode () const;
+  uint16_t  GetLocalLinkId () const;
+  uint16_t  GetPeerLinkId () const;
+  bool   SubtypeIsOpen () const;
+  bool   SubtypeIsClose () const;
+  bool   SubtypeIsConfirm () const ;
+  uint8_t GetSubtype() const { return m_subtype;};
+private:
+  WifiElementId ElementId () const{
+    return IE11S_PEERING_MANAGEMENT;
+  }
+  uint8_t  GetInformationSize (void) const;
+  void SerializeInformation (Buffer::Iterator i) const;
+  uint8_t DeserializeInformation (Buffer::Iterator i, uint8_t length);
+  void PrintInformation (std::ostream& os) const;
+private:
+  uint8_t   m_length;
+  uint8_t   m_subtype;
+  uint16_t  m_localLinkId;
+  /**
+   * Present within confirm and may be present in close
+   */
+  uint16_t  m_peerLinkId;
+  /**
+   * Present only within close frame
+   */
+  PmpReasonCode m_reasonCode;
+  friend bool operator== (const IePeerManagement & a, const IePeerManagement & b);
+};
+bool operator== (const IePeerManagement & a, const IePeerManagement & b);
+} // namespace dot11s
+} //namespace ns3
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-peering-protocol.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,67 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#include "ie-dot11s-peering-protocol.h"
+namespace ns3 {
+namespace dot11s {
+TypeId
+IePeeringProtocol::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::dot11s::IePeeringProtocol")
+    .SetParent<WifiInformationElement> ();
+  return tid;
+}
+
+TypeId
+IePeeringProtocol::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+uint8_t
+IePeeringProtocol::GetInformationSize () const
+{
+  return 1;
+}
+IePeeringProtocol::IePeeringProtocol ():
+  m_protocol(0)
+{
+}
+void
+IePeeringProtocol::SerializeInformation (Buffer::Iterator i) const
+{
+  i.WriteU8 (m_protocol);
+}
+
+uint8_t
+IePeeringProtocol::DeserializeInformation (Buffer::Iterator i, uint8_t length)
+{
+  Buffer::Iterator start = i;
+  m_protocol  = i.ReadU8 ();
+  return i.GetDistanceFrom (start);
+}
+void
+IePeeringProtocol::PrintInformation (std::ostream& os) const
+{
+  //TODO: print
+}
+} // namespace dot11s
+} //namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-peering-protocol.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,50 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#ifndef MESH_PERING_PROTOCOL_H
+#define MESH_PEERING_PROTOCOL_H
+
+#include "ns3/wifi-information-element.h"
+
+namespace ns3 {
+namespace dot11s {
+class IePeeringProtocol : public WifiInformationElement
+{
+public:
+  static TypeId GetTypeId ();
+  TypeId GetInstanceTypeId () const;
+
+  IePeeringProtocol ();
+private:
+  WifiElementId ElementId () const
+  {
+    return IE11S_MESH_PEERING_PROTOCOL_VERSION;
+  }
+  uint8_t  GetInformationSize () const;
+  void SerializeInformation (Buffer::Iterator i) const;
+  uint8_t DeserializeInformation (Buffer::Iterator i, uint8_t length);
+  void PrintInformation (std::ostream& os) const;
+private:
+  uint8_t m_protocol;
+};
+} // namespace dot11s
+} //namespace ns3
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-perr.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,200 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#include "ie-dot11s-perr.h"
+#include "ns3/address-utils.h"
+#include "ns3/node.h"
+#include "ns3/packet.h"
+#include "ns3/test.h"
+namespace ns3 {
+namespace dot11s {
+IePerr::~IePerr ()
+{
+}
+
+TypeId
+IePerr::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::dot11s::IePerr")
+                      .SetParent<Object> ();
+  return tid;
+}
+void
+IePerr::PrintInformation (std::ostream &os) const
+{
+    // FILL
+}
+TypeId
+IePerr::GetInstanceTypeId () const
+{
+    return GetTypeId ();
+}
+IePerr::IePerr ():
+    m_numOfDest (0)
+{
+}
+uint8_t
+IePerr::GetNumOfDest ()
+{
+  return m_numOfDest;
+}
+void
+IePerr::SerializeInformation (Buffer::Iterator i) const
+{
+  i.WriteU8 (0);
+  i.WriteU8 (m_numOfDest);
+  NS_ASSERT (m_numOfDest == m_addressUnits.size ());
+  for (unsigned int j = 0; j < m_numOfDest; j++)
+    {
+      WriteTo (i, m_addressUnits[j].destination);
+      i.WriteHtolsbU32 (m_addressUnits[j].seqnum);
+    }
+}
+uint8_t
+IePerr::DeserializeInformation (Buffer::Iterator start, uint8_t length)
+{
+  Buffer::Iterator i = start;
+  i.Next (1); //Mode flags is not used now
+  m_numOfDest = i.ReadU8 ();
+  NS_ASSERT ((2+10*m_numOfDest) == length);
+  length = 0; //to avoid compiler warning in optimized builds
+  for (unsigned int j = 0; j < m_numOfDest; j++)
+    {
+      FailedDestination unit;
+      ReadFrom (i,unit.destination);
+      unit.seqnum = i.ReadLsbtohU32 ();
+      m_addressUnits.push_back (unit);
+    }
+  return i.GetDistanceFrom (start);
+}
+
+uint8_t
+IePerr::GetInformationSize () const
+{
+  uint8_t retval =
+     1 //ModeFlags
+    +1 //NumOfDests
+    +6*m_numOfDest
+    +4*m_numOfDest;
+  return retval;
+}
+
+void
+IePerr::AddAddressUnit (FailedDestination unit)
+{
+  for (unsigned int i = 0; i < m_addressUnits.size (); i ++)
+    if (m_addressUnits[i].destination == unit.destination)
+      return;
+  m_addressUnits.push_back (unit);
+  m_numOfDest++;
+}
+
+std::vector<IePerr::FailedDestination>
+IePerr::GetAddressUnitVector () const
+{
+  return m_addressUnits;
+}
+void
+IePerr::DeleteAddressUnit (Mac48Address address)
+{
+  for (std::vector<FailedDestination>::iterator i = m_addressUnits.begin (); i != m_addressUnits.end(); i ++)
+    if (i->destination == address)
+      {
+        m_numOfDest --;
+        m_addressUnits.erase (i);
+        break;
+      }
+}
+void
+IePerr::Merge(const IePerr perr)
+{
+  std::vector<FailedDestination> to_merge = perr.GetAddressUnitVector ();
+  for (std::vector<FailedDestination>::iterator i = to_merge.begin (); i != to_merge.end(); i ++)
+  {
+    bool should_add = true;
+    for (std::vector<FailedDestination>::iterator j = m_addressUnits.begin (); j != m_addressUnits.end(); j ++)
+      if ((i->destination == j->destination) && (i->seqnum <= j->seqnum))
+        should_add = false;
+    if(should_add)
+      AddAddressUnit (*i);
+  }
+}
+void
+IePerr::ResetPerr ()
+{
+  m_numOfDest = 0;
+  m_addressUnits.clear ();
+}
+bool operator== (const IePerr & a, const IePerr & b)
+{
+  if(a.m_numOfDest != b.m_numOfDest)
+    return false;
+  for(unsigned int i = 0; i < a.m_addressUnits.size(); i ++)
+  {
+    if(a.m_addressUnits[i].destination != b.m_addressUnits[i].destination)
+      return false;
+    if(a.m_addressUnits[i].seqnum != b.m_addressUnits[i].seqnum)
+      return false;
+  }
+  return true;
+}
+#ifdef RUN_SELF_TESTS
+
+/// Built-in self test for IePreq
+struct IePerrBist : public IeTest 
+{
+  IePerrBist () : IeTest ("Mesh/802.11s/IE/PERR") {}
+  virtual bool RunTests(); 
+};
+
+/// Test instance
+static IePerrBist g_IePerrBist;
+
+bool IePerrBist::RunTests ()
+{
+  bool result(true);
+  // create test information element
+  IePerr a;
+  IePerr::FailedDestination dest;
+  dest.destination = Mac48Address("11:22:33:44:55:66");
+  dest.seqnum = 1;
+  a.AddAddressUnit(dest);
+  dest.destination = Mac48Address("10:20:30:40:50:60");
+  dest.seqnum = 2;
+  a.AddAddressUnit(dest);
+  dest.destination = Mac48Address("01:02:03:04:05:06");
+  dest.seqnum = 3;
+  a.AddAddressUnit(dest);
+  
+  IePerr b = a;
+  b.Merge(a);
+  NS_TEST_ASSERT_EQUAL (a, b);
+  
+  result = result && TestRoundtripSerialization (a);
+  return result;
+}
+
+#endif // RUN_SELF_TESTS
+
+} // namespace dot11s
+} //namespace ns3
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-perr.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,69 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#ifndef PERR_INFORMATION_ELEMENT_H
+#define PERR_INFORMATION_ELEMENT_H
+
+#include "ns3/mac48-address.h"
+#include "ns3/wifi-information-element.h"
+
+namespace ns3 {
+namespace dot11s {
+/**
+ * \ingroup dot11s
+ * \brief See 7.3.2.98 of 802.11s draft 2.07
+ */
+class IePerr : public WifiInformationElement
+{
+public:
+  IePerr ();
+  ~IePerr ();
+  static  TypeId   GetTypeId ();
+  virtual TypeId   GetInstanceTypeId () const;
+  struct FailedDestination
+  {
+    Mac48Address destination;
+    uint32_t seqnum;
+  };
+  uint8_t   GetNumOfDest ();
+
+  void AddAddressUnit (struct FailedDestination unit);
+  std::vector<FailedDestination> GetAddressUnitVector () const;
+  void DeleteAddressUnit (Mac48Address address);
+  void Merge(const IePerr perr);
+  void ResetPerr ();
+private:
+  WifiElementId ElementId () const{
+    return IE11S_PERR;
+  };
+  void  SerializeInformation (Buffer::Iterator i) const;
+  uint8_t  DeserializeInformation (Buffer::Iterator start, uint8_t length);
+  void PrintInformation (std::ostream& os) const;
+  uint8_t  GetInformationSize () const;
+private:
+  uint8_t   m_numOfDest;
+  std::vector<FailedDestination> m_addressUnits;
+  friend bool operator== (const IePerr & a, const IePerr & b);
+};
+  bool operator== (const IePerr & a, const IePerr & b);
+} // namespace dot11s
+} //namespace ns3
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-prep.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,264 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#include "ie-dot11s-prep.h"
+#include "ns3/address-utils.h"
+#include "ns3/node.h"
+#include "ns3/assert.h"
+#include "ns3/test.h"
+#include "ns3/packet.h"
+namespace ns3 {
+namespace dot11s {
+/********************************
+ * IePrep
+ *******************************/
+IePrep::~IePrep ()
+{
+}
+
+TypeId
+IePrep::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::dot11s::IePrep")
+                      .SetParent<Object> ();
+  return tid;
+}
+TypeId
+IePrep::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+IePrep::IePrep ():
+    m_flags (0),
+    m_hopcount (0),
+    m_ttl (0),
+    m_destinationAddress (Mac48Address::GetBroadcast()),
+    m_destSeqNumber (0),
+    m_lifetime (0),
+    m_metric (0),
+    m_originatorAddress (Mac48Address::GetBroadcast()),
+    m_originatorSeqNumber (0)
+{
+}
+void
+IePrep::SetFlags (uint8_t flags)
+{
+  m_flags = flags;
+}
+void
+IePrep::SetHopcount (uint8_t hopcount)
+{
+  m_hopcount = hopcount;
+}
+void
+IePrep::SetTtl (uint8_t ttl)
+{
+  m_ttl = ttl;
+}
+void
+IePrep::SetDestinationSeqNumber (uint32_t dest_seq_number)
+{
+  m_destSeqNumber = dest_seq_number;
+}
+void
+IePrep::SetDestinationAddress (Mac48Address dest_address)
+{
+  m_destinationAddress = dest_address;
+}
+void
+IePrep::SetMetric (uint32_t metric)
+{
+  m_metric = metric;
+}
+void
+IePrep::SetOriginatorAddress (Mac48Address originator_address)
+{
+  m_originatorAddress = originator_address;
+}
+void
+IePrep::SetOriginatorSeqNumber (uint32_t originator_seq_number)
+{
+  m_originatorSeqNumber = originator_seq_number;
+}
+void
+IePrep::SetLifetime (uint32_t lifetime)
+{
+  m_lifetime = lifetime;
+}
+uint8_t
+IePrep::GetFlags () const
+{
+  return m_flags;
+}
+uint8_t
+IePrep::GetHopcount () const
+{
+  return m_hopcount;
+}
+uint32_t
+IePrep::GetTtl () const
+{
+  return m_ttl;
+}
+uint32_t
+IePrep::GetDestinationSeqNumber () const
+{
+  return m_destSeqNumber;
+}
+Mac48Address
+IePrep::GetDestinationAddress () const
+{
+  return m_destinationAddress;
+}
+uint32_t
+IePrep::GetMetric () const
+{
+  return m_metric;
+}
+Mac48Address
+IePrep::GetOriginatorAddress () const
+{
+  return m_originatorAddress;
+}
+uint32_t
+IePrep::GetOriginatorSeqNumber () const
+{
+  return m_originatorSeqNumber;
+}
+uint32_t
+IePrep::GetLifetime () const
+{
+  return m_lifetime;
+}
+void
+IePrep::DecrementTtl ()
+{
+  m_ttl --;
+}
+
+void
+IePrep::IncrementMetric (uint32_t metric)
+{
+  m_metric +=metric;
+}
+
+
+void
+IePrep::SerializeInformation (Buffer::Iterator i) const
+{
+  i.WriteU8 (m_flags);
+  i.WriteU8 (m_hopcount);
+  i.WriteU8 (m_ttl);
+  WriteTo (i, m_destinationAddress);
+  i.WriteHtolsbU32 (m_destSeqNumber);
+  i.WriteHtolsbU32 (m_lifetime);
+  i.WriteHtolsbU32 (m_metric);
+  WriteTo (i, m_originatorAddress);
+  i.WriteHtolsbU32 (m_originatorSeqNumber);
+}
+uint8_t
+IePrep::DeserializeInformation (Buffer::Iterator start, uint8_t length)
+{
+  Buffer::Iterator i = start;
+  m_flags = i.ReadU8 ();
+  m_hopcount = i.ReadU8 ();
+  m_ttl = i.ReadU8 ();
+  ReadFrom (i, m_destinationAddress);
+  m_destSeqNumber = i.ReadLsbtohU32 ();
+  m_lifetime = i.ReadLsbtohU32 ();
+  m_metric = i.ReadLsbtohU32 ();
+  ReadFrom (i, m_originatorAddress);
+  m_originatorSeqNumber = i.ReadLsbtohU32 ();
+  return i.GetDistanceFrom (start);
+}
+uint8_t
+IePrep::GetInformationSize () const
+{
+  uint32_t retval =
+     1 //Flags
+    +1 //Hopcount
+    +1 //Ttl
+    +6 //Dest address
+    +4 //Dest seqno
+    +4 //Lifetime
+    +4 //metric
+    +6 //Originator address
+    +4 //Originator seqno
+    +1; //destination count
+  return retval;
+};
+void
+IePrep::PrintInformation (std::ostream& os) const
+{
+  //TODO
+}
+bool operator== (const IePrep & a, const IePrep & b)
+{
+  return (
+      (a.m_flags == b.m_flags) &&
+      (a.m_hopcount == b.m_hopcount) &&
+      (a.m_ttl == b.m_ttl) &&
+      (a.m_destinationAddress == b.m_destinationAddress) &&
+      (a.m_destSeqNumber == b.m_destSeqNumber) && 
+      (a.m_lifetime == b.m_lifetime) &&
+      (a.m_metric == b.m_metric) &&
+      (a.m_originatorAddress == b.m_originatorAddress) &&
+      (a.m_originatorSeqNumber == b.m_originatorSeqNumber)
+      );
+}
+
+#ifdef RUN_SELF_TESTS
+
+/// Built-in self test for IePrep
+struct IePrepBist : public IeTest 
+{
+  IePrepBist () : IeTest ("Mesh/802.11s/IE/PREP") {};
+  virtual bool RunTests(); 
+};
+
+/// Test instance
+static IePrepBist g_IePrepBist;
+
+bool IePrepBist::RunTests ()
+{
+  bool result(true);
+  
+  // create test information element
+  IePrep a;
+  a.SetFlags (12);
+  a.SetHopcount (11);
+  a.SetTtl (10);
+  a.SetDestinationAddress (Mac48Address("11:22:33:44:55:66"));
+  a.SetDestinationSeqNumber (123);
+  a.SetLifetime (5000);
+  a.SetMetric (4321);
+  a.SetOriginatorAddress (Mac48Address("33:00:22:00:11:00"));
+  a.SetOriginatorSeqNumber (666);
+  
+  result = result && TestRoundtripSerialization (a);
+  return result;
+}
+
+#endif // RUN_SELF_TESTS
+ 
+} // namespace dot11s
+} //namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-prep.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,88 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#ifndef WIFI_PREP_INFORMATION_ELEMENT_H
+#define WIFI_PREP_INFORMATION_ELEMENT_H
+
+
+#include "ns3/mac48-address.h"
+#include "ns3/wifi-information-element.h"
+
+namespace ns3 {
+namespace dot11s {
+/**
+ * \ingroup dot11s
+ * \brief See 7.3.2.97 of 802.11s draft 2.07
+ */
+class IePrep : public WifiInformationElement
+{
+public:
+  IePrep ();
+  ~IePrep ();
+  static TypeId GetTypeId ();
+  virtual TypeId GetInstanceTypeId () const;
+  void SetFlags (uint8_t flags);
+  void SetHopcount (uint8_t hopcount);
+  void SetTtl (uint8_t ttl);
+  void SetDestinationAddress (Mac48Address dest_address);
+  void SetDestinationSeqNumber (uint32_t dest_seq_number);
+  void SetLifetime (uint32_t lifetime);
+  void SetMetric (uint32_t metric);
+  void SetOriginatorAddress (Mac48Address originator_address);
+  void SetOriginatorSeqNumber (uint32_t originator_seq_number);
+ 
+  uint8_t GetFlags () const;
+  uint8_t GetHopcount () const;
+  uint32_t GetTtl () const;
+  Mac48Address GetDestinationAddress () const;
+  uint32_t GetDestinationSeqNumber () const;
+  uint32_t GetLifetime () const;
+  uint32_t GetMetric () const;
+  Mac48Address GetOriginatorAddress () const;
+  uint32_t GetOriginatorSeqNumber ()const ;
+
+  void  DecrementTtl ();
+  void  IncrementMetric (uint32_t metric);
+private:
+  WifiElementId ElementId () const{
+    return IE11S_PREP;
+  }
+  void SerializeInformation (Buffer::Iterator i) const;
+  uint8_t DeserializeInformation (Buffer::Iterator start, uint8_t length);
+  uint8_t GetInformationSize () const;
+  void PrintInformation (std::ostream& os) const;
+private:
+  uint8_t  m_flags;
+  uint8_t  m_hopcount;
+  uint8_t  m_ttl;
+  Mac48Address m_destinationAddress;
+  uint32_t m_destSeqNumber;
+  uint32_t m_lifetime;
+  uint32_t m_metric;
+  Mac48Address m_originatorAddress;
+  uint32_t m_originatorSeqNumber;
+  friend bool operator== (const IePrep & a, const IePrep & b);
+};
+bool operator== (const IePrep & a, const IePrep & b); 
+} // namespace dot11s
+} //namespace ns3
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-preq.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,468 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#include "ie-dot11s-preq.h"
+#include "ns3/address-utils.h"
+#include "ns3/node.h"
+#include "ns3/assert.h"
+#include "ns3/test.h"
+#include "ns3/packet.h"
+
+namespace ns3 {
+namespace dot11s {
+/*************************
+ * DestinationAddressUnit
+ ************************/
+DestinationAddressUnit::DestinationAddressUnit ():
+  m_do (false),
+  m_rf (false),
+  m_usn (false),
+  m_destinationAddress (Mac48Address ()),
+  m_destSeqNumber (0)
+{
+}
+void
+DestinationAddressUnit::SetFlags (bool doFlag, bool rfFlag, bool usnFlag)
+{
+  m_do = doFlag;
+  m_rf = rfFlag;
+  m_usn = usnFlag;
+}
+
+void
+DestinationAddressUnit::SetDestSeqNumber (uint32_t dest_seq_number)
+{
+  m_destSeqNumber = dest_seq_number;
+  if(m_destSeqNumber != 0)
+    m_usn = true;
+}
+void
+DestinationAddressUnit::SetDestinationAddress (Mac48Address dest_address)
+{
+  m_destinationAddress = dest_address;
+}
+bool
+DestinationAddressUnit::IsDo ()
+{
+  return m_do;
+}
+
+bool
+DestinationAddressUnit::IsRf ()
+{
+  return m_rf;
+}
+bool
+DestinationAddressUnit::IsUsn ()
+{
+  return m_usn;
+}
+uint32_t
+DestinationAddressUnit::GetDestSeqNumber () const
+{
+  return m_destSeqNumber;
+}
+Mac48Address
+DestinationAddressUnit::GetDestinationAddress () const
+{
+  return m_destinationAddress;
+}
+/********************************
+ * IePreq
+ *******************************/
+IePreq::~IePreq ()
+{
+}
+
+TypeId
+IePreq::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::dot11s::IePreq")
+                      .SetParent<Object> ();
+  return tid;
+}
+TypeId
+IePreq::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+
+IePreq::IePreq ():
+    m_maxSize (32),
+    m_flags (0),
+    m_hopCount (0),
+    m_ttl (0),
+    m_preqId (0),
+    m_originatorAddress (Mac48Address::GetBroadcast()),
+    m_originatorSeqNumber (0),
+    m_lifetime (0),
+    m_metric (0),
+    m_destCount (0)
+{
+}
+void
+IePreq::SetUnicastPreq ()
+{
+  m_flags |= 1<<1;
+}
+
+void
+IePreq::SetNeedNotPrep ()
+{
+  m_flags |= 1<<2;
+}
+//void
+//IePreq::SetFlags (uint8_t flags)
+//{
+// m_flags = flags;
+//}
+void
+IePreq::SetHopcount (uint8_t hopcount)
+{
+  m_hopCount = hopcount;
+}
+void
+IePreq::SetTTL (uint8_t ttl)
+{
+  m_ttl = ttl;
+}
+void
+IePreq::SetPreqID (uint32_t preq_id)
+{
+  m_preqId = preq_id;
+}
+void
+IePreq::SetMetric (uint32_t metric)
+{
+  m_metric = metric;
+}
+void
+IePreq::SetOriginatorAddress (Mac48Address originator_address)
+{
+  m_originatorAddress = originator_address;
+}
+void
+IePreq::SetOriginatorSeqNumber (uint32_t originator_seq_number)
+{
+  m_originatorSeqNumber = originator_seq_number;
+}
+void
+IePreq::SetLifetime (uint32_t lifetime)
+{
+  m_lifetime = lifetime;
+}
+void
+IePreq::SetDestCount (uint8_t dest_count)
+{
+  m_destCount = dest_count;
+}
+bool
+IePreq::IsUnicastPreq () const
+{
+  return (m_flags & (1<<1));
+}
+bool
+IePreq::IsNeedNotPrep () const
+{
+  return (m_flags & (1<<2));
+}
+uint8_t
+IePreq::GetHopCount () const
+{
+  return m_hopCount;
+}
+uint8_t
+IePreq::GetTtl () const
+{
+  return m_ttl;
+}
+uint32_t
+IePreq::GetPreqID () const
+{
+  return m_preqId;
+}
+uint32_t
+IePreq::GetMetric () const
+{
+  return m_metric;
+}
+Mac48Address
+IePreq::GetOriginatorAddress () const
+{
+  return m_originatorAddress;
+}
+uint32_t
+IePreq::GetOriginatorSeqNumber () const
+{
+  return m_originatorSeqNumber;
+}
+uint32_t
+IePreq::GetLifetime () const
+{
+  return m_lifetime;
+}
+
+uint8_t
+IePreq::GetDestCount () const
+{
+  return m_destCount;
+}
+void
+IePreq::DecrementTtl ()
+{
+  m_ttl --;
+  m_hopCount ++;
+}
+void
+IePreq::IncrementMetric (uint32_t metric)
+{
+  m_metric +=metric;
+}
+void
+IePreq::SerializeInformation (Buffer::Iterator i) const
+{
+  i.WriteU8 (m_flags);
+  i.WriteU8 (m_hopCount);
+  i.WriteU8 (m_ttl);
+  i.WriteHtolsbU32 (m_preqId);
+  WriteTo (i, m_originatorAddress);
+  i.WriteHtolsbU32 (m_originatorSeqNumber);
+  i.WriteHtolsbU32 (m_lifetime);
+  i.WriteHtolsbU32 (m_metric);
+  i.WriteU8 (m_destCount);
+  int written = 0;
+  for (std::vector<Ptr<DestinationAddressUnit> >::const_iterator j = m_destinations.begin (); j != m_destinations.end(); j++)
+    {
+      uint8_t flags = 0;
+      if ((*j)->IsDo ())
+        flags += 128;
+      if ((*j)->IsRf ())
+        flags += 64;
+      if((*j)->IsUsn ())
+        flags += 32;
+      i.WriteU8 (flags);
+      WriteTo (i, (*j)->GetDestinationAddress());
+      i.WriteHtolsbU32 ((*j)->GetDestSeqNumber ());
+      written++;
+      if (written > m_maxSize)
+        break;
+    }
+}
+uint8_t
+IePreq::DeserializeInformation (Buffer::Iterator start, uint8_t length)
+{
+  Buffer::Iterator i = start;
+  m_flags = i.ReadU8 ();
+  m_hopCount = i.ReadU8 ();
+  m_ttl = i.ReadU8 ();
+  m_preqId = i.ReadLsbtohU32 ();
+  ReadFrom (i, m_originatorAddress);
+  m_originatorSeqNumber = i.ReadLsbtohU32 ();
+  m_lifetime = i.ReadLsbtohU32 ();
+  m_metric = i.ReadLsbtohU32 ();
+  m_destCount = i.ReadU8 ();
+  for (int j = 0; j < m_destCount; j++ )
+    {
+      Ptr<DestinationAddressUnit> new_element = Create<DestinationAddressUnit> ();
+      bool doFlag = false;
+      bool rfFlag = false;
+      bool usnFlag = false;
+      uint8_t flags = i.ReadU8 ();
+      if (flags >= 128)
+        {
+          doFlag = true;
+          flags -=128;
+        }
+      if (flags >=64)
+      {
+        rfFlag = true;
+        flags -= 64;
+      }
+      if (flags >= 32)
+        usnFlag = true;
+      new_element->SetFlags (doFlag, rfFlag, usnFlag);
+      Mac48Address addr;
+      ReadFrom (i,addr);
+      new_element->SetDestinationAddress (addr);
+      new_element->SetDestSeqNumber (i.ReadLsbtohU32());
+      m_destinations.push_back (new_element);
+      NS_ASSERT (28+j*11 < length);
+    }
+  return i.GetDistanceFrom (start);
+}
+uint8_t
+IePreq::GetInformationSize () const
+{
+  uint8_t retval =
+     1 //Flags
+    +1 //Hopcount
+    +1 //TTL
+    +4 //PREQ ID
+    +6 //Source address (originator)
+    +4 //Originator seqno
+    +4 //Lifetime
+    +4 //metric
+    +1; //destination count
+  if (m_destCount > m_maxSize)
+     retval += (m_maxSize*11);
+  else
+     retval += (m_destCount*11);
+  return retval;
+}
+void
+IePreq::PrintInformation (std::ostream &os) const
+{
+  os << " originator address  = " << m_originatorAddress << "\n";
+  os << " TTL                 = "  <<  (uint16_t)m_ttl << "\n";
+  os << " hop count           = "  <<  (uint16_t)m_hopCount << "\n";
+  os << " metric              = " << m_metric << "\n";
+  os << " seqno               = " << m_originatorSeqNumber << "\n";
+  os << " lifetime            = " << m_lifetime << "\n";
+  os << " preq ID             = " <<m_preqId << "\n";
+  os << " Destinations are:\n";
+  for (int j = 0; j < m_destCount; j++ )
+    os << "    " << m_destinations[j]->GetDestinationAddress () << "\n";
+}
+std::vector<Ptr<DestinationAddressUnit> >
+IePreq::GetDestinationList ()
+{
+  return m_destinations;
+}
+void
+IePreq::AddDestinationAddressElement (
+  bool doFlag, bool rfFlag,
+  Mac48Address dest_address,
+  uint32_t dest_seq_number
+)
+{
+  for (std::vector<Ptr<DestinationAddressUnit> >::const_iterator i = m_destinations.begin (); i != m_destinations.end(); i++ )
+    if ((*i)->GetDestinationAddress () == dest_address)
+      return;
+  Ptr<DestinationAddressUnit>new_element = Create<DestinationAddressUnit> ();
+  new_element->SetFlags (doFlag, rfFlag, false);
+  new_element->SetDestinationAddress (dest_address);
+  new_element->SetDestSeqNumber (dest_seq_number);
+  m_destinations.push_back (new_element);
+  m_destCount++;
+}
+void
+IePreq::DelDestinationAddressElement (Mac48Address dest_address)
+{
+  for (std::vector<Ptr<DestinationAddressUnit> >::iterator i = m_destinations.begin (); i != m_destinations.end(); i++)
+    if ((*i)->GetDestinationAddress () == dest_address)
+      {
+        m_destinations.erase (i);
+        m_destCount--;
+        break;
+      }
+}
+void
+IePreq::ClearDestinationAddressElement ()
+{
+  int i;
+  for (std::vector<Ptr<DestinationAddressUnit> >::iterator j = m_destinations.begin (); j != m_destinations.end(); j++)
+    (*j) = 0;
+  for (i = 0; i < m_destCount; i ++)
+    m_destinations.pop_back ();
+  m_destinations.clear ();
+}
+bool operator== (const DestinationAddressUnit & a, const DestinationAddressUnit & b)
+{
+  return (a.m_do == b.m_do 
+      &&  a.m_rf == b.m_rf
+      &&  a.m_usn == b.m_usn
+      &&  a.m_destinationAddress == b.m_destinationAddress
+      &&  a.m_destSeqNumber == b.m_destSeqNumber
+    );
+}
+bool operator== (const IePreq & a, const IePreq & b)
+{
+  bool ok = ( a.m_flags == b.m_flags 
+    && a.m_hopCount == b.m_hopCount
+    && a.m_ttl == b.m_ttl
+    && a.m_preqId == b.m_preqId 
+    && a.m_originatorAddress == b.m_originatorAddress
+    && a.m_originatorSeqNumber == b.m_originatorSeqNumber
+    && a.m_lifetime == b.m_lifetime
+    && a.m_metric == b.m_metric
+    && a.m_destCount == b.m_destCount
+  );
+  
+  if (! ok) 
+    return false;
+  
+  if (a.m_destinations.size() != b.m_destinations.size())
+    return false;
+  
+  for (size_t i = 0; i < a.m_destinations.size(); ++i)
+    if (!( *(PeekPointer (a.m_destinations[i])) == 
+           *(PeekPointer (b.m_destinations[i]))
+         )
+       )
+      return false;
+  
+  return true;
+}
+bool
+IePreq::MayAddAddress (Mac48Address originator)
+{
+  if (m_originatorAddress != originator)
+    return false;
+  if(m_destinations[0]->GetDestinationAddress () == Mac48Address::GetBroadcast ())
+    return false;
+  return true;
+}
+#ifdef RUN_SELF_TESTS
+
+/// Built-in self test for IePreq
+struct IePreqBist : public IeTest 
+{
+  IePreqBist () : IeTest ("Mesh/802.11s/IE/PREQ") {}
+  virtual bool RunTests(); 
+};
+
+/// Test instance
+static IePreqBist g_IePreqBist;
+
+bool IePreqBist::RunTests ()
+{
+  bool result(true);
+  
+  // create test information element
+  IePreq a;
+  a.SetHopcount (0);
+  a.SetTTL (1);
+  a.SetPreqID (2);
+  a.SetOriginatorAddress ( Mac48Address("11:22:33:44:55:66") );
+  a.SetOriginatorSeqNumber (3);
+  a.SetLifetime (4);
+  a.AddDestinationAddressElement (false, false, Mac48Address("11:11:11:11:11:11"), 5);
+  a.AddDestinationAddressElement (false, false, Mac48Address("22:22:22:22:22:22"), 6);
+
+  result = result && TestRoundtripSerialization (a);
+  return result;
+}
+
+#endif // RUN_SELF_TESTS
+  
+} // namespace dot11s
+} //namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-preq.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,145 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#ifndef WIFI_PREQ_INFORMATION_ELEMENT_H
+#define WIFI_PREQ_INFORMATION_ELEMENT_H
+
+#include <vector>
+
+#include "ns3/mac48-address.h"
+#include "ns3/wifi-information-element.h"
+
+namespace ns3 {
+namespace dot11s {
+/**
+ * \ingroup dot11s
+ * \brief Describes an address unit in PREQ information element
+ * See 7.3.2.96 for more details
+ */
+class DestinationAddressUnit : public RefCountBase
+{
+public:
+  DestinationAddressUnit ();
+  void SetFlags (bool doFlag, bool rfFlag, bool usnFlag);
+  void SetDestinationAddress (Mac48Address dest_address);
+  void SetDestSeqNumber (uint32_t dest_seq_number);
+  bool IsDo ();
+  bool IsRf ();
+  bool IsUsn ();
+  Mac48Address GetDestinationAddress () const;
+  uint32_t GetDestSeqNumber () const;
+private:
+  bool m_do;
+  bool m_rf;
+  bool m_usn;
+  Mac48Address m_destinationAddress;
+  uint32_t m_destSeqNumber;
+  
+  friend bool operator== (const DestinationAddressUnit & a, const DestinationAddressUnit & b);
+};
+/**
+ * \ingroup dot11s
+ * \brief See 7.3.2.96 of 802.11s draft 2.07
+ */
+class IePreq : public WifiInformationElement
+{
+public:
+  IePreq ();
+  ~IePreq ();
+  static TypeId GetTypeId ();
+  virtual TypeId GetInstanceTypeId () const;
+  void AddDestinationAddressElement (
+    bool doFlag,
+    bool rfFlag,
+    Mac48Address dest_address,
+    uint32_t dest_seq_number
+  );
+  void DelDestinationAddressElement (Mac48Address dest_address);
+  void ClearDestinationAddressElement ();
+  std::vector<Ptr<DestinationAddressUnit> > GetDestinationList ();
+  void SetUnicastPreq ();
+  /*
+   * \brief In proactive case: need we send PREP
+   */
+  void SetNeedNotPrep ();
+  void SetHopcount (uint8_t hopcount);
+  void SetTTL (uint8_t ttl);
+  void SetPreqID (uint32_t id);
+  void SetOriginatorAddress (Mac48Address originator_address);
+  void SetOriginatorSeqNumber (uint32_t originator_seq_number);
+  void SetLifetime (uint32_t lifetime);
+  void SetMetric (uint32_t metric);
+  void SetDestCount (uint8_t dest_count);
+
+  bool  IsUnicastPreq () const;
+  bool  IsNeedNotPrep () const;
+  uint8_t  GetHopCount () const;
+  uint8_t  GetTtl ()const ;
+  uint32_t GetPreqID () const;
+  Mac48Address GetOriginatorAddress () const;
+  uint32_t GetOriginatorSeqNumber () const;
+  uint32_t GetLifetime () const;
+  uint32_t GetMetric () const;
+  uint8_t  GetDestCount () const;
+  void  DecrementTtl ();
+  void  IncrementMetric (uint32_t metric);
+  /*
+   * \brief Checks that preq's originator address equals to originator, and
+   * this preq is not proactive
+   */
+  bool MayAddAddress(Mac48Address originator);
+
+private:
+  WifiElementId ElementId () const{
+    return IE11S_PREQ;
+  }
+  void SerializeInformation (Buffer::Iterator i) const;
+  uint8_t DeserializeInformation (Buffer::Iterator i, uint8_t length);
+  uint8_t GetInformationSize () const;
+  void PrintInformation (std::ostream& os) const;
+  /**
+   * how many destinations we support
+   */
+  uint8_t m_maxSize; //TODO: make as an attrubute
+  /**
+   * Fields of information element:
+   */
+  uint8_t m_flags;
+  uint8_t m_hopCount;
+  uint8_t m_ttl;
+  uint32_t m_preqId;
+  Mac48Address m_originatorAddress;
+  uint32_t m_originatorSeqNumber;
+  uint32_t m_lifetime;
+  uint32_t m_metric;
+  uint8_t  m_destCount;
+  std::vector<Ptr<DestinationAddressUnit> >  m_destinations;
+  
+  friend bool operator== (const IePreq & a, const IePreq & b);
+};
+
+bool operator== (const DestinationAddressUnit & a, const DestinationAddressUnit & b);
+bool operator== (const IePreq & a, const IePreq & b);
+
+} // namespace dot11s
+} //namespace ns3
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-rann.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,224 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#include "ie-dot11s-rann.h"
+#include "ns3/assert.h"
+#include "ns3/address-utils.h"
+#include "ns3/node.h"
+#include "ns3/packet.h"
+#include "ns3/test.h"
+
+namespace ns3 {
+namespace dot11s {
+
+IeRann::~IeRann ()
+{
+}
+TypeId
+IeRann::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::dot11s::IeRann").SetParent<Object> ();
+  return tid;
+}
+TypeId
+IeRann::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+IeRann::IeRann ():
+    m_flags (0),
+    m_hopcount (0),
+    m_ttl (0),
+    m_originatorAddress (Mac48Address::GetBroadcast()),
+    m_destSeqNumber (0),
+    m_metric (0)
+{
+}
+void
+IeRann::SetFlags (uint8_t flags)
+{
+  m_flags = flags;
+}
+void
+IeRann::SetHopcount (uint8_t hopcount)
+{
+  m_hopcount = hopcount;
+}
+void
+IeRann::SetTTL (uint8_t ttl)
+{
+  m_ttl = ttl;
+}
+void
+IeRann::SetDestSeqNumber (uint32_t dest_seq_number)
+{
+  m_destSeqNumber = dest_seq_number;
+}
+void
+IeRann::SetMetric (uint32_t metric)
+{
+  m_metric = metric;
+}
+void
+IeRann::SetOriginatorAddress (Mac48Address originator_address)
+{
+  m_originatorAddress = originator_address;
+}
+
+uint8_t
+IeRann::GetFlags ()
+{
+  return m_flags;
+}
+uint8_t
+IeRann::GetHopcount ()
+{
+  return m_hopcount;
+}
+uint8_t
+IeRann::GetTtl ()
+{
+  return m_ttl;
+}
+uint32_t
+IeRann::GetDestSeqNumber ()
+{
+  return m_destSeqNumber;
+}
+uint32_t
+IeRann::GetMetric ()
+{
+  return m_metric;
+}
+void
+IeRann::DecrementTtl ()
+{
+  m_ttl --;
+  m_hopcount ++;
+}
+
+void 
+IeRann::IncrementMetric (uint32_t m)
+{
+  m_metric += m;
+}
+
+Mac48Address
+IeRann::GetOriginatorAddress ()
+{
+  return m_originatorAddress;
+}
+void
+IeRann::SerializeInformation (Buffer::Iterator i) const
+{
+  i.WriteU8 (m_flags);
+  i.WriteU8 (m_hopcount);
+  i.WriteU8 (m_ttl);
+  WriteTo (i, m_originatorAddress);
+  i.WriteHtolsbU32 (m_destSeqNumber);
+  i.WriteHtolsbU32 (m_metric);
+}
+uint8_t
+IeRann::DeserializeInformation (Buffer::Iterator start, uint8_t length)
+{
+  Buffer::Iterator i = start;
+  m_flags = i.ReadU8 ();
+  m_hopcount = i.ReadU8 ();
+  m_ttl = i.ReadU8 ();
+  ReadFrom (i, m_originatorAddress);
+  m_destSeqNumber = i.ReadLsbtohU32 ();
+  m_metric = i.ReadLsbtohU32 ();
+  return i.GetDistanceFrom (start);
+}
+uint8_t
+IeRann::GetInformationSize () const
+{
+  uint8_t retval =
+     1 //Flags
+    +1 //Hopcount
+    +1 //TTL
+    +6 //OriginatorAddress
+    +4 //DestSeqNumber
+    +4;//Metric
+  return retval;
+}
+
+void 
+IeRann::PrintInformation (std::ostream &os) const
+{
+  os << "  flags              = " << (int)m_flags       << "\n";
+  os << "  hop count          = " << (int)m_hopcount    << "\n";
+  os << "  TTL                = " << (int)m_ttl         << "\n";
+  os << "  originator address = " << m_originatorAddress<< "\n";
+  os << "  dst seq. number    = " << m_destSeqNumber    << "\n";
+  os << "  metric             = " << m_metric           << "\n";
+}
+
+bool
+operator== (const IeRann & a, const IeRann & b)
+{
+  return (a.m_flags == b.m_flags 
+      &&  a.m_hopcount == b.m_hopcount 
+      &&  a.m_ttl == b.m_ttl
+      &&  a.m_originatorAddress == b.m_originatorAddress
+      &&  a.m_destSeqNumber == b.m_destSeqNumber
+      &&  a.m_metric == b.m_metric 
+      );
+}
+  
+#ifdef RUN_SELF_TESTS
+
+/// Built-in self test for IeRann
+struct IeRannBist : public IeTest
+{
+  IeRannBist () : IeTest ("Mesh/802.11s/IE/RANN") {}
+  virtual bool RunTests(); 
+};
+
+/// Test instance
+static IeRannBist g_IeRannBist;
+
+bool IeRannBist::RunTests ()
+{
+  bool result(true);
+  
+  // create test information element
+  IeRann a;
+  
+  a.SetFlags (1);
+  a.SetHopcount (2);
+  a.SetTTL (4);
+  a.DecrementTtl ();
+  NS_TEST_ASSERT_EQUAL (a.GetTtl(), 3);
+  a.SetOriginatorAddress (Mac48Address ("11:22:33:44:55:66"));
+  a.SetDestSeqNumber (5);
+  a.SetMetric (6);
+  a.IncrementMetric (2);
+  NS_TEST_ASSERT_EQUAL (a.GetMetric(), 8);
+  
+  result = result && TestRoundtripSerialization (a);
+  return result;
+}
+#endif // RUN_SELF_TESTS
+
+}} // namespace ns3::dot11s
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/ie-dot11s-rann.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,80 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+
+#ifndef RANN_INFORMATION_ELEMENT_H
+#define RANN_INFORMATION_ELEMENT_H
+
+#include "ns3/mac48-address.h"
+#include "ns3/wifi-information-element.h"
+
+namespace ns3 {
+namespace dot11s {
+/**
+ * \ingroup dot11s
+ * \brief See 7.3.2.95 of 802.11s draft 2.07
+ */
+class IeRann : public WifiInformationElement
+{
+public:
+  IeRann ();
+  virtual ~IeRann ();
+  static TypeId GetTypeId ();
+  virtual TypeId GetInstanceTypeId () const;
+  void SetFlags (uint8_t flags);
+  void SetHopcount (uint8_t hopcount);
+  void SetTTL (uint8_t ttl);
+  void SetOriginatorAddress (Mac48Address originator_address);
+  void SetDestSeqNumber (uint32_t dest_seq_number);
+  void SetMetric (uint32_t metric);
+  uint8_t GetFlags ();
+  uint8_t GetHopcount ();
+  uint8_t GetTtl ();
+  Mac48Address GetOriginatorAddress ();
+  uint32_t GetDestSeqNumber ();
+  uint32_t GetMetric ();
+  void DecrementTtl ();
+  void IncrementMetric (uint32_t metric);
+    
+private:
+  WifiElementId ElementId () const{
+    return IE11S_RANN;
+  }
+  void SerializeInformation (Buffer::Iterator i) const;
+  uint8_t DeserializeInformation (Buffer::Iterator start, uint8_t length);
+  uint8_t GetInformationSize () const;
+  void PrintInformation (std::ostream &os) const;
+  
+  uint8_t m_flags;
+  uint8_t m_hopcount;
+  uint8_t m_ttl;
+  Mac48Address m_originatorAddress;
+  uint32_t m_destSeqNumber;
+  uint32_t m_metric;
+  
+  friend bool operator== (const IeRann & a, const IeRann & b);
+};
+
+bool operator== (const IeRann & a, const IeRann & b);
+
+} // namespace dot11s
+} //namespace ns3
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/peer-link-frame.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,253 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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
+ * 
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ */
+
+#include "peer-link-frame.h"
+#include "ie-dot11s-peer-management.h"
+#include "ns3/mesh-wifi-interface-mac.h"
+#include "ns3/test.h"
+#include "ns3/packet.h"
+
+namespace ns3 {
+namespace dot11s {
+NS_OBJECT_ENSURE_REGISTERED (PeerLinkFrameStart);
+
+PeerLinkFrameStart::PeerLinkFrameStart ():
+  m_subtype (255),
+  m_capability (0),
+  m_aid (0),
+  m_rates (SupportedRates()),
+  m_meshId (IeMeshId()),
+  m_config(IeConfiguration ()),
+  m_reasonCode ((uint16_t)REASON11S_RESERVED)
+{
+}
+void
+PeerLinkFrameStart::SetPlinkFrameSubtype(uint8_t subtype)
+{
+  m_subtype = subtype;
+}
+void
+PeerLinkFrameStart::SetPlinkFrameStart(PeerLinkFrameStart::PlinkFrameStartFields fields)
+{
+  m_subtype = fields.subtype;
+  m_protocol = fields.protocol;
+  if(m_subtype != (uint8_t)(WifiMeshActionHeader::PEER_LINK_CLOSE))
+    m_capability = fields.capability;
+  if(m_subtype == (uint8_t)(WifiMeshActionHeader::PEER_LINK_CONFIRM))
+    m_aid = fields.aid;
+  if(m_subtype != (uint8_t)(WifiMeshActionHeader::PEER_LINK_CLOSE))
+    m_rates = fields.rates;
+  if(m_subtype != (uint8_t)(WifiMeshActionHeader::PEER_LINK_CONFIRM))
+    m_meshId = fields.meshId;
+  if(m_subtype != (uint8_t)(WifiMeshActionHeader::PEER_LINK_CLOSE))
+    m_config = fields.config;
+  else
+    m_reasonCode = fields.reasonCode;
+}
+PeerLinkFrameStart::PlinkFrameStartFields
+PeerLinkFrameStart::GetFields ()
+{
+  PlinkFrameStartFields retval;
+  //TODO: protocol version:
+  retval.subtype = m_subtype;
+  retval.capability = m_capability;
+  retval.aid = m_aid;
+  retval.rates = m_rates;
+  retval.meshId = m_meshId;
+  retval.config = m_config;
+  retval.reasonCode = m_reasonCode;
+  return retval;
+}
+TypeId
+PeerLinkFrameStart::GetTypeId ()
+{
+  static TypeId tid =
+    TypeId ("ns3::dot11s::PeerLinkFrameStart")
+    .SetParent<Header> ()
+    .AddConstructor<PeerLinkFrameStart> ()
+    ;
+  return tid;
+}
+TypeId
+PeerLinkFrameStart::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+void
+PeerLinkFrameStart::Print (std::ostream &os) const
+{
+  os << "subtype = " << (uint16_t)m_subtype
+  << "\ncapability = " << m_capability
+  << "\naid = " << (uint16_t)m_aid
+  << "\nrates = " << m_rates
+  << "\nmeshId = " << m_meshId
+  << "\nconfiguration = " << m_config
+  << "\nreason code = " << m_reasonCode;
+}
+uint32_t
+PeerLinkFrameStart::GetSerializedSize () const
+{
+  uint32_t size = 3; //Peering protocol
+  NS_ASSERT(m_subtype < 3);
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    size += 2;  //capability
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CONFIRM) == m_subtype)
+    size += 2; //AID of remote peer
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    size += m_rates.GetSerializedSize ();
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CONFIRM) != m_subtype)
+    size += m_meshId.GetSerializedSize ();
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    size += m_config.GetSerializedSize ();
+  else
+    size += 2; //reasonCode
+  return size;
+}
+void
+PeerLinkFrameStart::Serialize (Buffer::Iterator start) const
+{
+  Buffer::Iterator i = start;
+  NS_ASSERT(m_subtype < 3);
+  m_protocol.Serialize (i);
+  i.Next (m_protocol.GetSerializedSize ());
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    i.WriteHtolsbU16(m_capability);
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CONFIRM) == m_subtype)
+    i.WriteHtolsbU16 (m_aid);
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    i = m_rates.Serialize (i);
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CONFIRM) != m_subtype)
+  {
+    m_meshId.Serialize (i);
+    i.Next(m_meshId.GetSerializedSize ());
+  }
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CLOSE) != m_subtype)
+  {
+    m_config.Serialize (i);
+    i.Next(m_config.GetSerializedSize ());
+  }
+  else
+    i.WriteHtolsbU16(m_reasonCode);
+}
+uint32_t
+PeerLinkFrameStart::Deserialize (Buffer::Iterator start)
+{
+  Buffer::Iterator i = start;
+  NS_ASSERT(m_subtype < 3);
+  m_protocol.Deserialize (i);
+  i.Next (m_protocol.GetSerializedSize ());
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    m_capability = i.ReadLsbtohU16();
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CONFIRM) == m_subtype)
+    m_aid = i.ReadLsbtohU16 ();
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    i = m_rates.Deserialize (i);
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CONFIRM) != m_subtype)
+  {
+    m_meshId.Deserialize (i);
+    i.Next(m_meshId.GetSerializedSize ());
+  }
+  if ((uint8_t)(WifiMeshActionHeader::PEER_LINK_CLOSE) != m_subtype)
+  {
+    m_config.Deserialize (i);
+    i.Next (m_config.GetSerializedSize ());
+  }
+  else
+    m_reasonCode = i.ReadLsbtohU16();
+  return i.GetDistanceFrom (start);
+}
+bool operator== (const PeerLinkFrameStart & a, const PeerLinkFrameStart & b)
+{
+  return (
+      (a.m_subtype == b.m_subtype) &&
+      (a.m_capability == b.m_capability) &&
+      (a.m_aid == b.m_aid) &&
+      (a.m_meshId.IsEqual(b.m_meshId)) &&
+      (a.m_config == b.m_config) &&
+      (a.m_reasonCode == b.m_reasonCode)
+      );
+}
+#ifdef RUN_SELF_TESTS
+/// Built-in self test for PeerLinkFrameStart
+struct PeerLinkFrameStartBist : public Test 
+{
+  PeerLinkFrameStartBist () : Test ("Mesh/802.11s/IE/PeerLinkFrameStart") {}
+  virtual bool RunTests(); 
+};
+/// Test instance
+static PeerLinkFrameStartBist g_PeerLinkFrameStartBist;
+
+bool PeerLinkFrameStartBist::RunTests ()
+{
+  bool result (true);
+  {
+    PeerLinkFrameStart a;
+    PeerLinkFrameStart::PlinkFrameStartFields fields;
+    fields.subtype = (uint8_t)(WifiMeshActionHeader::PEER_LINK_OPEN);
+    fields.capability = 0;
+    fields.aid = 101;
+    fields.reasonCode = 12;
+    fields.meshId = IeMeshId("qwertyuiop", 10);
+    a.SetPlinkFrameStart(fields);
+    Ptr<Packet> packet = Create<Packet> ();
+    packet->AddHeader (a);
+    PeerLinkFrameStart b;
+    b.SetPlinkFrameSubtype((uint8_t)(WifiMeshActionHeader::PEER_LINK_OPEN));
+    packet->RemoveHeader (b);
+    NS_TEST_ASSERT_EQUAL (a, b);
+  }
+  {
+    PeerLinkFrameStart a;
+    PeerLinkFrameStart::PlinkFrameStartFields fields;
+    fields.subtype = (uint8_t)(WifiMeshActionHeader::PEER_LINK_CONFIRM);
+    fields.capability = 0;
+    fields.aid = 1234;
+    fields.reasonCode = 12;
+    fields.meshId = IeMeshId("qwerty", 6);
+    a.SetPlinkFrameStart(fields);
+    Ptr<Packet> packet = Create<Packet> ();
+    packet->AddHeader (a);
+    PeerLinkFrameStart b;
+    b.SetPlinkFrameSubtype((uint8_t)(WifiMeshActionHeader::PEER_LINK_CONFIRM));
+    packet->RemoveHeader (b);
+    NS_TEST_ASSERT_EQUAL (a, b);
+  }
+  {
+    PeerLinkFrameStart a;
+    PeerLinkFrameStart::PlinkFrameStartFields fields;
+    fields.subtype = (uint8_t)(WifiMeshActionHeader::PEER_LINK_CLOSE);
+    fields.capability = 0;
+    fields.aid = 10;
+    fields.meshId = IeMeshId("qqq", 3);
+    fields.reasonCode = 12;
+    a.SetPlinkFrameStart(fields);
+    Ptr<Packet> packet = Create<Packet> ();
+    packet->AddHeader (a);
+    PeerLinkFrameStart b;
+    b.SetPlinkFrameSubtype((uint8_t)(WifiMeshActionHeader::PEER_LINK_CLOSE));
+    packet->RemoveHeader (b);
+    NS_TEST_ASSERT_EQUAL (a, b);
+  }
+  return result;  
+}
+#endif
+} // namespace dot11s
+} //namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/peer-link-frame.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,91 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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
+ * 
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ */
+
+#ifndef PEER_LINK_FRAME_START_H
+#define PEER_LINK_FRAME_START_H
+#include "ns3/header.h"
+#include "ns3/supported-rates.h"
+#include "dot11s-mac-header.h"
+#include "ie-dot11s-configuration.h"
+#include "ie-dot11s-peering-protocol.h"
+#include "ie-dot11s-id.h"
+namespace ns3 {
+class MeshWifiInterfaceMac;
+namespace dot11s {
+/**
+ * \ingroup dot11s
+ * 
+ * \brief 802.11s Peer link management frame:
+ * \details included the following (see chapters 7.4.12.1-7.4.12.3 of
+ * 802.11s):
+ * - Subtype field
+ * - Association ID field
+ * - Supported rates
+ * - Mesh ID of mesh
+ */
+class PeerLinkFrameStart : public Header
+{
+public:
+  PeerLinkFrameStart ();
+  ///\brief fields:
+  struct PlinkFrameStartFields
+  {
+    uint8_t subtype;
+    IePeeringProtocol protocol; //Peering protocol version - in all subtypes - 3 octets
+    uint16_t capability;        //open and confirm
+    uint16_t aid;               //confirm only
+    SupportedRates rates;       //open and confirm
+    IeMeshId meshId;            //open and close
+    IeConfiguration config;     //open and confirm
+    uint16_t reasonCode;        //close only
+  };
+  ///\attention: must be set before deserialize, before only multihop
+  //action header knows about subtype
+  void SetPlinkFrameSubtype(uint8_t subtype);
+  void SetPlinkFrameStart(PlinkFrameStartFields);
+  PlinkFrameStartFields GetFields ();
+  /** \name Inherited from header:
+   * \{
+   */
+  static  TypeId   GetTypeId ();
+  virtual TypeId   GetInstanceTypeId () const;
+  virtual void     Print (std::ostream &os) const;
+  virtual uint32_t GetSerializedSize () const;
+  virtual void     Serialize (Buffer::Iterator start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator start);
+  /**
+   * \}
+   */
+private:
+  uint8_t m_subtype;
+  IePeeringProtocol m_protocol;
+  uint16_t m_capability;
+  uint16_t m_aid;
+  SupportedRates m_rates;
+  IeMeshId m_meshId;
+  IeConfiguration m_config;
+  uint16_t m_reasonCode;
+
+  friend bool operator== (const PeerLinkFrameStart & a, const PeerLinkFrameStart & b);
+};
+bool operator== (const PeerLinkFrameStart & a, const PeerLinkFrameStart & b);
+} //namespace dot11s
+} //namespace ns3
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/peer-link.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,595 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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
+ * 
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ *          Aleksey Kovalenko <kovalenko@iitp.ru>
+ *          Pavel Boyko <boyko@iitp.ru>
+ */
+
+#include "peer-link.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/traced-value.h"
+
+NS_LOG_COMPONENT_DEFINE ("Dot11sPeerManagementProtocol");
+
+namespace ns3 {
+namespace dot11s {
+
+NS_OBJECT_ENSURE_REGISTERED(PeerLink);
+
+TypeId 
+PeerLink::GetTypeId()
+{
+  static TypeId tid = TypeId ("ns3::dot11s::PeerLink")
+    .SetParent<Object> ()
+    .AddConstructor<PeerLink> ()
+    .AddAttribute ("RetryTimeout", "Retry timeout",
+        TimeValue (TimeValue (MicroSeconds (40 * 1024))),
+        MakeTimeAccessor (&PeerLink::m_dot11MeshRetryTimeout),
+        MakeTimeChecker ()
+        )
+    .AddAttribute ("HoldingTimeout", "Holding timeout",
+        TimeValue (TimeValue (MicroSeconds (40 * 1024))),
+        MakeTimeAccessor (&PeerLink::m_dot11MeshHoldingTimeout),
+        MakeTimeChecker ()
+        )
+    .AddAttribute ("ConfirmTimeout", "Confirm timeout",
+        TimeValue (TimeValue (MicroSeconds (40 * 1024))),
+        MakeTimeAccessor (&PeerLink::m_dot11MeshConfirmTimeout),
+        MakeTimeChecker ()
+        )
+    .AddAttribute ("MaxRetries", "Maximum number of retries",
+        UintegerValue (4),
+        MakeUintegerAccessor (&PeerLink::m_dot11MeshMaxRetries),
+        MakeUintegerChecker<uint16_t> ()
+        )
+    .AddAttribute ("MaxBeaconLoss", "Maximum number of lost beacons before link will be closed",
+        UintegerValue (2),
+        MakeUintegerAccessor (&PeerLink::m_maxBeaconLoss),
+        MakeUintegerChecker<uint16_t> (1)
+        );
+  return tid;
+}
+  
+//-----------------------------------------------------------------------------
+// PeerLink public interface
+//-----------------------------------------------------------------------------
+PeerLink::PeerLink ():
+  m_peerAddress (Mac48Address::GetBroadcast ()),
+  m_peerMeshPointAddress (Mac48Address::GetBroadcast ()),
+  m_localLinkId (0),
+  m_peerLinkId (0),
+  m_state (IDLE),
+  m_retryCounter (0)
+{
+}
+PeerLink::~PeerLink ()
+{
+}
+void
+PeerLink::DoDispose ()
+{
+  m_retryTimer.Cancel ();
+  m_holdingTimer.Cancel ();
+  m_confirmTimer.Cancel ();
+  m_beaconLossTimer.Cancel ();
+  m_beaconTiming.ClearTimingElement ();
+}
+void
+PeerLink::SetPeerAddress (Mac48Address macaddr)
+{
+  m_peerAddress = macaddr;
+}
+void
+PeerLink::SetPeerMeshPointAddress(Mac48Address macaddr)
+{
+  m_peerMeshPointAddress = macaddr;
+}
+void
+PeerLink::SetInterface (uint32_t interface)
+{
+  m_interface = interface;
+}
+void
+PeerLink::SetLocalLinkId (uint16_t id)
+{
+  m_localLinkId = id;
+}
+void
+PeerLink::SetLocalAid (uint16_t aid)
+{
+  m_assocId = aid;
+}
+void
+PeerLink::SetBeaconInformation (Time lastBeacon, Time beaconInterval)
+{
+  m_lastBeacon = lastBeacon;
+  m_beaconInterval = beaconInterval;
+  m_beaconLossTimer.Cancel ();
+  Time delay = Seconds(beaconInterval.GetSeconds() * m_maxBeaconLoss);
+  NS_ASSERT (delay.GetMicroSeconds() != 0);
+  m_beaconLossTimer = Simulator::Schedule (delay, &PeerLink::BeaconLoss, this);
+}
+void
+PeerLink::MLMESetSignalStatusCallback (PeerLink::SignalStatusCallback cb)
+{
+  m_linkStatusCallback = cb;
+}
+void
+PeerLink::BeaconLoss ()
+{
+  StateMachine (CNCL);
+}
+void
+PeerLink::SetBeaconTimingElement (IeBeaconTiming beaconTiming)
+{
+  m_beaconTiming = beaconTiming;
+}
+Mac48Address
+PeerLink::GetPeerAddress () const
+{
+  return m_peerAddress;
+}
+uint16_t
+PeerLink::GetLocalAid () const
+{
+  return m_assocId;
+}
+Time
+PeerLink::GetLastBeacon () const
+{
+  return m_lastBeacon;
+}
+Time
+PeerLink::GetBeaconInterval () const
+{
+  return m_beaconInterval;
+}
+IeBeaconTiming
+PeerLink::GetBeaconTimingElement () const
+{
+  return m_beaconTiming;
+}
+void
+PeerLink::MLMECancelPeerLink (PmpReasonCode reason)
+{
+  StateMachine (CNCL,reason);
+}
+void
+PeerLink::MLMEPassivePeerLinkOpen ()
+{
+  StateMachine (PASOPN);
+}
+void
+PeerLink::MLMEActivePeerLinkOpen ()
+{
+  StateMachine (ACTOPN);
+}
+void
+PeerLink::MLMEPeeringRequestReject ()
+{
+  StateMachine (REQ_RJCT, REASON11S_PEERING_CANCELLED);
+}
+void
+PeerLink::Close (uint16_t localLinkId, uint16_t peerLinkId, PmpReasonCode reason)
+{
+  if (peerLinkId != 0 && m_localLinkId != peerLinkId)
+    return;
+  if (m_peerLinkId == 0)
+    m_peerLinkId = localLinkId;
+  else if (m_peerLinkId != localLinkId)
+    return;
+  StateMachine (CLS_ACPT, reason);
+}
+void
+PeerLink::OpenAccept (uint16_t localLinkId, IeConfiguration  conf, Mac48Address peerMp)
+{
+  if (m_peerLinkId == 0)
+    m_peerLinkId = localLinkId;
+  m_configuration = conf;
+  if(m_peerMeshPointAddress != Mac48Address::GetBroadcast ())
+  {
+    NS_ASSERT(m_peerMeshPointAddress == peerMp);
+  }
+  else
+    m_peerMeshPointAddress = peerMp;
+  StateMachine (OPN_ACPT);
+}
+void
+PeerLink::OpenReject (uint16_t localLinkId, IeConfiguration  conf, Mac48Address peerMp, PmpReasonCode reason)
+{
+  if ( m_peerLinkId == 0)
+    m_peerLinkId = localLinkId;
+  m_configuration = conf;
+  if(m_peerMeshPointAddress != Mac48Address::GetBroadcast ())
+  {
+    NS_ASSERT(m_peerMeshPointAddress == peerMp);
+  }
+  else
+    m_peerMeshPointAddress = peerMp;
+  StateMachine (OPN_RJCT, reason);
+}
+void
+PeerLink::ConfirmAccept (uint16_t localLinkId, uint16_t peerLinkId, uint16_t peerAid, IeConfiguration conf, Mac48Address peerMp)
+{
+  if ( m_localLinkId != peerLinkId)
+    return;
+  if ( m_peerLinkId == 0)
+    m_peerLinkId = localLinkId;
+  else if ( m_peerLinkId != localLinkId )
+    return;
+  m_configuration = conf;
+  m_peerAssocId = peerAid;
+  if(m_peerMeshPointAddress != Mac48Address::GetBroadcast ())
+  {
+    NS_ASSERT(m_peerMeshPointAddress == peerMp);
+  }
+  else
+    m_peerMeshPointAddress = peerMp;
+  StateMachine (CNF_ACPT);
+}
+void
+PeerLink::ConfirmReject (uint16_t localLinkId, uint16_t peerLinkId,
+    IeConfiguration  conf, Mac48Address peerMp, PmpReasonCode reason)
+{
+  if (m_localLinkId != peerLinkId)
+    return;
+  if (m_peerLinkId == 0)
+    m_peerLinkId = localLinkId;
+  else if (m_peerLinkId != localLinkId)
+    return;
+  m_configuration = conf;
+  if(m_peerMeshPointAddress != Mac48Address::GetBroadcast ())
+  {
+    NS_ASSERT(m_peerMeshPointAddress == peerMp);
+  }
+  m_peerMeshPointAddress = peerMp;
+  StateMachine (CNF_RJCT, reason);
+}
+bool
+PeerLink::LinkIsEstab () const
+{
+  return (m_state == ESTAB);
+}
+bool
+PeerLink::LinkIsIdle () const
+{
+  return (m_state == IDLE);
+}
+void
+PeerLink::SetMacPlugin(Ptr<PeerManagerMacPlugin> plugin)
+{
+  m_macPlugin = plugin;
+}
+//-----------------------------------------------------------------------------
+// Private
+//-----------------------------------------------------------------------------
+void
+PeerLink::StateMachine (PeerEvent event,PmpReasonCode reasoncode)
+{
+  switch (m_state)
+    {
+    case IDLE:
+      switch (event)
+        {
+        case CNCL:
+        case CLS_ACPT:
+          m_state = IDLE;
+          // TODO Callback MLME-SignalPeerLinkStatus
+          break;
+        case REQ_RJCT:
+          SendPeerLinkClose (reasoncode);
+          break;
+        case ACTOPN:
+          m_state = OPN_SNT;
+          SendPeerLinkOpen ();
+          SetRetryTimer ();
+          break;
+        case OPN_ACPT:
+          m_state = OPN_RCVD;
+          SendPeerLinkConfirm ();
+          SendPeerLinkOpen ();
+          SetRetryTimer ();
+          break;
+        default:
+        {}
+        }
+      break;
+    case OPN_SNT:
+      switch (event)
+        {
+        case TOR1:
+          SendPeerLinkOpen ();
+          m_retryCounter++;
+          SetRetryTimer ();
+          break;
+        case CNF_ACPT:
+          m_state = CNF_RCVD;
+          ClearRetryTimer ();
+          SetConfirmTimer ();
+          break;
+        case OPN_ACPT:
+          m_state = OPN_RCVD;
+          SendPeerLinkConfirm ();
+          break;
+        case CLS_ACPT:
+          m_state = HOLDING;
+          ClearRetryTimer ();
+          SendPeerLinkClose (REASON11S_MESH_CLOSE_RCVD);
+          SetHoldingTimer ();
+          break;
+        case OPN_RJCT:
+        case CNF_RJCT:
+          m_state = HOLDING;
+          ClearRetryTimer ();
+          SendPeerLinkClose (reasoncode);
+          SetHoldingTimer ();
+          break;
+        case TOR2:
+          m_state = HOLDING;
+          ClearRetryTimer ();
+          SendPeerLinkClose (REASON11S_MESH_MAX_RETRIES);
+          SetHoldingTimer ();
+          break;
+        case CNCL:
+          m_state = HOLDING;
+          ClearRetryTimer ();
+          SendPeerLinkClose (REASON11S_PEERING_CANCELLED);
+          SetHoldingTimer ();
+          break;
+        default:
+        {}
+        }
+      break;
+    case CNF_RCVD:
+      switch (event)
+        {
+        case CNF_ACPT:
+          break;
+        case OPN_ACPT:
+          m_state = ESTAB;
+          ClearConfirmTimer ();
+          SendPeerLinkConfirm ();
+          NS_ASSERT(m_peerMeshPointAddress != Mac48Address::GetBroadcast ());
+          m_linkStatusCallback (m_interface, m_peerAddress, m_peerMeshPointAddress, true);
+          // TODO Callback MLME-SignalPeerLinkStatus
+          break;
+        case CLS_ACPT:
+          m_state = HOLDING;
+          ClearConfirmTimer ();
+          SendPeerLinkClose (REASON11S_MESH_CLOSE_RCVD);
+          SetHoldingTimer ();
+          break;
+        case CNF_RJCT:
+        case OPN_RJCT:
+          m_state = HOLDING;
+          ClearConfirmTimer ();
+          SendPeerLinkClose (reasoncode);
+          SetHoldingTimer ();
+          break;
+        case CNCL:
+          m_state = HOLDING;
+          ClearConfirmTimer ();
+          SendPeerLinkClose (REASON11S_PEERING_CANCELLED);
+          SetHoldingTimer ();
+          break;
+        case TOC:
+          m_state = HOLDING;
+          SendPeerLinkClose (REASON11S_MESH_CONFIRM_TIMEOUT);
+          SetHoldingTimer ();
+          break;
+        default:
+        {}
+        }
+      break;
+    case OPN_RCVD:
+      switch (event)
+        {
+        case TOR1:
+          SendPeerLinkOpen ();
+          m_retryCounter++;
+          SetRetryTimer ();
+          break;
+        case CNF_ACPT:
+          m_state = ESTAB;
+          ClearRetryTimer ();
+          NS_ASSERT(m_peerMeshPointAddress != Mac48Address::GetBroadcast ());
+          m_linkStatusCallback (m_interface, m_peerAddress, m_peerMeshPointAddress, true);
+          // TODO Callback MLME-SignalPeerLinkStatus
+          break;
+        case CLS_ACPT:
+          m_state = HOLDING;
+          ClearRetryTimer ();
+          SendPeerLinkClose (REASON11S_MESH_CLOSE_RCVD);
+          SetHoldingTimer ();
+          break;
+        case OPN_RJCT:
+        case CNF_RJCT:
+          m_state = HOLDING;
+          ClearRetryTimer ();
+          SendPeerLinkClose (reasoncode);
+          SetHoldingTimer ();
+          break;
+        case TOR2:
+          m_state = HOLDING;
+          ClearRetryTimer ();
+          SendPeerLinkClose (REASON11S_MESH_MAX_RETRIES);
+          SetHoldingTimer ();
+          break;
+        case CNCL:
+          m_state = HOLDING;
+          ClearRetryTimer ();
+          SendPeerLinkClose (REASON11S_PEERING_CANCELLED);
+          SetHoldingTimer ();
+          break;
+        default:
+        {}
+        }
+      break;
+    case ESTAB:
+      switch (event)
+        {
+        case OPN_ACPT:
+          SendPeerLinkConfirm ();
+          break;
+        case CLS_ACPT:
+          m_state = HOLDING;
+          SendPeerLinkClose (REASON11S_MESH_CLOSE_RCVD);
+          SetHoldingTimer ();
+          m_linkStatusCallback (m_interface, m_peerAddress, m_peerMeshPointAddress, false);
+          break;
+        case OPN_RJCT:
+        case CNF_RJCT:
+          m_state = HOLDING;
+          ClearRetryTimer ();
+          SendPeerLinkClose (reasoncode);
+          SetHoldingTimer ();
+          m_linkStatusCallback (m_interface, m_peerAddress, m_peerMeshPointAddress, false);
+          break;
+        case CNCL:
+          m_state = HOLDING;
+          SendPeerLinkClose (REASON11S_PEERING_CANCELLED);
+          SetHoldingTimer ();
+          m_linkStatusCallback (m_interface, m_peerAddress, m_peerMeshPointAddress, false);
+          break;
+        default:
+        {}
+        }
+      break;
+    case HOLDING:
+      switch (event)
+        {
+        case CLS_ACPT:
+          ClearHoldingTimer ();
+        case TOH:
+          m_state = IDLE;
+          // TODO Callback MLME-SignalPeerLinkStatus
+          break;
+        case OPN_ACPT:
+        case CNF_ACPT:
+          m_state = HOLDING;
+          // reason not spec in D2.0
+          SendPeerLinkClose (REASON11S_PEERING_CANCELLED);
+          break;
+        case OPN_RJCT:
+        case CNF_RJCT:
+          m_state = HOLDING;
+          SendPeerLinkClose (reasoncode);
+          break;
+        default:
+        {}
+        }
+      break;
+    }
+}
+void
+PeerLink::ClearRetryTimer ()
+{
+  m_retryTimer.Cancel ();
+}
+void
+PeerLink::ClearConfirmTimer ()
+{
+  m_confirmTimer.Cancel ();
+}
+void
+PeerLink::ClearHoldingTimer ()
+{
+  m_holdingTimer.Cancel ();
+}
+void
+PeerLink::SendPeerLinkClose (PmpReasonCode reasoncode)
+{
+  IePeerManagement peerElement;
+  peerElement.SetPeerClose (m_localLinkId, m_peerLinkId, reasoncode);
+  m_macPlugin->SendPeerLinkManagementFrame (m_peerAddress, m_peerMeshPointAddress, m_assocId, peerElement, m_configuration);
+}
+void
+PeerLink::SendPeerLinkOpen ()
+{
+  IePeerManagement peerElement;
+  peerElement.SetPeerOpen (m_localLinkId);
+  NS_ASSERT (m_macPlugin != NULL);
+  m_macPlugin->SendPeerLinkManagementFrame (m_peerAddress, m_peerMeshPointAddress, m_assocId, peerElement, m_configuration);
+}
+void
+PeerLink::SendPeerLinkConfirm ()
+{
+  IePeerManagement peerElement;
+  peerElement.SetPeerConfirm (m_localLinkId, m_peerLinkId);
+  m_macPlugin->SendPeerLinkManagementFrame (m_peerAddress, m_peerMeshPointAddress, m_assocId, peerElement, m_configuration);
+}
+void
+PeerLink::SetHoldingTimer ()
+{
+  NS_ASSERT(m_dot11MeshHoldingTimeout.GetMicroSeconds() !=0);
+  m_holdingTimer = Simulator::Schedule (m_dot11MeshHoldingTimeout, &PeerLink::HoldingTimeout, this);
+}
+void
+PeerLink::HoldingTimeout ()
+{
+  StateMachine (TOH);
+}
+void
+PeerLink::SetRetryTimer ()
+{
+  NS_ASSERT(m_dot11MeshRetryTimeout.GetMicroSeconds() !=0);
+  m_retryTimer = Simulator::Schedule (m_dot11MeshRetryTimeout, &PeerLink::RetryTimeout, this);
+}
+void
+PeerLink::RetryTimeout ()
+{
+  if ( m_retryCounter < m_dot11MeshMaxRetries)
+    StateMachine (TOR1);
+  else
+    StateMachine (TOR2);
+}
+void
+PeerLink::SetConfirmTimer ()
+{
+  NS_ASSERT(m_dot11MeshConfirmTimeout.GetMicroSeconds() !=0);
+  m_confirmTimer = Simulator::Schedule (m_dot11MeshConfirmTimeout, &PeerLink::ConfirmTimeout, this);
+}
+void
+PeerLink::ConfirmTimeout ()
+{
+  StateMachine (TOC);
+}
+void
+PeerLink::Report (std::ostream & os) const
+{
+  if(m_state != ESTAB)
+    return;
+  os << "<PeerLink\n"
+    "localAddress=\"" << m_macPlugin->GetAddress () << "\"\n"
+    "peerInterfaceAddress=\"" << m_peerAddress << "\"\n"
+    "peerMeshPointAddress=\"" << m_peerMeshPointAddress << "\"\n"
+    "metricOfTheLink=\"" << m_macPlugin->GetLinkMetric(m_peerAddress) << "\"\n"
+    "m_lastBeacon=\"" << m_lastBeacon.GetMilliSeconds () << "ms\"\n"
+    "m_localLinkId=\"" << m_localLinkId << "\"\n"
+    "m_peerLinkId=\"" << m_peerLinkId << "\"\n"
+    "m_assocId=\"" << m_assocId << "\"\n"
+    "dot11MeshMaxRetries=\"" << m_dot11MeshMaxRetries << "\"\n"
+    "dot11MeshRetryTimeout=\"" << m_dot11MeshRetryTimeout.GetMilliSeconds () << "ms\"\n"
+    "dot11MeshHoldingTimeout=\"" << m_dot11MeshHoldingTimeout.GetMilliSeconds () << "ms\"\n"
+    "dot11MeshConfirmTimeout=\"" << m_dot11MeshConfirmTimeout.GetMilliSeconds () << "ms\"\n"
+    "/>\n";
+}
+} // namespace dot11s
+} //namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/peer-link.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,264 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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
+ * 
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ *          Aleksey Kovalenko <kovalenko@iitp.ru>
+ */
+
+#ifndef PEERLLINK_H_
+#define PEERLLINK_H_
+
+#include "ns3/nstime.h"
+#include "ns3/callback.h"
+#include "ns3/mac48-address.h"
+#include "ns3/event-id.h"
+#include "ie-dot11s-beacon-timing.h"
+#include "ie-dot11s-peer-management.h"
+#include "ie-dot11s-configuration.h"
+#include "peer-management-plugin.h"
+namespace ns3 {
+namespace dot11s {
+/**
+ * \ingroup dot11s
+ * 
+ * \brief Peer link model for 802.11s Peer Management protocol 
+ */
+class PeerLink : public Object
+{
+public:
+  friend class PeerManagementProtocol;
+  /// Support object system
+  static TypeId GetTypeId();
+  /// C-tor create empty link
+  PeerLink ();
+  ~PeerLink ();
+  void DoDispose ();
+  
+  /// Process beacon received from peer
+  void SetBeaconInformation (Time lastBeacon, Time BeaconInterval);
+  /**
+   * \brief Method used to detecet peer link changes
+   * 
+   * \param bool if true - opened new link, if false - link closed
+   */
+  void  SetLinkStatusCallback (Callback<void, uint32_t, Mac48Address, bool> cb);
+  /**
+   * \name Peer link geeters/setters
+   * \{
+   */
+  void SetPeerAddress (Mac48Address macaddr);
+  void SetPeerMeshPointAddress (Mac48Address macaddr);
+  void SetInterface (uint32_t interface);
+  void SetLocalLinkId (uint16_t id);
+  void SetPeerLinkId (uint16_t id);
+  void SetLocalAid (uint16_t aid);
+  void SetPeerAid (uint16_t aid);
+  void SetBeaconTimingElement (IeBeaconTiming beaconTiming);
+  void SetPeerLinkDescriptorElement (IePeerManagement peerLinkElement);
+  Mac48Address GetPeerAddress () const;
+  uint16_t GetLocalAid () const;
+  Time GetLastBeacon () const;
+  Time GetBeaconInterval () const;
+  IeBeaconTiming GetBeaconTimingElement ()const;
+  IePeerManagement GetPeerLinkDescriptorElement ()const;
+  //\}
+  
+  /**
+   * \name MLME
+   * \{
+   */
+  /// MLME-CancelPeerLink.request
+  void MLMECancelPeerLink (PmpReasonCode reason);
+  /// MLME-PassivePeerLinkOpen.request
+  void MLMEPassivePeerLinkOpen ();
+  /// MLME-ActivePeerLinkOpen.request
+  void MLMEActivePeerLinkOpen ();
+  /// MLME-PeeringRequestReject
+  void MLMEPeeringRequestReject ();
+  /// Callback type for MLME-SignalPeerLinkStatus event
+  typedef Callback<void, uint32_t, Mac48Address, Mac48Address, bool> SignalStatusCallback; 
+  /// Set callback
+  void MLMESetSignalStatusCallback (SignalStatusCallback);
+  //\}
+  ///\brief Statistics
+  void Report (std::ostream & os) const;
+private:
+  /**
+   * \name Link response to received management frames
+   * 
+   * \attention In all this methods {local/peer}LinkID correspond to _peer_ station, as written in
+   * received frame, e.g. I am peerLinkID and peer link is localLinkID .
+   * 
+   * TODO is that clear?
+   * 
+   * \{
+   */
+  /// Close link
+  void Close (uint16_t localLinkID, uint16_t peerLinkID, PmpReasonCode reason);
+  /// Accept open link
+  void OpenAccept (uint16_t localLinkId, IeConfiguration conf, Mac48Address peerMp);
+  /// Reject open link 
+  void OpenReject (uint16_t localLinkId, IeConfiguration conf, Mac48Address peerMp, PmpReasonCode reason);
+  /// Confirm accept
+  void ConfirmAccept (
+    uint16_t localLinkId,
+    uint16_t peerLinkId,
+    uint16_t peerAid,
+    IeConfiguration conf,
+    Mac48Address peerMp
+  );
+  /// Confirm reject
+  void  ConfirmReject (
+    uint16_t localLinkId,
+    uint16_t peerLinkId,
+    IeConfiguration  conf,
+    Mac48Address peerMp,
+    PmpReasonCode reason
+  );
+  //\}
+  
+  /// True if link is established
+  bool  LinkIsEstab () const;
+  /// True if link is idle. Link can be deleted in this state 
+  bool  LinkIsIdle () const;
+  /**
+   * Set pointer to MAC-plugin, which is responsible for sending peer
+   * link management frames
+   */
+  void SetMacPlugin(Ptr<PeerManagerMacPlugin> plugin);
+private:
+  /// Peer link states, see 802.11s draft 11B.3.3.1
+  enum  PeerState {
+    IDLE,       
+    OPN_SNT,
+    CNF_RCVD,
+    OPN_RCVD,
+    ESTAB,
+    HOLDING,
+  };
+  /// Peer link events, see 802.11s draft 11B.3.3.2
+  enum  PeerEvent
+  {
+    CNCL,       ///< MLME-CancelPeerLink
+    PASOPN,     ///< MLME-PassivePeerLinkOpen
+    ACTOPN,     ///< MLME-ActivePeerLinkOpen
+    CLS_ACPT,   ///< PeerLinkClose_Accept
+    OPN_ACPT,   ///< PeerLinkOpen_Accept
+    OPN_RJCT,   ///< PeerLinkOpen_Reject
+    REQ_RJCT,   ///< PeerLinkOpenReject by internal reason
+    CNF_ACPT,   ///< PeerLinkConfirm_Accept
+    CNF_RJCT,   ///< PeerLinkConfirm_Reject
+    TOR1,       ///< Timeout of retry timer
+    TOR2,       ///< also timeout of retry timer
+    TOC,        ///< Timeout of confirm timer
+    TOH,        ///< Timeout of holding (gracefull closing) timer
+  };
+  
+private:
+  /// State transition
+  void StateMachine (PeerEvent event, PmpReasonCode = REASON11S_RESERVED);
+  
+  /** 
+   * \name Event handlers
+   * \{ 
+   */
+  void ClearRetryTimer ();
+  void ClearConfirmTimer ();
+  void ClearHoldingTimer ();
+  void SetHoldingTimer ();
+  void SetRetryTimer ();
+  void SetConfirmTimer ();
+  //\}
+
+  /** 
+   * \name Work with management frames
+   * \{
+   */
+  void SendPeerLinkClose (PmpReasonCode reasoncode);
+  void SendPeerLinkOpen ();
+  void SendPeerLinkConfirm ();
+  //\}
+  
+  /** 
+   * \name Timeout handlers 
+   * \{
+   */
+  void HoldingTimeout ();
+  void RetryTimeout ();
+  void ConfirmTimeout ();
+  //\}
+  
+private:
+  ///The number of interface I am associated with
+  uint32_t m_interface;
+  /// pointer to mac plugin, which is responsible for peer management
+  Ptr<PeerManagerMacPlugin> m_macPlugin;
+  /// Peer address
+  Mac48Address m_peerAddress;
+  /// Mesh point address, equal to peer address in case of single
+  //interface mesh point
+  Mac48Address m_peerMeshPointAddress;
+  /// My ID of this link
+  uint16_t m_localLinkId;
+  /// Peer ID of this link
+  uint16_t m_peerLinkId;
+  /// My association ID
+  uint16_t m_assocId;
+  /// Assoc Id assigned to me by peer
+  uint16_t m_peerAssocId;
+    
+  /// When last beacon was sent (TODO or received?)
+  Time  m_lastBeacon;
+  /// Current beacon interval on corresponding interface
+  Time  m_beaconInterval;
+  
+  /// Current state
+  PeerState m_state;
+  /// Mesh interface configuration
+  IeConfiguration m_configuration;
+  
+  // State is a bitfield as defined as follows:
+  // This are states for a given
+  IeBeaconTiming m_beaconTiming;
+
+  /**
+   * \name Timers & counters used for internal state transitions
+   * \{
+   */
+  uint16_t m_dot11MeshMaxRetries;
+  Time     m_dot11MeshRetryTimeout;
+  Time     m_dot11MeshHoldingTimeout;
+  Time     m_dot11MeshConfirmTimeout;
+
+  EventId  m_retryTimer;
+  EventId  m_holdingTimer;
+  EventId  m_confirmTimer;
+  uint16_t m_retryCounter;
+  EventId  m_beaconLossTimer;
+  uint16_t  m_maxBeaconLoss;
+  //\}
+  
+  /// ?
+  void BeaconLoss ();
+   
+  /// How to report my status change
+  SignalStatusCallback m_linkStatusCallback;
+};
+  
+} // namespace dot11s
+} //namespace ns3
+#endif /* PEERLLINK_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/peer-management-plugin.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,317 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+#include "ie-dot11s-configuration.h"
+#include "ie-dot11s-peer-management.h"
+#include "dot11s-mac-header.h"
+#include "peer-management-plugin.h"
+#include "peer-management-protocol.h"
+#include "peer-link-frame.h"
+#include "ns3/mesh-wifi-interface-mac.h"
+#include "ns3/simulator.h"
+#include "ns3/wifi-mac-header.h"
+namespace ns3 {
+namespace dot11s {
+PeerManagerMacPlugin::PeerManagerMacPlugin (uint32_t interface, Ptr<PeerManagementProtocol> protocol)
+{
+  m_ifIndex = interface;
+  m_protocol = protocol;
+}
+
+PeerManagerMacPlugin::~PeerManagerMacPlugin ()
+{
+}
+
+void
+PeerManagerMacPlugin::SetParent (Ptr<MeshWifiInterfaceMac> parent)
+{
+  m_parent = parent;
+}
+
+bool
+PeerManagerMacPlugin::Receive (Ptr<Packet> const_packet, const WifiMacHeader & header)
+{
+  // First of all we copy a packet, because we need to remove some
+  //headers
+  Ptr<Packet> packet = const_packet->Copy();
+  if(header.IsBeacon())
+  {
+    IeBeaconTiming beaconTiming;
+    IeMeshId meshId;
+    Ptr<Packet> myBeacon = packet->Copy();
+    MgtBeaconHeader beacon_hdr;
+    myBeacon->RemoveHeader(beacon_hdr);
+    meshId.FindFirst(myBeacon);
+    bool meshBeacon = false;
+    if (
+        (beaconTiming.FindFirst(myBeacon)) &&
+        (m_protocol->GetMeshId ()->IsEqual(meshId))
+        )
+      meshBeacon = true;
+    m_protocol->UpdatePeerBeaconTiming(
+        m_ifIndex,
+        meshBeacon,
+        beaconTiming,
+        header.GetAddr2(),
+        Simulator::Now(),
+        MicroSeconds(beacon_hdr.GetBeaconIntervalUs())
+        );
+    // Beacon shall not be dropeed. May be needed to another plugins
+    return true;
+  }
+  if(header.IsAction())
+  {
+    WifiMeshActionHeader actionHdr;
+    packet->RemoveHeader (actionHdr);
+    WifiMeshActionHeader::ActionValue actionValue = actionHdr.GetAction ();
+    // If can not handle - just return;
+    if(actionHdr.GetCategory () != WifiMeshActionHeader::MESH_PEER_LINK_MGT)
+      return m_protocol->IsActiveLink(m_ifIndex,header.GetAddr2());
+    m_stats.recvMgt ++;
+    m_stats.recvMgtBytes += packet->GetSize ();
+    Mac48Address peerAddress = header.GetAddr2 ();
+    Mac48Address peerMpAddress = header.GetAddr3 ();
+    PeerLinkFrameStart::PlinkFrameStartFields fields;
+    {
+      PeerLinkFrameStart peerFrame;
+      peerFrame.SetPlinkFrameSubtype((uint8_t)actionValue.peerLink);
+      packet->RemoveHeader (peerFrame);
+      fields = peerFrame.GetFields();
+      NS_ASSERT(fields.subtype == actionValue.peerLink);
+    }
+    if (
+        (actionValue.peerLink != WifiMeshActionHeader::PEER_LINK_CLOSE) &&
+        !(m_parent->CheckSupportedRates(fields.rates))
+        )
+      {
+        m_protocol->ConfigurationMismatch (m_ifIndex, peerAddress);
+        // Broken peer link frame - drop it
+        m_stats.brokenMgt ++;
+        return false;
+      }
+    if (
+        (actionValue.peerLink != WifiMeshActionHeader::PEER_LINK_CONFIRM) &&
+        !fields.meshId.IsEqual(*(m_protocol->GetMeshId()))
+        )
+      {
+        m_protocol->ConfigurationMismatch (m_ifIndex, peerAddress);
+        // Broken peer link frame - drop it
+        m_stats.brokenMgt ++;
+        return false;
+      }
+    IePeerManagement peerElement;
+    packet->RemoveHeader(peerElement);
+    //Check taht frame subtype corresponds peer link subtype
+    if(peerElement.SubtypeIsOpen ())
+    {
+      m_stats.recvOpen ++;
+      NS_ASSERT(actionValue.peerLink == WifiMeshActionHeader::PEER_LINK_OPEN);
+    }
+    if(peerElement.SubtypeIsConfirm ())
+    {
+      m_stats.recvConfirm ++;
+      NS_ASSERT(actionValue.peerLink == WifiMeshActionHeader::PEER_LINK_CONFIRM);
+    }
+    if(peerElement.SubtypeIsClose ())
+    {
+      m_stats.recvClose ++;
+      NS_ASSERT(actionValue.peerLink == WifiMeshActionHeader::PEER_LINK_CLOSE);
+    }
+    //Deliver Peer link management frame to protocol:
+    m_protocol->ReceivePeerLinkFrame(m_ifIndex, peerAddress, peerMpAddress, fields.aid, peerElement, fields.config);
+    // if we can handle a frame - drop it
+    return false;
+  }
+  return m_protocol->IsActiveLink(m_ifIndex,header.GetAddr2());
+}
+bool
+PeerManagerMacPlugin::UpdateOutcomingFrame (Ptr<Packet> packet, WifiMacHeader & header, Mac48Address from, Mac48Address to)
+{
+  if(header.IsAction ())
+  {
+    WifiMeshActionHeader actionHdr;
+    packet->PeekHeader (actionHdr);
+    WifiMeshActionHeader::ActionValue actionValue = actionHdr.GetAction ();
+    if(actionHdr.GetCategory () == WifiMeshActionHeader::MESH_PEER_LINK_MGT)
+      return true;
+  }
+  if(header.GetAddr1 ().IsGroup ())
+    return true;
+  else
+  {
+    if(m_protocol->IsActiveLink(m_ifIndex,header.GetAddr1()))
+      return true;
+    else
+    {
+      m_stats.dropped ++;
+      return false;
+    }
+  }
+}
+void
+PeerManagerMacPlugin::UpdateBeacon (MeshWifiBeacon & beacon) const
+{
+  Ptr<IeBeaconTiming>  beaconTiming = m_protocol->GetBeaconTimingElement(m_ifIndex);
+  beacon.AddInformationElement(beaconTiming);
+  beacon.AddInformationElement(m_protocol->GetMeshId ());
+}
+
+void
+PeerManagerMacPlugin::SendPeerLinkManagementFrame(
+      Mac48Address peerAddress,
+      Mac48Address peerMpAddress,
+      uint16_t aid,
+      IePeerManagement peerElement,
+      IeConfiguration meshConfig
+      )
+{
+  //Create a packet:
+  meshConfig.SetNeighborCount (m_protocol->GetNumberOfLinks ());
+  Ptr<Packet> packet = Create<Packet> ();
+  packet->AddHeader (peerElement);
+  PeerLinkFrameStart::PlinkFrameStartFields fields;
+  fields.rates = m_parent->GetSupportedRates ();
+  fields.capability = 0;
+  fields.meshId = *(m_protocol->GetMeshId ());
+  fields.config = meshConfig;
+  PeerLinkFrameStart plinkFrame;
+  //Create an 802.11 frame header:
+  //Send management frame to MAC:
+  WifiMeshActionHeader actionHdr;
+  if (peerElement.SubtypeIsOpen ())
+    {
+      m_stats.sendOpen ++;
+      WifiMeshActionHeader::ActionValue action;
+      action.peerLink = WifiMeshActionHeader::PEER_LINK_OPEN;
+      fields.subtype = WifiMeshActionHeader::PEER_LINK_OPEN;
+      actionHdr.SetAction (WifiMeshActionHeader::MESH_PEER_LINK_MGT, action);
+    }
+  if (peerElement.SubtypeIsConfirm ())
+    {
+      m_stats.sendConfirm ++;
+      WifiMeshActionHeader::ActionValue action;
+      action.peerLink = WifiMeshActionHeader::PEER_LINK_CONFIRM;
+      fields.aid = aid;
+      fields.subtype = WifiMeshActionHeader::PEER_LINK_CONFIRM;
+      actionHdr.SetAction (WifiMeshActionHeader::MESH_PEER_LINK_MGT, action);
+    }
+  if (peerElement.SubtypeIsClose ())
+    {
+      m_stats.sendClose ++;
+      WifiMeshActionHeader::ActionValue action;
+      action.peerLink = WifiMeshActionHeader::PEER_LINK_CLOSE;
+      fields.subtype = WifiMeshActionHeader::PEER_LINK_CLOSE;
+      fields.reasonCode = peerElement.GetReasonCode ();
+      actionHdr.SetAction (WifiMeshActionHeader::MESH_PEER_LINK_MGT, action);
+    }
+  plinkFrame.SetPlinkFrameStart(fields);
+  packet->AddHeader (plinkFrame);
+  packet->AddHeader (actionHdr);
+  m_stats.sentMgt ++;
+  m_stats.sentMgtBytes += packet->GetSize ();
+  // Wifi Mac header:
+  WifiMacHeader hdr;
+  hdr.SetAction ();
+  hdr.SetAddr1 (peerAddress);
+  hdr.SetAddr2 (m_parent->GetAddress ());
+  //Addr is not used here, we use it as our MP address
+  hdr.SetAddr3 (m_protocol->GetAddress ());
+  hdr.SetDsNotFrom ();
+  hdr.SetDsNotTo ();
+  m_parent->SendManagementFrame(packet, hdr);
+}
+
+Mac48Address
+PeerManagerMacPlugin::GetAddress () const
+{
+  if(m_parent !=  0)
+    return m_parent->GetAddress ();
+  else return Mac48Address::Mac48Address();
+}
+std::pair<Time, Time> 
+PeerManagerMacPlugin::GetBeaconInfo() const
+{
+  std::pair<Time,Time> retval;
+  retval.first = m_parent->GetTbtt ();
+  retval.second = m_parent->GetBeaconInterval ();
+  return retval;
+}
+void
+PeerManagerMacPlugin::SetBeaconShift(Time shift)
+{
+  if(shift != Seconds (0))
+    m_stats.beaconShift ++;
+  m_parent->ShiftTbtt (shift);
+}
+PeerManagerMacPlugin::Statistics::Statistics () :
+  sendOpen (0),
+  sendConfirm (0),
+  sendClose (0),
+  recvOpen (0),
+  recvConfirm (0),
+  recvClose (0),
+  dropped (0),
+  brokenMgt (0),
+  sentMgt (0),
+  sentMgtBytes (0),
+  recvMgt (0),
+  recvMgtBytes (0),
+  beaconShift (0)
+{
+}
+void
+PeerManagerMacPlugin::Statistics::Print (std::ostream & os) const
+{
+  os << "<Statistics "
+    "sendOpen=\"" << sendOpen << "\"\n"
+    "sendConfirm=\"" << sendConfirm << "\"\n"
+    "sendClose=\"" << sendClose << "\"\n"
+    "recvOpen=\"" << recvOpen << "\"\n"
+    "recvConfirm=\"" << recvConfirm << "\"\n"
+    "recvClose=\"" << recvClose << "\"\n"
+    "dropped=\"" << dropped << "\"\n"
+    "brokenMgt=\"" << brokenMgt << "\"\n"
+    "sentMgt=\"" << sentMgt << "\"\n"
+    "sentMgtBytes=\"" << (double)sentMgtBytes /1024.0 << "\"\n"
+    "recvMgt=\"" << recvMgt << "\"\n"
+    "recvMgtBytes=\"" << (double)recvMgtBytes / 1024.0 << "K\"\n"
+    "beaconShift=\"" << beaconShift << "\"/>\n";
+}
+void
+PeerManagerMacPlugin::Report (std::ostream & os) const
+{
+  os << "<PeerManagerPlugin "
+    "address=\"" << m_parent->GetAddress () << "\">\n";
+  m_stats.Print (os);
+  os << "</PeerManagerPlugin>\n";
+}
+void
+PeerManagerMacPlugin::ResetStats ()
+{
+  m_stats = Statistics::Statistics ();
+}
+uint32_t
+PeerManagerMacPlugin::GetLinkMetric (Mac48Address peerAddress)
+{
+  return m_parent->GetLinkMetric (peerAddress);
+}
+} // namespace dot11s
+} //namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/peer-management-plugin.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,131 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ */
+
+#ifndef PEER_MANAGER_MAC_PLUGIN_H_
+#define PEER_MANAGER_MAC_PLUGIN_H_
+
+#include "ns3/mesh-wifi-interface-mac-plugin.h"
+
+namespace ns3 {
+class MeshWifiInterfaceMac;
+namespace dot11s {
+class PeerManagementProtocol;
+class IeConfiguration;
+class IePeerManagement;
+class PeerManagementProtocol;
+/**
+ * \ingroup dot11s
+ * 
+ * \brief This is plugin to Mesh WiFi MAC, which implements
+ * interface to dot11s peer management protocol: it takes proper
+ * frames from MAC-layer, extracts peer link management information
+ * element and mesh configuration element and passes it to main part
+ * of protocol
+ */
+class PeerManagerMacPlugin : public MeshWifiInterfaceMacPlugin
+{
+public:
+  PeerManagerMacPlugin (uint32_t interface, Ptr<PeerManagementProtocol> protocol);
+  ~PeerManagerMacPlugin ();
+  ///\name Inherited from plugin abstract class
+  ///\{
+  void SetParent (Ptr<MeshWifiInterfaceMac> parent);
+  bool Receive (Ptr<Packet> packet, const WifiMacHeader & header);
+  bool UpdateOutcomingFrame (Ptr<Packet> packet, WifiMacHeader & header, Mac48Address from, Mac48Address to);
+  void UpdateBeacon (MeshWifiBeacon & beacon) const;
+  ///\}
+  ///\name Statistics:
+  ///\{
+  void Report (std::ostream &) const;
+  void ResetStats ();
+  uint32_t GetLinkMetric (Mac48Address peerAddress);
+  ///\}
+private:
+  friend class PeerManagementProtocol;
+  friend class PeerLink; 
+  ///\name BCA functionallity:
+  ///\{
+  ///\brief Fills TBTT and beacon interval. Needed by BCA
+  ///functionallity
+  ///\param first in retval is TBTT
+  ///\param second in retval is beacon interval
+  std::pair<Time, Time> GetBeaconInfo() const;
+  void SetBeaconShift(Time shift);
+  ///\}
+  void SetPeerManagerProtcol(Ptr<PeerManagementProtocol> protocol);
+  void SendPeerLinkManagementFrame(
+      Mac48Address peerAddress,
+      Mac48Address peerMpAddress,
+      uint16_t aid,
+      IePeerManagement peerElement,
+      IeConfiguration meshConfig
+      );
+  ///\brief DUBUG only - to print established links
+  Mac48Address GetAddress () const;
+private:
+  ///\name Information about MAC and protocol:
+  ///\{
+  Ptr<MeshWifiInterfaceMac> m_parent;
+  uint32_t m_ifIndex;
+  Ptr<PeerManagementProtocol> m_protocol;
+   ///\}
+   ///\name Create peer link management frames:
+   ///\{
+  Ptr<Packet> CreatePeerLinkOpenFrame();
+  Ptr<Packet> CreatePeerLinkConfirmFrame();
+  Ptr<Packet> CreatePeerLinkCloseFrame();
+  ///This structure keeps all fields in peer link management frame,
+  ///which are not subclasses of WifiInformationElement
+  struct PlinkFrameStart {
+    uint8_t subtype;
+    uint16_t aid;
+    SupportedRates rates;
+    uint16_t qos;
+  };
+  /// \name Parses the start of the frame, where there are no
+  /// WifiInformationElements exist
+  PlinkFrameStart ParsePlinkFrame(Ptr<const Packet> packet);
+  ///\}
+  //Keeps statistics
+  struct Statistics {
+    uint16_t sendOpen;
+    uint16_t sendConfirm;
+    uint16_t sendClose;
+    uint16_t recvOpen;
+    uint16_t recvConfirm;
+    uint16_t recvClose;
+    uint16_t dropped;
+    uint16_t brokenMgt;
+    uint16_t sentMgt;
+    uint32_t sentMgtBytes;
+    uint16_t recvMgt;
+    uint32_t recvMgtBytes;
+    uint16_t beaconShift;
+    
+    Statistics ();
+    void Print (std::ostream & os) const;
+  };
+  struct Statistics m_stats;
+};
+  
+} // namespace dot11s
+} //namespace ns3
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/peer-management-protocol.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,525 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ *          Aleksey Kovalenko <kovalenko@iitp.ru>
+ */
+
+
+#include "peer-management-protocol.h"
+
+#include "ie-dot11s-peer-management.h"
+#include "ie-dot11s-configuration.h"
+
+#include "ns3/mesh-point-device.h"
+#include "ns3/simulator.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/random-variable.h"
+#include "ns3/mesh-wifi-interface-mac.h"
+#include "ns3/mesh-wifi-interface-mac-plugin.h"
+#include "ns3/wifi-net-device.h"
+#include "peer-link.h"
+#include "peer-management-plugin.h"
+
+
+NS_LOG_COMPONENT_DEFINE ("PeerManagementProtocol");
+namespace ns3 {
+namespace dot11s {
+/***************************************************
+ * PeerManager
+ ***************************************************/
+NS_OBJECT_ENSURE_REGISTERED (PeerManagementProtocol);
+
+TypeId
+PeerManagementProtocol::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::dot11s::PeerManagementProtocol")
+    .SetParent<Object> ()
+    .AddConstructor<PeerManagementProtocol> ()
+    // maximum number of peer links. Now we calculate the total
+    // number of peer links on all interfaces
+    .AddAttribute ("MaxNumberOfPeerLinks",
+        "Maximum number of peer links",
+        UintegerValue (32),
+        MakeUintegerAccessor (&PeerManagementProtocol::m_maxNumberOfPeerLinks),
+        MakeUintegerChecker<uint8_t> ()
+        );
+  return tid;
+}
+PeerManagementProtocol::PeerManagementProtocol ():
+  m_lastAssocId (0),
+  m_lastLocalLinkId (1),
+  m_numberOfActivePeers (0)
+{
+}
+PeerManagementProtocol::~PeerManagementProtocol ()
+{
+}
+void
+PeerManagementProtocol::DoDispose ()
+{
+  //cancel cleanup event and go through the map of peer links,
+  //deleting each
+  for (PeerLinksMap::iterator j = m_peerLinks.begin (); j != m_peerLinks.end (); j++)
+    {
+      for (PeerLinksOnInterface::iterator i = j->second.begin (); i != j->second.end(); i++)
+          (*i) = 0;
+      j->second.clear ();
+    }
+  m_peerLinks.clear ();
+  //cleaning beacon structures:
+  for(BeaconInfoMap::iterator i =  m_neighbourBeacons.begin(); i != m_neighbourBeacons.end(); i ++)
+  {
+    i->second.clear();
+  }
+  m_neighbourBeacons.clear();
+}
+
+bool
+PeerManagementProtocol::Install(Ptr<MeshPointDevice> mp)
+{
+  std::vector<Ptr<NetDevice> > interfaces = mp->GetInterfaces ();
+  for(std::vector<Ptr<NetDevice> >::iterator i = interfaces.begin(); i != interfaces.end(); i ++)
+  {
+    Ptr<WifiNetDevice> wifiNetDev = (*i)->GetObject<WifiNetDevice> ();
+    if (wifiNetDev == 0)
+      return false;
+    Ptr<MeshWifiInterfaceMac>  mac = wifiNetDev->GetMac ()->GetObject<MeshWifiInterfaceMac> ();
+    if (mac == 0)
+      return false;
+    Ptr<PeerManagerMacPlugin> peerPlugin = Create<PeerManagerMacPlugin> ((*i)->GetIfIndex(), this);
+    mac->InstallPlugin(peerPlugin);
+    m_plugins[(*i)->GetIfIndex()] = peerPlugin;
+    PeerLinksOnInterface newmap;
+    m_peerLinks[(*i)->GetIfIndex()] = newmap;
+  }
+  // Mesh point aggregates all installed protocols
+  m_address = Mac48Address::ConvertFrom(mp->GetAddress ());
+  NS_LOG_UNCOND("MP address:"<<m_address);
+  mp->AggregateObject(this);
+  return true;
+}
+
+Ptr<IeBeaconTiming>
+PeerManagementProtocol::GetBeaconTimingElement(uint32_t interface)
+{
+  Ptr<IeBeaconTiming> retval = Create<IeBeaconTiming> ();
+  BeaconInfoMap::iterator i = m_neighbourBeacons.find(interface);
+  if(i == m_neighbourBeacons.end())
+    return retval;
+  bool cleaned = false;
+  while(!cleaned)
+  {
+    for(BeaconsOnInterface::iterator j = i->second.begin(); j != i->second.end(); j++)
+    {
+      //check beacon loss and make a timing element
+      //if last beacon was 3 beacons ago - we do not put it to the
+      //timing element
+      if(
+          (j->second.referenceTbtt.GetMicroSeconds() +
+           (j->second.beaconInterval.GetMicroSeconds()* 3))
+          <
+          Simulator::Now().GetMicroSeconds()
+          )
+      {
+        i->second.erase(j);
+        break;
+      }
+    }
+    cleaned = true;
+  }
+  for(BeaconsOnInterface::const_iterator j = i->second.begin(); j != i->second.end(); j++)
+    retval->AddNeighboursTimingElementUnit(j->second.aid, j->second.referenceTbtt, j->second.beaconInterval);
+  return retval;
+}
+
+void
+PeerManagementProtocol::FillBeaconInfo(uint32_t interface, Mac48Address peerAddress, Time receivingTime, Time beaconInterval)
+{
+  BeaconInfoMap::iterator i = m_neighbourBeacons.find(interface);
+  if(i == m_neighbourBeacons.end())
+  {
+     BeaconsOnInterface newMap;
+     m_neighbourBeacons[interface] = newMap;
+  }
+  i = m_neighbourBeacons.find(interface);
+  BeaconsOnInterface::iterator j = i->second.find(peerAddress);
+  if(j == i->second.end())
+  {
+    BeaconInfo newInfo;
+    newInfo.referenceTbtt = receivingTime;
+    newInfo.beaconInterval = beaconInterval;
+    newInfo.aid = m_lastAssocId++;
+    if(m_lastAssocId == 0xff)
+      m_lastAssocId = 0;
+    i->second[peerAddress] = newInfo;
+  }
+  else
+  {
+    j->second.referenceTbtt = receivingTime;
+    j->second.beaconInterval = beaconInterval;
+  }
+}
+
+void
+PeerManagementProtocol::UpdatePeerBeaconTiming(
+    uint32_t interface,
+    bool meshBeacon,
+    IeBeaconTiming timingElement,
+    Mac48Address peerAddress,
+    Time receivingTime,
+    Time beaconInterval)
+{
+  FillBeaconInfo(interface, peerAddress, receivingTime, beaconInterval);
+   if(!meshBeacon)
+     return;
+   //BCA:
+   PeerManagerPluginMap::iterator plugin = m_plugins.find (interface);
+   NS_ASSERT(plugin != m_plugins.end ());
+   plugin->second->SetBeaconShift(GetNextBeaconShift(interface));
+   //PM STATE Machine
+   //Check that a given beacon is not from our interface
+   for(PeerManagerPluginMap::const_iterator i = m_plugins.begin (); i != m_plugins.end (); i ++)
+     if(i->second->GetAddress () == peerAddress)
+       return;
+   Ptr<PeerLink> peerLink = FindPeerLink(interface, peerAddress);
+   if(peerLink !=0)  
+   {
+     peerLink->SetBeaconTimingElement (timingElement);
+     peerLink->SetBeaconInformation (receivingTime, beaconInterval);
+   }
+   else
+   {
+     peerLink = InitiateLink (interface, peerAddress, Mac48Address::GetBroadcast (), receivingTime, beaconInterval);
+     peerLink->SetBeaconTimingElement (timingElement);
+     if (ShouldSendOpen (interface, peerAddress))
+       peerLink->MLMEActivePeerLinkOpen ();
+   }
+}
+
+void
+PeerManagementProtocol::ReceivePeerLinkFrame (
+    uint32_t interface,
+    Mac48Address peerAddress,
+    Mac48Address peerMeshPointAddress,
+    uint16_t aid,
+    IePeerManagement peerManagementElement,
+    IeConfiguration meshConfig
+      )
+{
+  Ptr<PeerLink> peerLink = FindPeerLink(interface, peerAddress);
+  if (peerManagementElement.SubtypeIsOpen ())
+  {
+    PmpReasonCode reasonCode;
+    bool reject = ! (ShouldAcceptOpen (interface, peerAddress,reasonCode));
+    if (peerLink == 0)
+      peerLink = InitiateLink (interface, peerAddress, peerMeshPointAddress, Simulator::Now (), Seconds(1.0));
+    if(!reject)
+    {
+      peerLink->MLMEPassivePeerLinkOpen ();
+      peerLink->OpenAccept (peerManagementElement.GetLocalLinkId(), meshConfig, peerMeshPointAddress);
+    }
+    else
+      peerLink->OpenReject (peerManagementElement.GetLocalLinkId(), meshConfig, peerMeshPointAddress, reasonCode);
+  }
+  if (peerLink == 0)
+    return;
+  if (peerManagementElement.SubtypeIsConfirm ())
+    peerLink->ConfirmAccept (
+        peerManagementElement.GetLocalLinkId(),
+        peerManagementElement.GetPeerLinkId(),
+        aid,
+        meshConfig,
+        peerMeshPointAddress);
+  if (peerManagementElement.SubtypeIsClose ())
+    peerLink->Close (
+        peerManagementElement.GetLocalLinkId(),
+        peerManagementElement.GetPeerLinkId(),
+        peerManagementElement.GetReasonCode()
+        );
+}
+
+void
+PeerManagementProtocol::ConfigurationMismatch (uint32_t interface, Mac48Address peerAddress)
+{
+  Ptr<PeerLink> peerLink = FindPeerLink(interface, peerAddress);
+  if(peerLink != 0)
+      peerLink->MLMECancelPeerLink (REASON11S_MESH_CAPABILITY_POLICY_VIOLATION);
+}
+
+Ptr<PeerLink>
+PeerManagementProtocol::InitiateLink (
+  uint32_t interface,
+  Mac48Address peerAddress,
+  Mac48Address peerMeshPointAddress,
+  Time lastBeacon,
+  Time beaconInterval)
+{
+  Ptr<PeerLink> new_link = CreateObject<PeerLink> ();
+  if (m_lastLocalLinkId == 0xff)
+    m_lastLocalLinkId = 0;
+  //find a beacon entry
+  BeaconInfoMap::iterator beaconsOnInterface = m_neighbourBeacons.find (interface);
+  if(beaconsOnInterface == m_neighbourBeacons.end())
+    FillBeaconInfo(interface, peerAddress, lastBeacon, beaconInterval);
+  beaconsOnInterface = m_neighbourBeacons.find (interface);
+  BeaconsOnInterface::iterator beacon = beaconsOnInterface->second.find (peerAddress);
+  if(beacon == beaconsOnInterface->second.end ())
+    FillBeaconInfo(interface, peerAddress, lastBeacon, beaconInterval);
+  beacon = beaconsOnInterface->second.find (peerAddress);
+  //find a peer link  - it must not exist
+  if(FindPeerLink(interface, peerAddress) != 0)
+  {
+    NS_ASSERT (false);
+  }
+  // Plugin must exist
+  PeerManagerPluginMap::iterator plugin = m_plugins.find (interface);
+  NS_ASSERT(plugin != m_plugins.end ());
+  PeerLinksMap::iterator iface = m_peerLinks.find (interface);
+  NS_ASSERT (iface != m_peerLinks.end());
+  new_link->SetLocalAid (beacon->second.aid);
+  new_link->SetInterface (interface);
+  new_link->SetLocalLinkId (m_lastLocalLinkId++);
+  new_link->SetPeerAddress (peerAddress);
+  new_link->SetPeerMeshPointAddress (peerMeshPointAddress);
+  new_link->SetBeaconInformation (lastBeacon, beaconInterval);
+  new_link->SetMacPlugin (plugin->second);
+  new_link->MLMESetSignalStatusCallback (MakeCallback(&PeerManagementProtocol::PeerLinkStatus, this));
+  iface->second.push_back (new_link);  
+  return new_link;
+}
+Ptr<PeerLink>
+PeerManagementProtocol::FindPeerLink(uint32_t interface, Mac48Address peerAddress)
+{
+  PeerLinksMap::iterator iface = m_peerLinks.find (interface);
+  NS_ASSERT (iface != m_peerLinks.end());
+  for (PeerLinksOnInterface::iterator i = iface->second.begin (); i != iface->second.end(); i++)
+    if ((*i)->GetPeerAddress () == peerAddress)
+    {
+      if((*i)->LinkIsIdle ())
+      {
+        (*i) = 0;
+        (iface->second).erase(i);
+        return 0;
+      }
+      else
+        return (*i);
+    }
+  return 0;
+}
+void
+PeerManagementProtocol::SetPeerLinkStatusCallback(Callback <void, Mac48Address, Mac48Address, uint32_t, bool> cb)
+{
+  m_peerStatusCallback = cb;
+}
+std::vector<Mac48Address>
+PeerManagementProtocol::GetActiveLinks(uint32_t interface)
+{
+  std::vector<Mac48Address> retval;
+  PeerLinksMap::iterator iface = m_peerLinks.find (interface);
+  NS_ASSERT (iface != m_peerLinks.end());
+  for (PeerLinksOnInterface::iterator i = iface->second.begin (); i != iface->second.end(); i++)
+    if((*i)->LinkIsEstab ())
+      retval.push_back((*i)->GetPeerAddress ());
+  return retval;
+}
+bool
+PeerManagementProtocol::IsActiveLink (uint32_t interface, Mac48Address peerAddress)
+{
+  Ptr<PeerLink> peerLink = FindPeerLink(interface, peerAddress);
+    if(peerLink != 0)
+      return (peerLink->LinkIsEstab ());
+  return false;
+}
+bool
+PeerManagementProtocol::ShouldSendOpen (uint32_t interface, Mac48Address peerAddress)
+{
+  if (m_numberOfActivePeers > m_maxNumberOfPeerLinks)
+    return false;
+  return true;
+}
+bool
+PeerManagementProtocol::ShouldAcceptOpen (
+    uint32_t interface,
+    Mac48Address peerAddress,
+    PmpReasonCode & reasonCode)
+{
+  if (m_numberOfActivePeers > m_maxNumberOfPeerLinks)
+    {
+      reasonCode = REASON11S_MESH_MAX_PEERS;
+      return false;
+    }
+  return true;
+}
+Time
+PeerManagementProtocol::GetNextBeaconShift (uint32_t interface)
+{
+  //REMINDER:: in timing element  1) last beacon reception time is measured in units of 256 microseconds
+  //                              2) beacon interval is mesured in units of 1024 microseconds
+  //                              3) hereafter TU = 1024 microseconds
+  //Im my MAC everything is stored in MicroSeconds
+
+  uint32_t myNextTbttInTimeUnits = Simulator::Now().GetMicroSeconds();
+  uint32_t futureBeaconInTimeUnits = 0;
+  //Going through all my timing elements and detecting future beacon collisions
+  PeerLinksMap::iterator iface = m_peerLinks.find (interface);
+  NS_ASSERT (iface != m_peerLinks.end());
+  PeerManagerPluginMap::iterator plugin = m_plugins.find (interface);
+  NS_ASSERT(plugin != m_plugins.end());
+  std::pair<Time, Time> myBeacon = plugin->second->GetBeaconInfo ();
+  for (PeerLinksOnInterface::iterator i = iface->second.begin (); i != iface->second.end (); i++)
+    {
+      IeBeaconTiming::NeighboursTimingUnitsList neighbours;
+      neighbours = (*i)->GetBeaconTimingElement ().GetNeighboursTimingElementsList();
+      //first let's form the list of all kown Tbtts
+      for (IeBeaconTiming::NeighboursTimingUnitsList::const_iterator j = neighbours.begin (); j != neighbours.end(); j++)
+        {
+          uint16_t beaconIntervalTimeUnits;
+          beaconIntervalTimeUnits = (*j)->GetBeaconInterval ();
+          //The last beacon time in timing elememt in Time Units
+          uint32_t lastBeaconInTimeUnits;
+          lastBeaconInTimeUnits = (*j)->GetLastBeacon ()/4;
+          //The time of my next beacon sending in Time Units
+          myNextTbttInTimeUnits = myBeacon.first.GetMicroSeconds ()/1024;
+          //My beacon interval in Time Units
+          uint32_t myBeaconIntervalInTimeUnits;
+          myBeaconIntervalInTimeUnits = myBeacon.second.GetMicroSeconds ()/1024;
+          //The time the beacon of other station will be sent
+          //we need the time just after my next Tbtt (or equal to my Tbtt)
+          futureBeaconInTimeUnits = lastBeaconInTimeUnits + beaconIntervalTimeUnits;
+          //We apply MBAC only if beacon Intervals are equal
+          if (beaconIntervalTimeUnits == myBeaconIntervalInTimeUnits)
+            {
+              //We know when the neighbor STA transmitted it's beacon
+              //Now we need to know when it's going to send it's beacon in the future
+              //So let's use the valuse of it's beacon interval
+              while (myNextTbttInTimeUnits >= futureBeaconInTimeUnits)
+                futureBeaconInTimeUnits = futureBeaconInTimeUnits + beaconIntervalTimeUnits;
+              //If we found that my Tbtt coincide with another STA's Tbtt
+              //break all cylce and return time shift for my next Tbtt
+              if (myNextTbttInTimeUnits == futureBeaconInTimeUnits)
+                break;
+            }
+        }
+      if (myNextTbttInTimeUnits == futureBeaconInTimeUnits)
+        break;
+    }
+  //Tbtts coincide, so let's calculate the shift
+  if (myNextTbttInTimeUnits == futureBeaconInTimeUnits)
+    {
+      NS_LOG_DEBUG ("MBCA: Future beacon collision is detected, applying avoidance mechanism");
+      UniformVariable randomSign (-1, 1);
+      int coefficientSign = -1;
+      if (randomSign.GetValue () >= 0)
+        coefficientSign = 1;
+      UniformVariable randomShift (1, 15);
+      //So, the shift is a random integer variable uniformly distributed in [-15;-1] U [1;15]
+      int beaconShift = randomShift.GetInteger (1,15) * coefficientSign;
+      NS_LOG_DEBUG ("Shift value = " << beaconShift << " beacon TUs");
+      //We need the result not in Time Units, but in microseconds
+      //Do not shift to the past
+      if(MicroSeconds(beaconShift * 1024) + Simulator::Now() < myBeacon.first)
+        return MicroSeconds (beaconShift * 1024);
+      else
+        return MicroSeconds (0);
+    }
+  //No collision detected, hence no shift is needed
+  else
+    return MicroSeconds (0);
+}
+void
+PeerManagementProtocol::PeerLinkStatus (uint32_t interface, Mac48Address peerAddress, Mac48Address peerMeshPointAddress, bool status)
+{
+   PeerManagerPluginMap::iterator plugin = m_plugins.find (interface);
+   NS_ASSERT(plugin != m_plugins.end());
+   NS_LOG_DEBUG(
+       "Link between me:" << m_address <<
+       " my interface:" << plugin->second->GetAddress() <<
+       " and peer mesh point:" << peerMeshPointAddress <<
+       " and its interface:" << peerAddress <<
+       ", at my interface ID:" << interface <<
+       ". Status:" << status);
+   if(status)
+   {
+     m_stats.linksOpened ++;
+     m_numberOfActivePeers ++;
+   }
+   else
+   {
+     m_stats.linksClosed ++;
+     m_numberOfActivePeers --;
+   }
+   if(!m_peerStatusCallback.IsNull ())
+     m_peerStatusCallback (peerMeshPointAddress, peerAddress, interface, status);
+}
+uint8_t
+PeerManagementProtocol::GetNumberOfLinks ()
+{
+  return m_numberOfActivePeers;
+}
+Ptr<IeMeshId>
+PeerManagementProtocol::GetMeshId () const
+{
+  NS_ASSERT (m_meshId != 0);
+  return m_meshId;
+}
+void
+PeerManagementProtocol::SetMeshId(char const meshId[32], uint8_t length)
+{
+  m_meshId = Create<IeMeshId> (meshId, length);
+}
+Mac48Address
+PeerManagementProtocol::GetAddress ()
+{
+  return m_address;
+}
+void
+PeerManagementProtocol::Statistics::Print (std::ostream & os) const
+{
+  os << "<Statistics "
+    "linksOpened=\"" << linksOpened << "\" "
+    "linksClosed=\"" << linksClosed << "\"/>\n";
+}
+void
+PeerManagementProtocol::Report (std::ostream & os) const
+{
+  os << "<PeerManagementProtocol>\n";
+  m_stats.Print (os);
+  for(PeerManagerPluginMap::const_iterator plugins = m_plugins.begin (); plugins != m_plugins.end (); plugins ++)
+  {
+    //Take statistics from plugin:
+    plugins->second->Report (os);
+    //Print all active peer links:
+    PeerLinksMap::const_iterator iface = m_peerLinks.find (plugins->second->m_ifIndex);
+    NS_ASSERT (iface != m_peerLinks.end());
+    for (PeerLinksOnInterface::const_iterator i = iface->second.begin (); i != iface->second.end(); i++)
+      (*i)->Report (os);
+  }
+  os << "</PeerManagementProtocol>\n";
+}
+void
+PeerManagementProtocol::ResetStats ()
+{
+  m_stats = Statistics::Statistics ();
+  for(PeerManagerPluginMap::const_iterator plugins = m_plugins.begin (); plugins != m_plugins.end (); plugins ++)
+    plugins->second->ResetStats ();
+}
+
+} // namespace dot11s
+} //namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/peer-management-protocol.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,239 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ *          Aleksey Kovalenko <kovalenko@iitp.ru>
+ */
+
+
+#ifndef DOT11S_PEER_MAN_H
+#define DOT11S_PEER_MAN_H
+
+#include "ns3/mac48-address.h"
+#include "ns3/net-device.h"
+#include "ns3/event-id.h"
+#include "ns3/nstime.h"
+#include "ie-dot11s-beacon-timing.h"
+#include "ie-dot11s-peer-management.h"
+#include "ie-dot11s-id.h"
+
+#include <map>
+namespace ns3 {
+class MeshPointDevice;
+namespace dot11s {
+class PeerManagerMacPlugin;
+class PeerLink;
+class IePeerManagement;
+class IeConfiguration;
+/**
+ * \ingroup dot11s
+ * 
+ * \brief 802.11s Peer Management Protocol model 
+ */
+class PeerManagementProtocol : public Object
+{
+public:
+  PeerManagementProtocol ();
+  ~PeerManagementProtocol ();
+  static TypeId GetTypeId ();
+  void DoDispose ();
+  /** 
+   * \brief Install PMP on given mesh point. 
+   * 
+   * Installing protocol cause installing its interface MAC plugins.
+   *  
+   * Also MP aggregates all installed protocols, PMP protocol can be accessed 
+   * via MeshPointDevice::GetObject<PeerManagementProtocol>();
+   */
+  bool Install(Ptr<MeshPointDevice>);
+  /** 
+   * \brief Methods that handle beacon sending/receiving procedure.
+   * 
+   * This methods interact with MAC_layer plug-in
+   * \{
+   */
+  /**
+   * \brief When we are sending a beacon - we fill beacon timing
+   * element
+   * \param IeBeaconTiming is a beacon timing element that
+   * should be present in beacon
+   * \param interface is a interface sending a beacon
+   */
+  Ptr<IeBeaconTiming> GetBeaconTimingElement(uint32_t interface);
+  /**
+   * \brief When we receive a beacon from peer-station, we remember
+   * its beacon timing element (needed for peer choosing mechanism),
+   * and remember beacon timers - last beacon and beacon interval to
+   * detect beacon loss and cancel links
+   * \param interface is a interface on which beacon was received
+   * \param timingElement is a timing element of remote beacon
+   */
+  void UpdatePeerBeaconTiming(
+      uint32_t interface,
+      bool meshBeacon,
+      IeBeaconTiming timingElement,
+      Mac48Address peerAddress,
+      Time receivingTime,
+      Time beaconInterval
+      );
+  //\}
+  /**
+   * \brief Methods that handle Peer link management frames
+   * interaction:
+   * \{
+   */
+  /**
+   * Deliver Peer link management information to the protocol-part
+   * \param void is returning value - we pass a frame and forget
+   * about it
+   * \param uint32_t - is a interface ID of a given MAC (interfaceID rather
+   * than MAC address, beacause many interfaces may have the same MAC)
+   * \param Mac48Address is address of peer
+   * \param Mac48Address is address of peer mesh point device (equal
+   * to peer address when only one interface)
+   * \param uint16_t is association ID, which peer has assigned to
+   * us
+   * \param IeConfiguration is mesh configuration element
+   * taken from the peer management frame
+   * \param IePeerManagement is peer link management element
+   */
+  void ReceivePeerLinkFrame(
+      uint32_t interface,
+      Mac48Address peerAddress,
+      Mac48Address peerMeshPointAddress,
+      uint16_t aid,
+      IePeerManagement peerManagementElement,
+      IeConfiguration meshConfig
+      );
+  /**
+   * Cancell peer link due to broken configuration (SSID or Supported
+   * rates)
+   */
+  void ConfigurationMismatch (uint32_t interface, Mac48Address peerAddress);
+  /**
+   * Checks if there is established link
+   */
+  bool IsActiveLink (uint32_t interface, Mac48Address peerAddress);
+  //\}
+  ///\brief Needed by external module to do MLME
+  Ptr<PeerLink> FindPeerLink(uint32_t interface, Mac48Address peerAddress);
+  void SetPeerLinkStatusCallback (Callback<void, Mac48Address, Mac48Address, uint32_t, bool> cb);
+  std::vector<Mac48Address> GetActiveLinks(uint32_t interface);
+  ///\brief needed by plugins to set global source address
+  Mac48Address GetAddress ();
+  ///\Needed to fill mesh configuration
+  uint8_t GetNumberOfLinks ();
+  void SetMeshId (char const meshId[32], uint8_t length);
+  Ptr<IeMeshId> GetMeshId() const;
+  ///\brief: Report statistics
+  void Report (std::ostream &) const;
+  void ResetStats ();
+private:
+  /** \name Private structures
+   * \{
+   */
+  /// Keeps information about beacon of peer station: beacon interval, association ID, last time we have received a beacon
+  struct BeaconInfo
+  {
+    uint16_t aid; //Assoc ID
+    Time referenceTbtt; //When one of my station's beacons was put into a beacon queue;
+    Time beaconInterval; //Beacon interval of my station;
+  };
+  /// We keep a vector of pointers to PeerLink class. This vector
+  /// keeps all peer links at a given interface.
+  typedef std::vector<Ptr<PeerLink> > PeerLinksOnInterface;
+  /// This map keeps all peer links.
+  ///\param uint32_t is interface ID
+  typedef std::map<uint32_t, PeerLinksOnInterface>  PeerLinksMap;
+  ///\brief This map keeps relationship between peer address and its
+  /// beacon information
+  typedef std::map<Mac48Address, BeaconInfo>  BeaconsOnInterface;
+  ///\brief This map keeps beacon information on all intefaces
+  typedef std::map<uint32_t, BeaconsOnInterface> BeaconInfoMap;
+  ///\brief this vector keeps pointers to MAC-plugins
+  typedef std::map<uint32_t, Ptr<PeerManagerMacPlugin> > PeerManagerPluginMap;
+  ///\}
+private:
+  /**
+   * Return a position in beacon-storage for a given remote station
+   */
+  void FillBeaconInfo(uint32_t interface, Mac48Address peerAddress, Time receivingTime, Time beaconInterval);
+  Ptr<PeerLink> InitiateLink (
+      uint32_t interface,
+      Mac48Address peerAddress,
+      Mac48Address peerMeshPointAddress,
+      Time lastBeacon,
+      Time beaconInterval
+      );
+  /**
+   * \name External peer-chooser
+   * \{
+   */
+  bool ShouldSendOpen (uint32_t interface, Mac48Address peerAddress);
+  bool ShouldAcceptOpen (uint32_t interface, Mac48Address peerAddress, PmpReasonCode & reasonCode);
+  /**
+   * \}
+   * \brief Indicates changes in peer links
+   */
+  void PeerLinkStatus (uint32_t interface, Mac48Address peerAddress, Mac48Address peerMeshPointAddres, bool status);
+  ///\brief BCA
+  Time GetNextBeaconShift (uint32_t interface);
+private:
+  PeerManagerPluginMap m_plugins;
+  Mac48Address m_address;
+  Ptr<IeMeshId> m_meshId;
+  /**
+   * \name Information related to beacons:
+   * \{
+   */
+  BeaconInfoMap m_neighbourBeacons;
+  ///\}
+  uint16_t m_lastAssocId;
+  uint16_t m_lastLocalLinkId;
+  uint8_t m_numberOfActivePeers; //number of established peer links
+  uint8_t m_maxNumberOfPeerLinks;
+  /**
+   * Peer Links
+   * \{
+   */
+  PeerLinksMap m_peerLinks;
+  /**
+   * \}
+   */
+  ///\brief Callback to notify about peer link changes:
+  ///\param Mac48Address is peer address of mesh point
+  ///\param Mac48Address is peer address of interface
+  ///\param uint32_t - interface ID
+  ///\param bool is staus - true when new link has appeared, false -
+  //when link was closed
+  Callback <void, Mac48Address, Mac48Address, uint32_t, bool> m_peerStatusCallback;
+  ///\}
+  //Keeps statistics
+  struct Statistics {
+    uint16_t linksOpened;
+    uint16_t linksClosed;
+
+    Statistics () : linksOpened (0), linksClosed (0) {};
+    void Print (std::ostream & os) const;
+  };
+  struct Statistics m_stats;
+
+};
+  
+} // namespace dot11s
+} //namespace ns3
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/waf	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../../waf "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/dot11s/wscript	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,38 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    obj = bld.create_ns3_module('dot11s', ['wifi'])
+    obj.source = [
+        'ie-dot11s-beacon-timing.cc',
+        'ie-dot11s-configuration.cc',
+        'ie-dot11s-id.cc',
+        'ie-dot11s-peer-management.cc',
+        'ie-dot11s-preq.cc',
+        'ie-dot11s-prep.cc',
+        'ie-dot11s-perr.cc',
+        'ie-dot11s-rann.cc',
+        'ie-dot11s-peering-protocol.cc',
+        'dot11s-mac-header.cc',
+        'peer-link-frame.cc',
+        'peer-link.cc',
+        'peer-management-plugin.cc',
+        'peer-management-protocol.cc',
+        'hwmp-tag.cc',
+        'hwmp-rtable.cc',
+        'hwmp-mac-plugin.cc',
+        'hwmp-protocol.cc',
+        'airtime-metric.cc',
+        'dot11s-helper.cc',
+        ]
+    headers = bld.new_task_gen('ns3header')
+    headers.module = 'dot11s'
+    headers.source = [
+        'peer-management-protocol.h',
+        'ie-dot11s-beacon-timing.h', 
+        'ie-dot11s-id.h',
+        'ie-dot11s-peer-management.h', 
+        'ie-dot11s-perr.h',
+        'hwmp-protocol.h',
+        'dot11s-helper.h',
+        'dot11s-mac-header.h',
+        ]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/mesh-l2-routing-protocol.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,55 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ *          Pavel Boyko <boyko@iitp.ru>
+ */
+
+#include "ns3/log.h"
+#include "ns3/mesh-l2-routing-protocol.h"
+#include "ns3/mesh-point-device.h"
+
+NS_LOG_COMPONENT_DEFINE ("MeshL2RoutingProtocol");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (MeshL2RoutingProtocol);
+
+TypeId
+MeshL2RoutingProtocol::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::MeshL2RoutingProtocol")
+                      .SetParent<Object> ();
+  return tid;
+}
+
+MeshL2RoutingProtocol::~MeshL2RoutingProtocol ()
+{
+}
+
+void
+MeshL2RoutingProtocol::SetMeshPoint (Ptr<MeshPointDevice> mp)
+{
+  m_mp = mp;
+}
+
+Ptr<MeshPointDevice> MeshL2RoutingProtocol::GetMeshPoint () const
+{
+  return m_mp;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/mesh-l2-routing-protocol.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,108 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ *          Pavel Boyko <boyko@iitp.ru>
+ */
+
+#ifndef MESH_L2_ROUTING_PROTOCOL_H
+#define MESH_L2_ROUTING_PROTOCOL_H
+
+#include "ns3/object.h"
+#include "ns3/mac48-address.h"
+#include "ns3/packet.h"
+
+namespace ns3 {
+
+class Packet;
+class MeshPointDevice;
+
+/**
+ * \ingroup mesh
+ *
+ * \brief Interface for L2 mesh routing protocol and mesh point communication. 
+ *
+ * Every mesh routing protocol must implement this interface. Each mesh point (MeshPointDevice) is supposed
+ * to know single L2RoutingProtocol to work with, see MeshPointDevice::SetRoutingProtocol ().  
+ * 
+ * This interface is similar to ipv4 routiong protocol base class.
+ */
+class MeshL2RoutingProtocol : public Object
+{
+public:
+  /// Never forget to support NS3 object model
+  static TypeId GetTypeId ();
+  /// virtual D-tor for subclasses
+  virtual ~MeshL2RoutingProtocol ();
+  /**
+   * Callback to be invoked when route discovery  procedure is completed.
+   * 
+   * \param flag        indicating whether a route was actually found and all needed information is 
+   *                    added to the packet succesfully
+   *                    
+   * \param packet      for which the route was resolved. All routing information for MAC layer
+   *                    must be stored in proper tags (like in case of HWMP, when WifiMacHeader 
+   *                    needs address of next hop), or must be added as a packet header (if MAC
+   *                    does not need any additional information). So, the packet is returned back 
+   *                    to MeshPointDevice looks like a pure packet with ethernet header 
+   *                    (i.e data + src +dst + protocol). The only special information addressed
+   *                    to MeshPointDevice is an outcoming interface ID.
+   *                    
+   * \param src         source address of the packet
+   * 
+   * \param dst         destiation address of the packet
+   * 
+   * \param protocol    ethernet 'Protocol' field, needed to form a proper MAC-layer header
+   * 
+   * \param uint32_t    outcoming interface to use or 0xffffffff if packet should be sent by ALL interfaces
+   */
+  typedef Callback<void,/* return type */
+          bool,        /* flag */
+          Ptr<Packet>, /* packet */
+          Mac48Address,/* src */
+          Mac48Address,/* dst */
+          uint16_t,    /* protocol */
+          uint32_t     /* out interface ID */ 
+          > RouteReplyCallback;
+  /**
+   * Request routing information, all packets must go through this request.
+   * 
+   * Note that route discobery works async. -- RequestRoute returns immediately, while
+   * reply callback will be called when routing information will be avaliable.
+   * \return true if valid route is already known
+   * \param sourceIface the incoming interface of the packet
+   * \param source        source address
+   * \param destination   destination address
+   * \param packet        the packet to be resolved (needed the whole packet, because
+   *                      routing information is added as tags or headers). The packet
+   *                      will be retutned to reply callback. 
+   * \param protocolType  protocol ID, needed to form a proper MAC-layer header
+   * \param routeReply    callback to be invoked after route discovery procedure, supposed 
+   *                      to really send packetusing routing information.
+   */
+  virtual bool RequestRoute (uint32_t sourceIface, const Mac48Address source, const Mac48Address destination, 
+      Ptr<Packet> packet, uint16_t  protocolType, RouteReplyCallback routeReply ) = 0;
+  /// Set host mesh point, analog of SetNode (...) methods for upper layer protocols.
+  void SetMeshPoint (Ptr<MeshPointDevice> mp);
+  /// Each mesh protocol must be installed on the mesh point to work.
+  Ptr<MeshPointDevice> GetMeshPoint () const; 
+protected:
+  /// Host mesh point
+  Ptr<MeshPointDevice> m_mp;
+};
+}//namespace ns3
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/mesh-point-device.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,390 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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: Kirill Andreev <andreev@iitp.ru>
+ *         Pavel Boyko <boyko@iitp.ru>
+ */
+
+
+#include "ns3/node.h"
+#include "ns3/packet.h"
+#include "ns3/log.h"
+#include "ns3/pointer.h"
+#include "ns3/mesh-point-device.h"
+#include "ns3/wifi-net-device.h"
+#include "ns3/mesh-wifi-interface-mac.h"
+
+NS_LOG_COMPONENT_DEFINE ("MeshPointDevice");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (MeshPointDevice);
+
+TypeId
+MeshPointDevice::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::MeshPointDevice")
+                      .SetParent<NetDevice> ()
+                      .AddConstructor<MeshPointDevice> ()
+                      .AddAttribute ("RoutingProtocol", "The mesh routing protocol used by this mesh point.",
+                          PointerValue (),
+                          MakePointerAccessor (&MeshPointDevice::GetRoutingProtocol,
+                                               &MeshPointDevice::SetRoutingProtocol),
+                          MakePointerChecker<MeshL2RoutingProtocol> ())
+                      ;
+  return tid;
+}
+
+MeshPointDevice::MeshPointDevice () : m_ifIndex (0), m_mtu(1500)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_channel = CreateObject<BridgeChannel> ();
+}
+
+MeshPointDevice::~MeshPointDevice ()
+{
+  NS_LOG_FUNCTION_NOARGS ();
+}
+
+void
+MeshPointDevice::DoDispose ()
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  for (std::vector< Ptr<NetDevice> >::iterator iter = m_ifaces.begin (); iter != m_ifaces.end (); iter++)
+    *iter = 0;
+  m_ifaces.clear ();
+  m_node = 0;
+  NetDevice::DoDispose ();
+
+}
+
+//-----------------------------------------------------------------------------
+// NetDevice interface implementation
+//-----------------------------------------------------------------------------
+
+void
+MeshPointDevice::ReceiveFromDevice (Ptr<NetDevice> incomingPort, Ptr<const Packet> packet, uint16_t protocol,
+                                       Address const &src, Address const &dst, PacketType packetType)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_DEBUG ("UID is " << packet->GetUid ());
+  const Mac48Address src48 = Mac48Address::ConvertFrom (src);
+  const Mac48Address dst48 = Mac48Address::ConvertFrom (dst);
+  NS_LOG_DEBUG ("SRC="<<src48<<", DST = "<<dst48<<", I am: "<<m_address);
+  if (!m_promiscRxCallback.IsNull ())
+    m_promiscRxCallback (this, packet, protocol, src, dst, packetType);
+  if(dst48.IsBroadcast () || dst48.IsGroup ())
+  {
+    m_rxCallback (this, packet, protocol, src);
+    Forward (incomingPort, packet->Copy (), protocol, src48, dst48);
+    return;
+  }
+  if(dst48 == m_address)
+    m_rxCallback (this, packet, protocol, src);
+  else
+    Forward (incomingPort, packet->Copy (), protocol, src48, dst48);
+}
+
+void
+MeshPointDevice::Forward (Ptr<NetDevice> inport, Ptr<Packet> packet,
+                             uint16_t protocol, const Mac48Address src, const Mac48Address dst)
+{
+  // pass through routing protocol
+  m_requestRoute (inport->GetIfIndex(), src, dst, packet, protocol, m_myResponse);
+}
+
+void
+MeshPointDevice::SetName (const std::string name)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_name = name;
+}
+
+std::string
+MeshPointDevice::GetName () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_name;
+}
+
+void
+MeshPointDevice::SetIfIndex (const uint32_t index)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_ifIndex = index;
+}
+
+uint32_t
+MeshPointDevice::GetIfIndex () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_ifIndex;
+}
+
+Ptr<Channel>
+MeshPointDevice::GetChannel () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_channel;
+}
+
+Address
+MeshPointDevice::GetAddress () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_address;
+}
+
+bool
+MeshPointDevice::SetMtu (const uint16_t mtu)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_mtu = mtu;
+  return true;
+}
+
+uint16_t
+MeshPointDevice::GetMtu () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_mtu;
+}
+
+bool
+MeshPointDevice::IsLinkUp () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return true;
+}
+
+void
+MeshPointDevice::SetLinkChangeCallback (Callback<void> callback)
+{
+  // do nothing
+}
+
+bool
+MeshPointDevice::IsBroadcast () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return true;
+}
+
+Address
+MeshPointDevice::GetBroadcast () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return Mac48Address ("ff:ff:ff:ff:ff:ff");
+}
+
+bool
+MeshPointDevice::IsMulticast () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return true;
+}
+
+Address
+MeshPointDevice::GetMulticast (Ipv4Address multicastGroup) const
+{
+  NS_LOG_FUNCTION (this << multicastGroup);
+  Mac48Address multicast = Mac48Address::GetMulticast (multicastGroup);
+  return multicast;
+}
+
+bool
+MeshPointDevice::IsPointToPoint () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return false;
+}
+
+bool
+MeshPointDevice::IsBridge () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return false;
+}
+
+
+bool
+MeshPointDevice::Send (Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
+{
+  const Mac48Address dst48 = Mac48Address::ConvertFrom (dest);
+  NS_LOG_DEBUG("SEND:, DST = "<<dst48<<", I am: "<<m_address);
+  return m_requestRoute (m_ifIndex, m_address, dst48, packet, protocolNumber, m_myResponse);
+}
+
+bool
+MeshPointDevice::SendFrom (Ptr<Packet> packet, const Address& src, const Address& dest, uint16_t protocolNumber)
+{
+  const Mac48Address src48 = Mac48Address::ConvertFrom (src);
+  const Mac48Address dst48 = Mac48Address::ConvertFrom (dest);
+  return m_requestRoute (m_ifIndex, src48, dst48, packet, protocolNumber, m_myResponse);
+}
+
+Ptr<Node>
+MeshPointDevice::GetNode () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_node;
+}
+
+void
+MeshPointDevice::SetNode (Ptr<Node> node)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_node = node;
+}
+
+bool
+MeshPointDevice::NeedsArp () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return true;
+}
+
+void
+MeshPointDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_rxCallback = cb;
+}
+
+void
+MeshPointDevice::SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_promiscRxCallback = cb;
+}
+
+bool
+MeshPointDevice::SupportsSendFrom () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return false; // don't allow to bridge mesh network with something else.
+}
+
+Address
+MeshPointDevice::GetMulticast (Ipv6Address addr) const
+{
+  NS_LOG_FUNCTION (this << addr);
+  return Mac48Address::GetMulticast (addr);
+}
+
+//-----------------------------------------------------------------------------
+// Interfaces
+//-----------------------------------------------------------------------------
+uint32_t
+MeshPointDevice::GetNInterfaces () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_ifaces.size ();
+}
+
+Ptr<NetDevice>
+MeshPointDevice::GetInterface (uint32_t n) const
+{
+  for(std::vector< Ptr<NetDevice> >::const_iterator i = m_ifaces.begin (); i != m_ifaces.end (); i ++)
+    if((*i)->GetIfIndex() == n)
+      return (*i);
+  NS_ASSERT(false);
+  return 0;
+}
+std::vector<Ptr<NetDevice> >
+MeshPointDevice::GetInterfaces () const
+{
+  return m_ifaces;
+}
+void
+MeshPointDevice::AddInterface (Ptr<NetDevice> iface)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  
+  NS_ASSERT (iface != this);
+  if (!Mac48Address::IsMatchingType (iface->GetAddress ()))
+  {
+    NS_FATAL_ERROR ("Device does not support eui 48 addresses: cannot be used as a mesh point interface.");
+  }
+  if (!iface->SupportsSendFrom ())
+  {
+    NS_FATAL_ERROR ("Device does not support SendFrom: cannot be used as a mesh point interface.");
+  }
+  
+  // Mesh point has MAC address of it's first interface
+  if (m_ifaces.empty()) 
+    m_address = Mac48Address::ConvertFrom (iface->GetAddress ());
+  
+  const WifiNetDevice * wifiNetDev = dynamic_cast<const WifiNetDevice *> (PeekPointer (iface));
+  if (wifiNetDev == 0)
+    NS_FATAL_ERROR ("Device is not a WiFi NIC: cannot be used as a mesh point interface.");
+      
+  MeshWifiInterfaceMac * ifaceMac = dynamic_cast<MeshWifiInterfaceMac *> (PeekPointer (wifiNetDev->GetMac ()));
+  if (ifaceMac == 0)
+    NS_FATAL_ERROR ("WiFi device doesn't have correct MAC installed: cannot be used as a mesh point interface.");
+
+  ifaceMac->SetMeshPointAddress (m_address);
+  
+  // Receive frames from this interface
+  m_node->RegisterProtocolHandler (MakeCallback (&MeshPointDevice::ReceiveFromDevice, this),
+                                   0, iface, /*promiscuous = */true);
+  
+  m_ifaces.push_back (iface);
+  m_channel->AddChannel (iface->GetChannel ());
+}
+
+//-----------------------------------------------------------------------------
+// Protocols
+//-----------------------------------------------------------------------------
+
+void
+MeshPointDevice::SetRoutingProtocol (Ptr<MeshL2RoutingProtocol> protocol)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  
+  NS_ASSERT_MSG (PeekPointer(protocol->GetMeshPoint()) == this, "Routing protocol must be installed on mesh point to be useful.");
+  
+  m_routingProtocol = protocol;
+  m_requestRoute = MakeCallback (&MeshL2RoutingProtocol::RequestRoute, protocol);
+  m_myResponse = MakeCallback (&MeshPointDevice::DoSend, this);
+  
+  return;
+}
+
+Ptr<MeshL2RoutingProtocol>
+MeshPointDevice::GetRoutingProtocol () const
+{
+  return m_routingProtocol;
+}
+
+void
+MeshPointDevice::DoSend (bool success, Ptr<Packet> packet, Mac48Address src, Mac48Address dst, uint16_t protocol, uint32_t outIface)
+{
+  if (!success)
+    {
+      NS_LOG_DEBUG ("Resolve failed");
+      return;
+    }
+  // Ok, now I know the route, just SendFrom
+  if (outIface != 0xffffffff)
+    GetInterface (outIface)->SendFrom(packet, src, dst, protocol);
+  else
+    for (std::vector<Ptr<NetDevice> >::iterator i = m_ifaces.begin (); i != m_ifaces.end(); i++)
+      (*i) -> SendFrom (packet, src, dst, protocol);
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/mesh-point-device.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,175 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008,2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ *          Pavel Boyko <boyko@iitp.ru>
+ */
+
+
+#ifndef L2ROUTING_NET_DEVICE_H
+#define L2ROUTING_NET_DEVICE_H
+
+#include "ns3/net-device.h"
+#include "ns3/mac48-address.h"
+#include "ns3/bridge-channel.h"
+#include "ns3/mesh-l2-routing-protocol.h"
+
+namespace ns3 {
+  
+class Node;
+/**
+ * \ingroup mesh
+ *
+ * \brief Virtual net device modeling mesh point. 
+ *
+ * Mesh point is a virtual net device which is responsible for
+ *   - Aggreagating and coordinating 1..* real devices -- mesh interfaces, see MeshInterfaceDevice class. 
+ *   - Hosting all mesh-related level 2 protocols. 
+ * 
+ * One of hosted L2 protocols must inplement L2RoutingProtocol interface and is used for packets forwarding.
+ *
+ * From the level 3 point of view MeshPointDevice is similar to BridgeNetDevice, but the packets, 
+ * which going through may be changed (because L2 protocols may require their own headers or tags).
+ * 
+ * Attributes: TODO
+ */
+class MeshPointDevice : public NetDevice
+{
+public:
+  /// Object type ID for NS3 object system
+  static TypeId GetTypeId ();
+  /// C-tor create empty (without interfaces and protocols) mesh point
+  MeshPointDevice ();
+  /// D-tor
+  virtual ~MeshPointDevice ();
+  
+  ///\name Interfaces 
+  //\{
+  /**
+   * \brief Attach new interface to the station. Interface must support 48-bit MAC address and SendFrom method.
+   * 
+   * \attention Only MeshPointDevice can have IP address, but not individual interfaces. 
+   */
+  void AddInterface (Ptr<NetDevice> port);
+  /**
+   * \return number of interfaces
+   */
+  uint32_t GetNInterfaces () const;
+  /**
+   * \return interface device by its index (aka ID)
+   * \param id is interface id, 0 <= id < GetNInterfaces
+   */
+  Ptr<NetDevice> GetInterface (uint32_t id) const;
+  /**
+   * \return vector of interfaces
+   */
+  std::vector<Ptr<NetDevice> > GetInterfaces () const;
+  //\}
+  
+  ///\name Protocols
+  //\{
+  /// Register routing protocol to be used. Protocol must be alredy installed on this mesh point.
+  void SetRoutingProtocol (Ptr<MeshL2RoutingProtocol> protocol);
+  /// Access current routing protocol
+  Ptr<MeshL2RoutingProtocol> GetRoutingProtocol() const;
+  //\}
+  
+  ///\name NetDevice interface for upper layers
+  //\{
+  virtual void SetName (const std::string name);
+  virtual std::string GetName () const;
+  virtual void SetIfIndex (const uint32_t index);
+  virtual uint32_t GetIfIndex () const;
+  virtual Ptr<Channel> GetChannel () const;
+  virtual Address GetAddress () const;
+  virtual bool SetMtu (const uint16_t mtu);
+  virtual uint16_t GetMtu () const;
+  virtual bool IsLinkUp () const;
+  virtual void SetLinkChangeCallback (Callback<void> callback);
+  virtual bool IsBroadcast () const;
+  virtual Address GetBroadcast () const;
+  virtual bool IsMulticast () const;
+  virtual Address GetMulticast (Ipv4Address multicastGroup) const;
+  virtual bool IsPointToPoint () const;
+  virtual bool IsBridge () const;
+  virtual bool Send (Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber);
+  virtual bool SendFrom (Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
+  virtual Ptr<Node> GetNode () const;
+  virtual void SetNode (Ptr<Node> node);
+  virtual bool NeedsArp () const;
+  virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb);
+  virtual void SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb);
+  virtual bool SupportsSendFrom () const;
+  virtual Address GetMulticast (Ipv6Address addr) const;
+  virtual void DoDispose ();
+  //\}
+  
+private:
+  /// Receive packet from interface
+  void ReceiveFromDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
+                          Address const &source, Address const &destination, PacketType packetType);
+  /// Forward packet down to interfaces 
+  void Forward (Ptr<NetDevice> incomingPort, Ptr<Packet> packet,
+                uint16_t protocol, const Mac48Address src, const Mac48Address dst);
+  /**
+   * Response callback for L2 routing protocol. This will be executed when routing information is ready.
+   * 
+   * \param success     True is route found. TODO: diagnose routing errors
+   * \param packet      Packet to send
+   * \param src         Source MAC address
+   * \param dst         Destination MAC address
+   * \param protocol    Protocol ID
+   * \param outIface    Interface to use (ID) for send (decided by routing protocol). All interfaces will be used if outIface = 0xffffffff
+   */
+  void DoSend (bool success, Ptr<Packet> packet, Mac48Address src, Mac48Address dst, uint16_t protocol, uint32_t iface);
+  
+private:
+  /// Receive action
+  NetDevice::ReceiveCallback   m_rxCallback;
+  /// Promisc receive action
+  NetDevice::PromiscReceiveCallback  m_promiscRxCallback;
+  /// Mesh point MAC address, supposed to be the address of the first added interface
+  Mac48Address m_address;
+  /// Parent node
+  Ptr<Node> m_node;
+  /// Station name
+  std::string m_name;
+  /// List of interfaces
+  std::vector< Ptr<NetDevice> > m_ifaces;
+  /// If index 
+  uint32_t m_ifIndex;
+  /// MTU in bytes
+  uint16_t m_mtu;
+  /// Virtual channel for upper layers
+  Ptr<BridgeChannel> m_channel;
+  
+  /// Routing request callback
+  Callback<bool,
+           uint32_t,
+           Mac48Address,
+           Mac48Address,
+           Ptr<Packet>,
+           uint16_t,
+           MeshL2RoutingProtocol::RouteReplyCallback>  m_requestRoute;
+  
+  /// Routing response callback, this is supplied to mesh routing protocol
+  MeshL2RoutingProtocol::RouteReplyCallback  m_myResponse;
+  /// Current routing protocol, used mainly by GetRoutingProtocol
+  Ptr<MeshL2RoutingProtocol> m_routingProtocol;
+};
+} //namespace ns3
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/mesh-wifi-beacon.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,81 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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: Pavel Boyko <boyko@iitp.ru>
+ */
+
+#include "ns3/mesh-wifi-beacon.h"
+#include <algorithm>
+
+namespace ns3 {
+  
+MeshWifiBeacon::MeshWifiBeacon (Ssid ssid, SupportedRates rates, uint64_t us)
+{
+  m_header.SetSsid (ssid);
+  m_header.SetSupportedRates (rates);
+  m_header.SetBeaconIntervalUs (us);
+}
+
+void MeshWifiBeacon::AddInformationElement (Ptr<WifiInformationElement> ie)
+{
+  m_elements.push_back (ie);
+}
+
+namespace {
+/// aux sorter for Ptr<WifiInformationElement>
+struct PIEComparator
+{
+  bool operator () (Ptr<WifiInformationElement> a, Ptr<WifiInformationElement> b) const
+  {
+    return ((*PeekPointer (a)) < (*PeekPointer(b)));
+  }
+};
+}
+
+Ptr<Packet> MeshWifiBeacon::CreatePacket ()
+{
+  Ptr<Packet> packet = Create<Packet> ();
+  
+  std::sort (m_elements.begin(), m_elements.end(), PIEComparator());
+  
+  std::vector< Ptr<WifiInformationElement> >::const_reverse_iterator i;
+  for (i = m_elements.rbegin(); i != m_elements.rend(); ++i)
+  {
+    packet->AddHeader (**i);
+  }
+  
+  packet->AddHeader (BeaconHeader());
+  
+  return packet;
+}
+
+WifiMacHeader MeshWifiBeacon::CreateHeader (Mac48Address address, Mac48Address mpAddress)
+{
+  WifiMacHeader hdr;
+    
+  hdr.SetBeacon ();
+  hdr.SetAddr1 (Mac48Address::GetBroadcast ());
+  hdr.SetAddr2 (address);
+  hdr.SetAddr3 (mpAddress);
+  hdr.SetDsNotFrom ();
+  hdr.SetDsNotTo ();
+  
+  return hdr;
+}
+
+} // namespace 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/mesh-wifi-beacon.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,71 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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: Pavel Boyko <boyko@iitp.ru>
+ */
+
+#ifndef MESHWIFIBEACON_H_
+#define MESHWIFIBEACON_H_
+
+#include "ns3/object.h"
+#include "ns3/packet.h"
+#include "ns3/wifi-information-element.h"
+#include "ns3/mgt-headers.h"        // from wifi module
+#include "ns3/wifi-mac-header.h"
+
+#include <vector>
+
+namespace ns3 {
+
+/**
+ * \brief Beacon is beacon header + list of arbitrary information elements
+ * 
+ * It is supposed that distinct mesh protocols can use beacons to transport
+ * their own information elements.
+ */
+class MeshWifiBeacon
+{
+public:
+  /** 
+   * C-tor
+   * 
+   * \param ssid is SSID for beacon header
+   * \param rates is a set of supported rates
+   * \param us beacon interval in microseconds
+   */
+  MeshWifiBeacon (Ssid ssid, SupportedRates rates, uint64_t us);
+  /// Read standard Wifi beacon header
+  MgtBeaconHeader BeaconHeader () const { return m_header; }
+  /// Add information element
+  void AddInformationElement (Ptr<WifiInformationElement> ie);
+  
+  /// Create wifi header for beacon frame. \param address is sender address \param mpAddress is mesh point address
+  WifiMacHeader CreateHeader (Mac48Address address, Mac48Address mpAddress);
+  /// Create frame = { beacon header + all information elements sorted by ElementId () }
+  Ptr<Packet> CreatePacket ();
+  
+private:
+  /// Beacon header
+  MgtBeaconHeader m_header;
+  /// List of information elements added 
+  std::vector< Ptr<WifiInformationElement> > m_elements;
+};
+
+}
+
+
+#endif /* MESHWIFIBEACON_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/mesh-wifi-interface-mac-plugin.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,71 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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: Pavel Boyko <boyko@iitp.ru>
+ */
+
+#ifndef MESHWIFIINTERFACEMACPLUGIN_H_
+#define MESHWIFIINTERFACEMACPLUGIN_H_
+
+#include "ns3/wifi-mac-header.h"
+#include "ns3/packet.h"
+#include "ns3/mac48-address.h"
+#include "ns3/mesh-wifi-beacon.h"
+#include "ns3/ref-count-base.h"
+
+namespace ns3 {
+
+class MeshWifiInterfaceMac;
+  
+/**
+ * \ingroup mesh
+ * 
+ * \brief Common interface for mesh point interface MAC plugins
+ * 
+ * TODO: plugins description
+ */
+class MeshWifiInterfaceMacPlugin : public RefCountBase
+{
+public:
+  /// This is for subclasses
+  virtual ~MeshWifiInterfaceMacPlugin (){};
+  /// Each plugin must be installed on interface to work 
+  virtual void SetParent (Ptr<MeshWifiInterfaceMac> parent) = 0; 
+  /** 
+   * \brief Process received frame
+   * 
+   * \return false if (and only if) frame should be dropped
+   * TODO define when MAC call this
+   */
+  virtual bool Receive (Ptr<Packet> packet, const WifiMacHeader & header) = 0;
+  /**
+   * \brief Update frame before it will be forwarded down
+   * 
+   * \return false if (and only if) frame should be dropped
+   * TODO define when MAC call this, preconditions & postconditions
+   */
+  virtual bool UpdateOutcomingFrame (Ptr<Packet> packet, WifiMacHeader & header, Mac48Address from, Mac48Address to) = 0;
+  /**
+   * \brief Update beacon before it will be formed and sent
+   *  
+   * TODO define when MAC call this
+   */
+  virtual void UpdateBeacon (MeshWifiBeacon & beacon) const = 0;
+};
+
+} // namespace ns3
+#endif /* MESHWIFIINTERFACEMACPLUGIN_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/mesh-wifi-interface-mac.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,668 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ *          Pavel Boyko <boyko@iitp.ru>
+ */
+
+#include "ns3/mesh-wifi-interface-mac.h"
+#include "ns3/mesh-wifi-beacon.h"
+#include "ns3/log.h"
+#include "ns3/wifi-phy.h"
+#include "ns3/dcf-manager.h"
+#include "ns3/mac-rx-middle.h"
+#include "ns3/mac-low.h"
+#include "ns3/dca-txop.h"
+#include "ns3/random-variable.h"
+#include "ns3/simulator.h"
+#include "ns3/yans-wifi-phy.h"
+
+NS_LOG_COMPONENT_DEFINE ("MeshWifiInterfaceMac");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (MeshWifiInterfaceMac);
+
+TypeId
+MeshWifiInterfaceMac::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::MeshWifiInterfaceMac")
+    .SetParent<WifiMac> ()
+    .AddConstructor<MeshWifiInterfaceMac> ()
+    .AddAttribute ("BeaconInterval", "Beacon Interval",
+        TimeValue (Seconds (1.0)),
+        MakeTimeAccessor (&MeshWifiInterfaceMac::m_beaconInterval),
+        MakeTimeChecker ()
+        )
+    .AddAttribute ("RandomStart", "Window when beacon generating starts (uniform random) in seconds",
+        TimeValue (Seconds (0.1)),
+        MakeTimeAccessor (&MeshWifiInterfaceMac::m_randomStart),
+        MakeTimeChecker ()
+        )
+    .AddAttribute ("BeaconGeneration", "Enable/Disable Beaconing.",
+        BooleanValue (true),
+        MakeBooleanAccessor (
+          &MeshWifiInterfaceMac::SetBeaconGeneration,
+          &MeshWifiInterfaceMac::GetBeaconGeneration
+          ),
+        MakeBooleanChecker ()
+        );
+  return tid;
+}
+
+MeshWifiInterfaceMac::MeshWifiInterfaceMac ()
+{
+  NS_LOG_FUNCTION (this);
+
+  m_rxMiddle = new MacRxMiddle ();
+  m_rxMiddle->SetForwardCallback (MakeCallback (&MeshWifiInterfaceMac::Receive, this));
+
+  m_low = CreateObject<MacLow> ();
+  m_low->SetRxCallback (MakeCallback (&MacRxMiddle::Receive, m_rxMiddle));
+
+  m_dcfManager = new DcfManager ();
+  m_dcfManager->SetupLowListener (m_low);
+
+  m_beaconDca = CreateObject<DcaTxop> ();
+  m_beaconDca->SetLow (m_low);
+  m_beaconDca->SetMinCw (0);
+  m_beaconDca->SetMaxCw (0);
+  m_beaconDca->SetAifsn (1);
+  m_beaconDca->SetManager (m_dcfManager);
+
+  m_VO = CreateObject<DcaTxop> ();
+  m_VO->SetLow (m_low);
+  m_VO->SetMinCw (3);
+  m_VO->SetMaxCw (7);
+  m_VO->SetManager (m_dcfManager);
+
+  m_BE = CreateObject<DcaTxop> ();
+  m_BE->SetLow (m_low);
+  m_BE->SetManager (m_dcfManager);
+}
+
+MeshWifiInterfaceMac::~MeshWifiInterfaceMac ()
+{
+  NS_LOG_FUNCTION (this);
+}
+
+//-----------------------------------------------------------------------------
+// WifiMac inherited
+//-----------------------------------------------------------------------------
+void
+MeshWifiInterfaceMac::SetSlot (Time slotTime)
+{
+  NS_LOG_FUNCTION (this << slotTime);
+  m_dcfManager->SetSlot (slotTime);
+  m_slot = slotTime;
+}
+
+void
+MeshWifiInterfaceMac::SetSifs (Time sifs)
+{
+  NS_LOG_FUNCTION (this << sifs);
+  m_dcfManager->SetSifs (sifs);
+  m_sifs = sifs;
+}
+void
+MeshWifiInterfaceMac::SetAckTimeout (Time ackTimeout)
+{
+  m_low->SetAckTimeout (ackTimeout);
+}
+
+void
+MeshWifiInterfaceMac::SetCtsTimeout (Time ctsTimeout)
+{
+  m_low->SetCtsTimeout (ctsTimeout);
+}
+
+void
+MeshWifiInterfaceMac::SetPifs (Time pifs)
+{
+  NS_LOG_FUNCTION (this << pifs);
+  m_pifs = pifs;
+}
+void
+MeshWifiInterfaceMac::SetEifsNoDifs (Time eifsNoDifs)
+{
+  NS_LOG_FUNCTION (this << eifsNoDifs);
+  m_dcfManager->SetEifsNoDifs (eifsNoDifs);
+  m_eifsNoDifs = eifsNoDifs;
+}
+
+Time
+MeshWifiInterfaceMac::GetSlot () const
+{
+  return m_slot;
+}
+
+Time
+MeshWifiInterfaceMac::GetSifs () const
+{
+  return m_sifs;
+}
+
+Time
+MeshWifiInterfaceMac::GetEifsNoDifs () const
+{
+  return m_eifsNoDifs;
+}
+
+Time
+MeshWifiInterfaceMac::GetAckTimeout () const
+{
+  return m_low->GetAckTimeout ();
+}
+
+Time
+MeshWifiInterfaceMac::GetCtsTimeout () const
+{
+  return m_low->GetCtsTimeout ();
+}
+
+Time
+MeshWifiInterfaceMac::GetPifs () const
+{
+  return m_low->GetPifs ();
+}
+
+void
+MeshWifiInterfaceMac::SetWifiPhy (Ptr<WifiPhy> phy)
+{
+  NS_LOG_FUNCTION (this << phy);
+  m_phy = phy;
+  m_dcfManager->SetupPhyListener (phy);
+  m_low->SetPhy (phy);
+
+  NS_LOG_DEBUG("SetWifiPhy: Can switch channel now: " << CanSwitchChannel() ); // TMP
+}
+
+void
+MeshWifiInterfaceMac::SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> stationManager)
+{
+  NS_LOG_FUNCTION (this << stationManager);
+  m_stationManager = stationManager;
+  m_BE->SetWifiRemoteStationManager (stationManager);
+  m_VO->SetWifiRemoteStationManager (stationManager);
+  m_beaconDca->SetWifiRemoteStationManager (stationManager);
+  m_low->SetWifiRemoteStationManager (stationManager);
+}
+
+void
+MeshWifiInterfaceMac::Enqueue (Ptr<const Packet> packet, Mac48Address to, Mac48Address from)
+{
+  NS_LOG_FUNCTION (this << packet << to << from);
+  ForwardDown (packet, from, to);
+}
+
+void
+MeshWifiInterfaceMac::Enqueue (Ptr<const Packet> packet, Mac48Address to)
+{
+  NS_LOG_FUNCTION (this << packet << to);
+  ForwardDown (packet, m_low->GetAddress (), to);
+}
+
+bool
+MeshWifiInterfaceMac::SupportsSendFrom () const
+{
+  return true;
+}
+
+void
+MeshWifiInterfaceMac::SetForwardUpCallback (Callback<void,Ptr<Packet>, Mac48Address, Mac48Address> upCallback)
+{
+  NS_LOG_FUNCTION (this);
+  m_upCallback = upCallback;
+}
+
+void
+MeshWifiInterfaceMac::SetLinkUpCallback (Callback<void> linkUp)
+{
+  NS_LOG_FUNCTION (this);
+  if (!linkUp.IsNull ())
+    {
+      linkUp ();
+    }
+}
+
+void
+MeshWifiInterfaceMac::SetLinkDownCallback (Callback<void> linkDown)
+{
+  NS_LOG_FUNCTION (this);
+}
+
+Mac48Address
+MeshWifiInterfaceMac::GetAddress () const
+{
+  return m_address;
+}
+Mac48Address
+MeshWifiInterfaceMac::GetBssid () const
+{
+  return m_address;
+}
+
+Ssid
+MeshWifiInterfaceMac::GetSsid () const
+{
+  return m_meshId;
+}
+
+void
+MeshWifiInterfaceMac::SetAddress (Mac48Address address)
+{
+  NS_LOG_FUNCTION (address);
+  m_low->SetAddress (address);
+  m_address = address;
+}
+
+void
+MeshWifiInterfaceMac::SetSsid (Ssid ssid)
+{
+  NS_LOG_FUNCTION (ssid);
+  m_meshId = ssid;
+}
+
+void
+MeshWifiInterfaceMac::DoDispose ()
+{
+  NS_LOG_FUNCTION (this);
+  delete m_rxMiddle;
+  delete m_dcfManager;
+  //Delete smart pointers:
+  m_rxMiddle = 0;
+  m_low = 0;
+  m_dcfManager = 0;
+  m_phy = 0;
+  m_BE = 0;
+  m_VO = 0;
+  m_beaconSendEvent.Cancel ();
+  m_beaconDca = 0;
+
+  WifiMac::DoDispose ();
+}
+
+//-----------------------------------------------------------------------------
+// Plugins
+//-----------------------------------------------------------------------------
+void
+MeshWifiInterfaceMac::InstallPlugin ( Ptr<MeshWifiInterfaceMacPlugin> plugin)
+{
+  NS_LOG_FUNCTION (this);
+
+  plugin->SetParent (this);
+  m_plugins.push_back (plugin);
+}
+
+//-----------------------------------------------------------------------------
+// Switch channels
+//-----------------------------------------------------------------------------
+bool MeshWifiInterfaceMac::CanSwitchChannel () const
+{
+  NS_LOG_FUNCTION (this);
+
+  // now only YansWifiPhy can switch channels runtime
+  if (m_phy != 0)
+    {
+      Ptr<YansWifiPhy> phy = m_phy->GetObject<YansWifiPhy> ();
+      return (phy != 0);
+    }
+  else
+    return false;
+}
+
+uint16_t MeshWifiInterfaceMac::GetFrequencyChannel () const
+{
+  NS_LOG_FUNCTION (this);
+  NS_ASSERT (m_phy != 0); // need PHY to set/get channel
+
+  Ptr<YansWifiPhy> phy = m_phy->GetObject<YansWifiPhy> ();
+  if (phy != 0)
+    return phy->GetFrequencyChannel ();
+  else
+    return 0;
+}
+
+void MeshWifiInterfaceMac::SwitchFrequencyChannel (uint16_t new_id)
+{
+  NS_LOG_FUNCTION (this);
+  NS_ASSERT (m_phy != 0); // need PHY to set/get channel
+  /* TODO
+   *
+   * Correct channel switching is:
+   *
+   * 1. Interface down, e.g. to stop packets from layer 3
+   * 2. Wait before all output queues will be empty
+   * 3. Switch PHY channel
+   * 4. Interface up
+   *
+   * Now we use dirty channel switch -- just change frequency
+   */
+  NS_ASSERT(CanSwitchChannel());
+
+  Ptr<YansWifiPhy> phy = m_phy->GetObject<YansWifiPhy> ();
+  phy->SetFrequencyChannel (new_id);
+  // Don't know NAV on new channel
+  m_dcfManager->NotifyNavResetNow (Seconds (0));
+}
+
+//-----------------------------------------------------------------------------
+// Forward frame up/down
+//-----------------------------------------------------------------------------
+void
+MeshWifiInterfaceMac::ForwardUp (Ptr<Packet> packet, Mac48Address src, Mac48Address dst)
+{
+  NS_LOG_FUNCTION (this << packet << src);
+  m_upCallback (packet, src, dst);
+}
+
+void
+MeshWifiInterfaceMac::ForwardDown (Ptr<const Packet> const_packet, Mac48Address from, Mac48Address to)
+{
+  // copy packet to allow modifications
+  Ptr<Packet> packet = const_packet->Copy ();
+  WifiMacHeader hdr;
+  hdr.SetTypeData ();
+  hdr.SetAddr2 (GetAddress ());
+  hdr.SetAddr3 (to);
+  hdr.SetAddr4 (from);
+  hdr.SetDsFrom ();
+  hdr.SetDsTo ();
+
+  // Address 1 is unknwon here. Routing plugin is responsible to correctly set it.
+  hdr.SetAddr1 (Mac48Address ());
+
+  // Filter packet through all installed plugins
+  for (PluginList::const_iterator i = m_plugins.end()-1; i != m_plugins.begin()-1; i--)
+    {
+      bool drop = ! ((*i)->UpdateOutcomingFrame(packet, hdr, from, to));
+      if (drop) return; // plugin drops frame
+    }
+
+  // Assert that address1 is set. Assert will fail e.g. if there is no installed routing plugin.
+  NS_ASSERT (hdr.GetAddr1() != Mac48Address() );
+
+  // Queue frame
+  WifiRemoteStation *destination = m_stationManager->Lookup (to);
+
+  if (destination->IsBrandNew ())
+    {
+      // in adhoc mode, we assume that every destination
+      // supports all the rates we support.
+      for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
+        {
+          destination->AddSupportedMode (m_phy->GetMode (i));
+        }
+      destination->RecordDisassociated ();
+    }
+  m_stats.sentFrames ++;
+  m_stats.sentBytes += packet->GetSize ();
+  m_BE->Queue (packet, hdr);
+}
+
+void
+MeshWifiInterfaceMac::SendManagementFrame (Ptr<Packet> packet, const WifiMacHeader& hdr)
+{
+  //Filter management frames:
+  WifiMacHeader header = hdr;
+  for (PluginList::const_iterator i = m_plugins.end()-1; i != m_plugins.begin()-1; i--)
+    {
+      bool drop = ! ((*i)->UpdateOutcomingFrame(packet, header, Mac48Address (), Mac48Address ()));
+      if (drop) return; // plugin drops frame
+    }
+  m_stats.sentFrames ++;
+  m_stats.sentBytes += packet->GetSize ();
+  m_VO->Queue (packet, header);
+}
+
+SupportedRates
+MeshWifiInterfaceMac::GetSupportedRates () const
+{
+  // set the set of supported rates and make sure that we indicate
+  // the Basic Rate set in this set of supported rates.
+  SupportedRates rates;
+  for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
+    {
+      WifiMode mode = m_phy->GetMode (i);
+      rates.AddSupportedRate (mode.GetDataRate ());
+    }
+  // set the basic rates
+  for (uint32_t j = 0; j < m_stationManager->GetNBasicModes (); j++)
+    {
+      WifiMode mode = m_stationManager->GetBasicMode (j);
+      rates.SetBasicRate (mode.GetDataRate ());
+    }
+  return rates;
+}
+bool
+MeshWifiInterfaceMac::CheckSupportedRates(SupportedRates rates) const
+{
+  for (uint32_t i = 0; i < m_stationManager->GetNBasicModes (); i++)
+  {
+    WifiMode mode = m_stationManager->GetBasicMode (i);
+    if (!rates.IsSupportedRate (mode.GetDataRate ()))
+      return false;
+  }
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+// Beacons
+//-----------------------------------------------------------------------------
+void 
+MeshWifiInterfaceMac::SetRandomStartDelay (Time interval)
+{
+  NS_LOG_FUNCTION (this << interval);
+  m_randomStart = interval;
+}
+
+void
+MeshWifiInterfaceMac::SetBeaconInterval (Time interval)
+{
+  NS_LOG_FUNCTION (this << interval);
+  m_beaconInterval = interval;
+}
+
+Time
+MeshWifiInterfaceMac::GetBeaconInterval () const
+{
+  return m_beaconInterval;
+}
+
+void
+MeshWifiInterfaceMac::SetBeaconGeneration (bool enable)
+{
+  NS_LOG_FUNCTION (this << enable);
+  if (enable)
+    {
+      // Now start sending beacons after some random delay (to avoid collisions)
+      UniformVariable coefficient (0.0, m_randomStart.GetSeconds());
+      Time randomStart = Seconds (coefficient.GetValue());
+
+      m_beaconSendEvent = Simulator::Schedule (randomStart, &MeshWifiInterfaceMac::SendBeacon, this);
+      m_tbtt = Simulator::Now() + randomStart;
+    }
+  else
+    // stop sending beacons
+    m_beaconSendEvent.Cancel ();
+}
+
+bool
+MeshWifiInterfaceMac::GetBeaconGeneration () const
+{
+  return m_beaconSendEvent.IsRunning ();
+}
+
+Time
+MeshWifiInterfaceMac::GetTbtt () const
+{
+  return m_tbtt;
+}
+
+void MeshWifiInterfaceMac::ShiftTbtt (Time shift)
+{
+  // User of ShiftTbtt () must take care don't shift it to the past
+  NS_ASSERT (GetTbtt() + shift > Simulator::Now());
+
+  m_tbtt += shift;
+  // Shift scheduled event
+  Simulator::Cancel (m_beaconSendEvent);
+  m_beaconSendEvent = Simulator::Schedule (GetTbtt () - Simulator::Now(), &MeshWifiInterfaceMac::SendBeacon, this);
+}
+
+void
+MeshWifiInterfaceMac::ScheduleNextBeacon ()
+{
+  m_tbtt += GetBeaconInterval ();
+  m_beaconSendEvent = Simulator::Schedule (GetBeaconInterval(), &MeshWifiInterfaceMac::SendBeacon, this);
+}
+
+void
+MeshWifiInterfaceMac::SendBeacon ()
+{
+  NS_LOG_FUNCTION (this);
+  NS_LOG_DEBUG (GetAddress() <<" is sending beacon");
+
+  NS_ASSERT (! m_beaconSendEvent.IsRunning());
+  NS_ASSERT (Simulator::Now().GetMicroSeconds() == GetTbtt().GetMicroSeconds());     // assert that beacon is just on time
+
+  // Form & send beacon
+  MeshWifiBeacon beacon (GetSsid (), GetSupportedRates (), m_beaconInterval.GetMicroSeconds ());
+
+  // Ask all plugins to add their specific information elements to beacon
+  for (PluginList::const_iterator i = m_plugins.begin(); i != m_plugins.end(); ++i)
+    (*i)->UpdateBeacon (beacon);
+
+  m_beaconDca->Queue (beacon.CreatePacket(), beacon.CreateHeader(GetAddress (), GetMeshPointAddress ()));
+
+  ScheduleNextBeacon ();
+}
+
+void
+MeshWifiInterfaceMac::Receive (Ptr<Packet> packet, WifiMacHeader const *hdr)
+{
+  // Process beacon
+  if((hdr->GetAddr1() != GetAddress()) && (hdr->GetAddr1() != Mac48Address::GetBroadcast()))
+    return;
+  if (hdr->IsBeacon ())
+    {
+      m_stats.recvBeacons ++;
+      MgtBeaconHeader beacon_hdr;
+      Mac48Address from = hdr->GetAddr2 ();
+
+      packet->PeekHeader (beacon_hdr);
+
+      NS_LOG_DEBUG ("Beacon received from "<<hdr->GetAddr2()<<
+                   " I am "<<GetAddress ()<<
+                   " at "<<Simulator::Now ().GetMicroSeconds ()<<
+                   " microseconds");
+
+      // update supported rates
+      if (beacon_hdr.GetSsid ().IsEqual(GetSsid()))
+        {
+          SupportedRates rates = beacon_hdr.GetSupportedRates ();
+          WifiRemoteStation * peerSta = m_stationManager->Lookup (hdr->GetAddr2 ());
+
+          for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
+          {
+            WifiMode mode = m_phy->GetMode (i);
+            if (rates.IsSupportedRate (mode.GetDataRate ()))
+              {
+                peerSta->AddSupportedMode (mode);
+                if (rates.IsBasicRate (mode.GetDataRate ()))
+                  m_stationManager->AddBasicMode (mode);
+              }
+          }
+        }
+    }
+  else
+  {
+    m_stats.recvBytes += packet->GetSize ();
+    m_stats.recvFrames ++;
+  }
+  // Filter frame through all installed plugins
+  for (PluginList::iterator i = m_plugins.begin (); i != m_plugins.end(); ++i)
+    {
+      bool drop = ! ((*i)->Receive(packet, *hdr));
+      if (drop) return; // plugin drops frame
+    }
+
+  // Forward data up
+  if (hdr->IsData ())
+      ForwardUp (packet, hdr->GetAddr4(), hdr->GetAddr3());
+}
+
+uint32_t
+MeshWifiInterfaceMac::GetLinkMetric (Mac48Address peerAddress)
+{
+  uint32_t metric = 1;
+  if(!m_linkMetricCallback.IsNull ())
+    metric = m_linkMetricCallback(peerAddress, this);
+  return metric;
+}
+
+void
+MeshWifiInterfaceMac::SetLinkMetricCallback (Callback<uint32_t, Mac48Address, Ptr<MeshWifiInterfaceMac> > cb)
+{
+  m_linkMetricCallback = cb;
+}
+
+Ptr<WifiRemoteStationManager>
+MeshWifiInterfaceMac::GetStationManager()
+{
+  return m_stationManager;
+}
+
+void
+MeshWifiInterfaceMac::SetMeshPointAddress (Mac48Address a)
+{
+  m_mpAddress = a;
+}
+
+Mac48Address 
+MeshWifiInterfaceMac::GetMeshPointAddress () const
+{
+  return m_mpAddress;
+}
+//Statistics:
+void
+MeshWifiInterfaceMac::Statistics::Print (std::ostream & os) const
+{
+  os << "<Statistics "
+    "recvBeacons=\"" << recvBeacons << "\" "
+    "sentFrames=\"" << sentFrames << "\" "
+    "sentBytes=\"" << (double)sentBytes / 1024.0 << "K\" "
+    "recvFrames=\"" << recvFrames << "\" "
+    "recvBytes=\"" << (double)recvBytes / 1024.0 << "K\"/>\n";
+}
+void
+MeshWifiInterfaceMac::Report (std::ostream & os) const
+{
+  os << "<Interface "
+    "BeaconInterval=\"" << GetBeaconInterval ().GetSeconds() << "s\" "
+    "Channel=\"" << GetFrequencyChannel () << "\" "
+    "Address = \"" << GetAddress () << "\">\n";
+  m_stats.Print (os);
+  os << "</Interface>\n";
+}
+void
+MeshWifiInterfaceMac::ResetStats ()
+{
+  m_stats = Statistics::Statistics ();
+}
+} // namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/mesh-wifi-interface-mac.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,257 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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
+ * 
+ * Authors: Kirill Andreev <andreev@iitp.ru>
+ *          Pavel Boyko <boyko@iitp.ru>
+ */
+
+#ifndef MESHWIFIINTERFACEMAC_H_
+#define MESHWIFIINTERFACEMAC_H_
+
+#include <stdint.h>
+#include <map>
+#include "ns3/mac48-address.h"
+#include "ns3/mgt-headers.h"
+#include "ns3/callback.h"
+#include "ns3/packet.h"
+#include "ns3/nstime.h"
+#include "ns3/wifi-remote-station-manager.h"
+#include "ns3/wifi-mac.h"
+#include "ns3/mesh-wifi-interface-mac-plugin.h"
+#include "ns3/event-id.h"
+
+namespace ns3 {
+
+class WifiMacHeader;
+class DcaTxop;
+class WifiPhy;
+class DcfManager;
+class MacRxMiddle;
+class MacLow;
+/**
+ * \ingroup mesh
+ *
+ * \brief Basic MAC of mesh point Wi-Fi interface. Its function is extendable through plugins mechanism.
+ * 
+ * Now only three output queues are used:
+ *  - beacons (PIFS and no backoff),
+ *  - background traffic,
+ *  - management and priority traffic.
+ *  
+ */
+class MeshWifiInterfaceMac : public WifiMac
+{
+public:
+  /// Never forget to support typeid
+  static TypeId  GetTypeId ();
+  /// C-tor
+  MeshWifiInterfaceMac ();
+  /// D-tor
+  virtual ~MeshWifiInterfaceMac ();
+  
+  ///\name Inherited from WifiMac
+  //\{
+  virtual void  SetSlot (Time slotTime);
+  virtual void  SetSifs (Time sifs);
+  virtual void  SetPifs (Time pifs);
+  virtual void  SetCtsTimeout (Time ctsTimeout);
+  virtual void  SetAckTimeout (Time ackTimeout);
+  virtual void  SetEifsNoDifs (Time eifsNoDifs);
+  virtual Time  GetSlot () const;
+  virtual Time  GetSifs () const;
+  virtual Time  GetPifs () const;
+  virtual Time  GetCtsTimeout () const;
+  virtual Time  GetAckTimeout () const;
+  virtual Time  GetEifsNoDifs () const;
+  virtual void  SetWifiPhy (Ptr<WifiPhy> phy);
+  virtual void  SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> stationManager);
+  virtual void  Enqueue (Ptr<const Packet> packet, Mac48Address to, Mac48Address from);
+  virtual void  Enqueue (Ptr<const Packet> packet, Mac48Address to);
+  virtual bool  SupportsSendFrom () const;
+  virtual void  SetForwardUpCallback (Callback<void,Ptr<Packet>, Mac48Address, Mac48Address> upCallback);
+  virtual void  SetLinkUpCallback (Callback<void> linkUp);
+  virtual void  SetLinkDownCallback (Callback<void> linkDown);
+  virtual Mac48Address GetAddress () const;
+  virtual Mac48Address GetBssid () const;
+  virtual Ssid  GetSsid () const;
+  virtual void  SetAddress (Mac48Address address);
+  virtual void  SetSsid (Ssid ssid);
+  //\}
+  
+  ///\name Each mesh point interfaces must know the mesh point address
+  //\{
+  void SetMeshPointAddress (Mac48Address);
+  Mac48Address GetMeshPointAddress () const;
+  //\}
+  ///\name Beacons
+  //\{
+  /// Set maximum initial random delay before first beacon
+  void SetRandomStartDelay (Time interval);
+  /// Set interval between two successive beacons
+  void SetBeaconInterval (Time interval);
+  /// \return interval between two beacons
+  Time GetBeaconInterval () const;
+  /** 
+   * \brief Next beacon frame time
+   * 
+   * This is supposed to be used by any entity managing beacon collision avoidance (e.g. Peer management protocol in 802.11s)
+   */ 
+  Time GetTbtt () const;
+  /**
+   * \brief Shift TBTT.
+   * 
+   * This is supposed to be used by any entity managing beacon collision avoidance (e.g. Peer management protocol in 802.11s)
+   * 
+   * \attention User of ShiftTbtt () must take care to not shift it to the past. 
+   */
+  void ShiftTbtt (Time shift);
+  //\}
+  
+  ///\name Plugins
+  //\{
+  /// Install plugin. TODO return unique ID to allow unregister plugins
+  void InstallPlugin (Ptr<MeshWifiInterfaceMacPlugin> plugin);
+  //\}
+  
+  /** \name Channel switching
+   * 
+   * Channel center frequency = Channel starting frequency + 5 * channel_id (MHz), 
+   * where Starting channel frequency is standard-dependent as defined in IEEE 802.11-2007 17.3.8.3.2.
+   * 
+   * Number of channels to use must be limited elsewhere. 
+   */
+  //\{
+  /// Return true if PHY layer can switch channels
+  bool CanSwitchChannel () const;
+  /// Current channel Id
+  uint16_t GetFrequencyChannel () const;
+  /// Switch channel
+  void SwitchFrequencyChannel (uint16_t new_id);
+  //\}
+  
+  /// To be used by plugins sending management frames.
+  void SendManagementFrame(Ptr<Packet> frame, const WifiMacHeader& hdr);
+  /// \return true if rates are supported
+  bool CheckSupportedRates(SupportedRates rates) const;
+  /// \return list of supported bitrates
+  SupportedRates GetSupportedRates () const;
+  ///\ name Metric Calculation routines:
+  ///\{
+  void SetLinkMetricCallback(Callback<uint32_t, Mac48Address, Ptr<MeshWifiInterfaceMac> > cb);
+  uint32_t GetLinkMetric(Mac48Address peerAddress);
+  Ptr<WifiRemoteStationManager> GetStationManager ();
+  ///\}
+  ///\brief Statistics:
+  void Report (std::ostream &) const;
+  void ResetStats ();
+private:
+  /// Frame receive handler
+  void  Receive (Ptr<Packet> packet, WifiMacHeader const *hdr);
+  /// Forward frame to mesh point
+  virtual void ForwardUp (Ptr<Packet> packet, Mac48Address src, Mac48Address dst);
+  /// Send frame. Frame is supposed to be tagged by routing information. TODO: clarify this point 
+  void  ForwardDown (Ptr<const Packet> packet, Mac48Address from, Mac48Address to);
+  /// Send beacon
+  void SendBeacon ();
+  /// Schedule next beacon
+  void ScheduleNextBeacon ();
+  /// Enable/disable beacons
+  void SetBeaconGeneration (bool enable);
+  /// Get current beaconing status
+  bool GetBeaconGeneration () const;
+  /// Real d-tor
+  virtual void DoDispose ();
+  
+private:
+  ///\name Wifi MAC internals
+  //\{
+  Ptr<DcaTxop>   m_BE;
+  Ptr<DcaTxop>   m_BK;
+  Ptr<DcaTxop>   m_VI;
+  Ptr<DcaTxop>   m_VO;
+  Ptr<DcaTxop>   m_beaconDca;
+  Ptr<WifiRemoteStationManager> m_stationManager;
+  Ptr<WifiPhy>   m_phy;
+  Callback<void, Ptr<Packet>, Mac48Address, Mac48Address>  m_upCallback;
+  //\}
+  
+  ///\name Wifi timing intervals
+  //\{
+  Time m_slot;
+  Time m_sifs;
+  Time m_pifs;
+  Time m_ackTimeout;
+  Time m_ctsTimeout;
+  Time m_eifsNoDifs;
+  //\}
+  
+  ///\name Mesh timing intervals 
+  //\{
+  /// Beaconing interval.
+  Time m_beaconInterval;
+  /// Maximum delay before first beacon
+  Time m_randomStart;
+  /// Time for the next frame
+  Time m_tbtt;
+  //\}
+  
+  /// DCF implementation
+  DcfManager* m_dcfManager;
+  /// Middle MAC sublayer
+  MacRxMiddle* m_rxMiddle;
+  /// Low MAC sublayer
+  Ptr<MacLow> m_low;
+  /// My address
+  Mac48Address m_address;
+  /// Mesh point address
+  Mac48Address m_mpAddress;
+  /// SSID
+  Ssid m_meshId;
+  
+  /// "Timer" for the next beacon 
+  EventId m_beaconSendEvent;
+  
+  typedef std::vector< Ptr<MeshWifiInterfaceMacPlugin> > PluginList; 
+  /// List of all installed plugins
+  PluginList m_plugins;
+  Callback<uint32_t, Mac48Address, Ptr<MeshWifiInterfaceMac> > m_linkMetricCallback;
+  ///\name Statistics:
+  ///\{
+  struct Statistics
+  {
+    uint16_t recvBeacons;
+    uint32_t sentFrames;
+    uint32_t sentBytes;
+    uint32_t recvFrames;
+    uint32_t recvBytes;
+    void Print (std::ostream & os) const;
+    Statistics () :
+      recvBeacons (0),
+      sentFrames (0),
+      sentBytes (0),
+      recvFrames (0),
+      recvBytes (0)
+      {}
+  };
+  Statistics m_stats;
+  ///\}
+
+};
+
+} // namespace ns3
+
+#endif /* MESHWIFIINTERFACEMAC_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/mesh.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,30 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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: Pavel Boyko <boyko@iitp.ru>
+ *
+ * This is toplevel mesh module description
+ */
+
+/**
+ * \ingroup devices
+ * \defgroup mesh Mesh
+ *
+ * \brief Layer 2 mobile ad hoc wireless (aka mesh) networking
+ *
+ * see http://www.nsnam.org/wiki/index.php/Mesh for module architectural description.
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/waf	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/wifi-information-element.cc	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,99 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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: Pavel Boyko <boyko@iitp.ru>
+ */
+
+#include "ns3/wifi-information-element.h"
+#include "ns3/packet.h"
+#include "ns3/log.h"
+
+namespace ns3 {
+
+TypeId
+WifiInformationElement::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::WifiInformationElement")
+                      .SetParent<Header> ();
+  return tid;
+}
+
+TypeId
+WifiInformationElement::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+uint32_t WifiInformationElement::GetSerializedSize () const
+{
+  return (GetInformationSize () + 2);
+}
+
+void WifiInformationElement::Serialize (Buffer::Iterator i) const
+{
+  i.WriteU8 (ElementId ());
+  i.WriteU8 (GetInformationSize ());
+  SerializeInformation (i);
+}
+
+uint32_t WifiInformationElement::Deserialize (Buffer::Iterator i)
+{
+  if(i.ReadU8 () != ElementId())
+    return 0;
+  uint8_t length = i.ReadU8 ();
+  
+  return (DeserializeInformation (i, length) + 2);
+}
+
+void WifiInformationElement::Print (std::ostream &os) const
+{
+  os << "\n<information_element id=" << ElementId () << ">\n";
+  PrintInformation (os);
+  os << "</information_element>\n";
+}
+
+bool WifiInformationElement::FindFirst(Ptr<Packet> packet)
+{
+  const uint8_t * data = packet->PeekData();
+  uint32_t position = 0;
+  while(position < packet->GetSize ())
+  {
+    if(data[position] == ElementId())
+    {
+      Ptr<Packet> myIe = packet->CreateFragment(position, data[position+1]+2);
+      NS_ASSERT(myIe->GetSize() == (uint32_t)(data[position+1]+2));
+      myIe->RemoveHeader(*this);
+      return true;
+    }
+    else
+    {
+      if(data[position] > ElementId())
+        return false;
+      position +=data[position+1]+2;
+    }
+  }
+  return false;
+}
+
+bool operator< (WifiInformationElement const & a, WifiInformationElement const & b)
+{
+  return (a.ElementId () < b.ElementId());
+}
+
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/wifi-information-element.h	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,201 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/* 
+ * Copyright (c) 2009 IITP RAS
+ * 
+ * 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: Pavel Boyko <boyko@iitp.ru>
+ */
+
+#ifndef WIFIINFORMATIONELEMENT_H_
+#define WIFIINFORMATIONELEMENT_H_
+
+#include "ns3/header.h"
+#include "ns3/ref-count-base.h"
+#include "ns3/test.h"
+#include "ns3/packet.h"
+
+namespace ns3 {
+class Packet;
+/**
+ * \ingroup mesh
+ * 
+ * \brief Enum of all known information element id (aka tags). 
+ * 
+ * For now only 802.11s (mesh) related elements are supported here (so 11S prefix), 
+ * but this can change in future.
+ * 
+ * Note that 802.11s element ids are not yet officially assigned, we use ones 
+ * compatible with open80211s (http://o11s.org/) implementation.   
+ */
+enum WifiElementId {
+  /* begin of open80211s-compatible IDs */
+  IE11S_MESH_CONFIGURATION              = 51,
+  IE11S_MESH_ID                         = 52,
+  /* end of open80211s-compatible IDs */
+  IE11S_LINK_METRIC_REPORT              = 20,
+  IE11S_CONGESTION_NOTIFICATION,
+  /* begin of open80211s-compatible IDs */
+  IE11S_PEERING_MANAGEMENT              = 55,
+  /* end of open80211s-compatible IDs */
+  IE11S_SUPP_MBSS_REG_CLASSES_CHANNELS  = 23,
+  IE11S_MESH_CHANNEL_SWITCH_ANNOUNCEMENT,
+  IE11S_MESH_TIM,
+  IE11S_AWAKE_WINDOW,
+  IE11S_BEACON_TIMING,
+  IE11S_MCCAOP_SETUP_REQUEST,
+  IE11S_MCCAOP_SETUP_REPLY,
+  IE11S_MCCAOP_ADVERTISEMENT,
+  IE11S_MCCAOP_RESERVATION_TEARDOWN,
+  IE11S_PORTAL_ANNOUNCEMENT,
+  IE11S_RANN                            = 67,
+  /* begin of open80211s-compatible IDs */
+  IE11S_PREQ                            = 68,
+  IE11S_PREP                            = 69,
+  IE11S_PERR                            = 70, 
+  /* end of open80211s-compatible IDs */
+  IE11S_PROXY_UPDATE                    = 37,
+  IE11S_PROXY_UPDATE_CONFIRMATION,
+  IE11S_ABBREVIATED_HANDSHAKE,
+  IE11S_MESH_PEERING_PROTOCOL_VERSION   = 74,
+};  
+  
+/**
+ * \ingroup mesh
+ * 
+ * \brief Information element, as defined in 802.11-2007 standard
+ * 
+ * Elements are defined to have a common general format consisting of a 1 octet Element ID field, a 1 octet
+ * length field, and a variable-length element-specific information field. Each element is assigned a unique
+ * Element ID as defined in this standard. The Length field specifies the number of octets in the Information
+ * field. 
+ */
+class WifiInformationElement : public Header, 
+                               public RefCountBase     // need this to use Ptr<WifiInformationElement> 
+{
+public:
+  /// Support object system
+  static TypeId GetTypeId ();
+  TypeId GetInstanceTypeId () const;
+  
+  /// virtual d-tor for subclasses
+  virtual ~WifiInformationElement () {}
+  
+  ///\name Inherited from Header
+  //\{
+  /**
+   * \return the expected size of the header.
+   *
+   * This method is used by Packet::AddHeader
+   * to store a header into the byte buffer of a packet. This method
+   * should return the number of bytes which are needed to store
+   * the full header data by Serialize.
+   */
+  virtual uint32_t GetSerializedSize () const;
+  /**
+   * \param start an iterator which points to where the header should
+   *        be written.
+   *
+   * This method is used by Packet::AddHeader to
+   * store a header into the byte buffer of a packet.
+   * The data written
+   * is expected to match bit-for-bit the representation of this
+   * header in a real network.
+   */
+  virtual void Serialize (Buffer::Iterator start) const;
+  /**
+   * \param start an iterator which points to where the header should
+   *        written.
+   * \return the number of bytes read.
+   *
+   * This method is used by Packet::RemoveHeader to
+   * re-create a header from the byte buffer of a packet. 
+   * The data read is expected to
+   * match bit-for-bit the representation of this header in real
+   * networks.
+   */
+  virtual uint32_t Deserialize (Buffer::Iterator start);
+  /**
+   * This method is used by Packet::Print to print the 
+   * content of a trailer as ascii data to a c++ output stream.
+   * Although the trailer is free to format its output as it
+   * wishes, it is recommended to follow a few rules to integrate
+   * with the packet pretty printer: start with flags, small field 
+   * values located between a pair of parens. Values should be separated 
+   * by whitespace. Follow the parens with the important fields, 
+   * separated by whitespace.
+   * i.e.: (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
+   */
+  virtual void Print (std::ostream &os) const;
+  /**
+   * This method takes a packet which must be a list of information
+   * elements and looks for an information element of MINE Element ID
+   */
+  bool FindFirst(Ptr<Packet> packet);
+  //\}
+    
+protected:
+  ///\name Each subclass must implement 
+  //\{
+  /// Own unique Element ID
+  virtual WifiElementId ElementId () const = 0;
+  /// Length of serialized information
+  virtual uint8_t GetInformationSize () const = 0;
+  /// Serialize information
+  virtual void SerializeInformation (Buffer::Iterator start) const = 0;
+  /// Deserialize information
+  virtual uint8_t DeserializeInformation (Buffer::Iterator start, uint8_t length) = 0;
+  /// Print information
+  virtual void PrintInformation (std::ostream &os) const = 0;
+  //\}
+  
+  /// Compare information elements using Element ID
+  friend bool operator< (WifiInformationElement const & a, WifiInformationElement const & b);
+};
+
+/// Compare information elements using Element ID
+bool operator< (WifiInformationElement const & a, WifiInformationElement const & b);
+
+#ifdef RUN_SELF_TESTS
+/// Generic test of information element
+class IeTest : public Test
+{
+public:
+  IeTest (const char * name) : Test (name) {}
+  /// Test roundtrip serialization
+  template <typename IE> bool TestRoundtripSerialization (IE a);
+};
+
+template <typename IE> bool
+IeTest::TestRoundtripSerialization (IE a)
+{
+  bool result (true);
+  
+  Ptr<Packet> packet = Create<Packet> ();
+  packet->AddHeader (a);
+  IE b;
+  packet->RemoveHeader (b);
+  NS_TEST_ASSERT_EQUAL (a, b);
+  packet->AddHeader (a);
+  IE c;
+  bool ok = c.FindFirst(packet);
+  NS_TEST_ASSERT (ok);
+  NS_TEST_ASSERT_EQUAL (a, c);
+  
+  return result;
+}
+#endif 
+
+}  // namespace ns3
+#endif /* WIFIINFORMATIONELEMENT_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/mesh/wscript	Fri May 29 10:15:19 2009 +0400
@@ -0,0 +1,21 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    obj = bld.create_ns3_module('mesh', ['wifi', 'dot11s'])
+    obj.source = [
+        'wifi-information-element.cc',
+        'mesh-point-device.cc',
+        'mesh-l2-routing-protocol.cc',
+        'mesh-wifi-beacon.cc',
+        'mesh-wifi-interface-mac.cc',
+        ]
+    headers = bld.new_task_gen('ns3header')
+    headers.module = 'mesh'
+    headers.source = [
+        'wifi-information-element.h',
+        'mesh-point-device.h',
+        'mesh-l2-routing-protocol.h',
+        'mesh-wifi-beacon.h',
+        'mesh-wifi-interface-mac.h',
+        'mesh-wifi-interface-mac-plugin.h',
+        ]
--- a/src/devices/wifi/dca-txop.h	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/dca-txop.h	Fri May 29 10:15:19 2009 +0400
@@ -164,6 +164,7 @@
   bool m_accessOngoing;
   Ptr<const Packet> m_currentPacket;
   WifiMacHeader m_currentHdr;
+  uint8_t m_currentRetry;
   uint8_t m_fragmentNumber;
 };
 
--- a/src/devices/wifi/dcf-manager.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/dcf-manager.cc	Fri May 29 10:15:19 2009 +0400
@@ -160,17 +160,29 @@
  *         Listener for Nav events. Forwards to DcfManager
  ***************************************************************/
 
-class LowNavListener : public ns3::MacLowNavListener {
+class LowDcfListener : public ns3::MacLowDcfListener {
 public:
-  LowNavListener (ns3::DcfManager *dcf)
+  LowDcfListener (ns3::DcfManager *dcf)
     : m_dcf (dcf) {}
-  virtual ~LowNavListener () {}
+  virtual ~LowDcfListener () {}
   virtual void NavStart (Time duration) {
     m_dcf->NotifyNavStartNow (duration);
   }
   virtual void NavReset (Time duration) {
     m_dcf->NotifyNavResetNow (duration);
   }
+  virtual void AckTimeoutStart (Time duration) {
+    m_dcf->NotifyAckTimeoutStartNow (duration);
+  }
+  virtual void AckTimeoutReset () {
+    m_dcf->NotifyAckTimeoutResetNow ();
+  }
+  virtual void CtsTimeoutStart (Time duration) {
+    m_dcf->NotifyCtsTimeoutStartNow (duration);
+  }
+  virtual void CtsTimeoutReset () {
+    m_dcf->NotifyCtsTimeoutResetNow ();
+  }
 private:
   ns3::DcfManager *m_dcf;
 };
@@ -208,7 +220,9 @@
  ****************************************************************/
 
 DcfManager::DcfManager ()
-  : m_lastNavStart (MicroSeconds (0)),
+  : m_lastAckTimeoutEnd (MicroSeconds (0)),
+    m_lastCtsTimeoutEnd (MicroSeconds (0)),
+    m_lastNavStart (MicroSeconds (0)),
     m_lastNavDuration (MicroSeconds (0)),
     m_lastRxStart (MicroSeconds (0)),
     m_lastRxDuration (MicroSeconds (0)),
@@ -242,8 +256,8 @@
 void 
 DcfManager::SetupLowListener (Ptr<MacLow> low)
 {
-  m_lowListener = new LowNavListener (this);
-  low->RegisterNavListener (m_lowListener);
+  m_lowListener = new LowDcfListener (this);
+  low->RegisterDcfListener (m_lowListener);
 }
 
 void 
@@ -294,6 +308,16 @@
   Time retval = Max (e, f);
   return retval;
 }
+Time
+DcfManager::MostRecent (Time a, Time b, Time c, Time d, Time e, Time f) const
+{
+  Time g = Max (a, b);
+  Time h = Max (c, d);
+  Time i = Max (e, f);
+  Time k = Max (g, h);
+  Time retval = Max (k, i);
+  return retval;
+}
 
 bool 
 DcfManager::IsBusy (void) const
@@ -351,7 +375,7 @@
     {
       DcfState *state = *i;
       if (state->IsAccessRequested () && 
-          GetBackoffEndFor (state) <= Simulator::Now ())
+          GetBackoffEndFor (state).GetTimeStep() <= Simulator::Now ().GetTimeStep ())
         {
           /**
            * This is the first dcf we find with an expired backoff and which
@@ -431,7 +455,10 @@
   Time accessGrantedStart = MostRecent (rxAccessStart, 
                                         busyAccessStart,
                                         txAccessStart, 
-                                        navAccessStart);
+                                        navAccessStart,
+                                        m_lastAckTimeoutEnd,
+                                        m_lastCtsTimeoutEnd
+                                        );
   NS_LOG_INFO ("access grant start=" << accessGrantedStart <<
                ", rx access start=" << rxAccessStart <<
                ", busy access start=" << busyAccessStart <<
@@ -491,8 +518,9 @@
       if (state->IsAccessRequested ())
         {
           Time tmp = GetBackoffEndFor (state);
-          if (tmp > Simulator::Now ())
+          if (tmp.GetTimeStep () > Simulator::Now ().GetTimeStep ())
             {
+              //NS_LOG_UNCOND("Now:"<<Simulator::Now ().GetTimeStep ());
               accessTimeoutNeeded = true;
               expectedBackoffEnd = std::min (expectedBackoffEnd, tmp);
             }
@@ -586,5 +614,26 @@
       m_lastNavDuration = duration;
     }
 }
-
+void
+DcfManager::NotifyAckTimeoutStartNow (Time duration)
+{
+  m_lastAckTimeoutEnd = Simulator::Now () + duration;
+}
+void
+DcfManager::NotifyAckTimeoutResetNow ()
+{
+  m_lastAckTimeoutEnd = Simulator::Now ();
+  DoRestartAccessTimeoutIfNeeded ();
+}
+void
+DcfManager::NotifyCtsTimeoutStartNow (Time duration)
+{
+  m_lastCtsTimeoutEnd = Simulator::Now () + duration;
+}
+void
+DcfManager::NotifyCtsTimeoutResetNow ()
+{
+  m_lastCtsTimeoutEnd = Simulator::Now ();
+  DoRestartAccessTimeoutIfNeeded ();
+}
 } // namespace ns3
--- a/src/devices/wifi/dcf-manager.h	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/dcf-manager.h	Fri May 29 10:15:19 2009 +0400
@@ -238,12 +238,17 @@
    * Called at end of rx
    */
   void NotifyNavStartNow (Time duration);
-
+  void NotifyAckTimeoutStartNow (Time duration);
+  void NotifyAckTimeoutResetNow ();
+  void NotifyCtsTimeoutStartNow (Time duration);
+  void NotifyCtsTimeoutResetNow ();
+  void NotifyAckTimeoutEnd (Time duration);
 private:
   void UpdateBackoff (void);
   Time MostRecent (Time a, Time b) const;
   Time MostRecent (Time a, Time b, Time c) const;
   Time MostRecent (Time a, Time b, Time c, Time d) const;
+  Time MostRecent (Time a, Time b, Time c, Time d, Time e, Time f) const;
   /**
    * Access will never be granted to the medium _before_
    * the time returned by this method.
@@ -262,6 +267,8 @@
   typedef std::vector<DcfState *> States;
 
   States m_states;
+  Time m_lastAckTimeoutEnd;
+  Time m_lastCtsTimeoutEnd;
   Time m_lastNavStart;
   Time m_lastNavDuration;
   Time m_lastRxStart;
@@ -279,7 +286,7 @@
   Time m_slotTime;
   Time m_sifs;
   class PhyListener *m_phyListener;
-  class LowNavListener *m_lowListener;
+  class LowDcfListener *m_lowListener;
 };
 
 } // namespace ns3
--- a/src/devices/wifi/mac-low.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/mac-low.cc	Fri May 29 10:15:19 2009 +0400
@@ -110,9 +110,9 @@
 {}
 MacLowTransmissionListener::~MacLowTransmissionListener ()
 {}
-MacLowNavListener::MacLowNavListener ()
+MacLowDcfListener::MacLowDcfListener ()
 {}
-MacLowNavListener::~MacLowNavListener ()
+MacLowDcfListener::~MacLowDcfListener ()
 {}
 
 MacLowTransmissionParameters::MacLowTransmissionParameters ()
@@ -271,6 +271,7 @@
 MacLow::DoDispose (void)
 {
   NS_LOG_FUNCTION (this);
+  m_listener = 0;
   CancelAllEvents ();
   m_phy = 0;
   m_stationManager = 0;
@@ -423,9 +424,9 @@
   m_rxCallback = callback;
 }
 void 
-MacLow::RegisterNavListener (MacLowNavListener *listener)
+MacLow::RegisterDcfListener (MacLowDcfListener *listener)
 {
-  m_navListeners.push_back (listener);
+  m_dcfListeners.push_back (listener);
 }
 
 
@@ -537,12 +538,13 @@
     {
       NS_LOG_DEBUG ("receive cts from="<<m_currentHdr.GetAddr1 ());
       SnrTag tag;
-      packet->FindFirstMatchingTag (tag);
+      packet->RemovePacketTag (tag);
       WifiRemoteStation *station = GetStation (m_currentHdr.GetAddr1 ());
       station->ReportRxOk (rxSnr, txMode);
       station->ReportRtsOk (rxSnr, txMode, tag.Get ());
       
       m_ctsTimeoutEvent.Cancel ();
+      NotifyCtsTimeoutResetNow ();
       m_listener->GotCts (rxSnr, txMode);
       NS_ASSERT (m_sendDataEvent.IsExpired ());
       m_sendDataEvent = Simulator::Schedule (GetSifs (), 
@@ -560,7 +562,7 @@
     {
       NS_LOG_DEBUG ("receive ack from="<<m_currentHdr.GetAddr1 ());
       SnrTag tag;
-      packet->FindFirstMatchingTag (tag);
+      packet->RemovePacketTag (tag);
       WifiRemoteStation *station = GetStation (m_currentHdr.GetAddr1 ());
       station->ReportRxOk (rxSnr, txMode);
       station->ReportDataOk (rxSnr, txMode, tag.Get ());
@@ -569,12 +571,14 @@
           m_normalAckTimeoutEvent.IsRunning ()) 
         {
           m_normalAckTimeoutEvent.Cancel ();
+          NotifyAckTimeoutResetNow ();
           gotAck = true;
         }
       if (m_txParams.MustWaitFastAck () &&
           m_fastAckTimeoutEvent.IsRunning ()) 
         {
           m_fastAckTimeoutEvent.Cancel ();
+          NotifyAckTimeoutResetNow ();
           gotAck = true;
         }
       if (gotAck) 
@@ -796,7 +800,7 @@
 void
 MacLow::DoNavResetNow (Time duration)
 {
-  for (NavListenersCI i = m_navListeners.begin (); i != m_navListeners.end (); i++) 
+  for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++) 
     {
       (*i)->NavReset (duration);
     }
@@ -806,7 +810,7 @@
 bool
 MacLow::DoNavStartNow (Time duration)
 {
-  for (NavListenersCI i = m_navListeners.begin (); i != m_navListeners.end (); i++) 
+  for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++) 
     {
       (*i)->NavStart (duration);
     }
@@ -820,6 +824,38 @@
     }
   return false;
 }
+void
+MacLow::NotifyAckTimeoutStartNow (Time duration)
+{
+  for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++) 
+    {
+      (*i)->AckTimeoutStart (duration);
+    }
+}
+void
+MacLow::NotifyAckTimeoutResetNow ()
+{
+  for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++) 
+    {
+      (*i)->AckTimeoutReset ();
+    }
+}
+void
+MacLow::NotifyCtsTimeoutStartNow (Time duration)
+{
+  for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++) 
+    {
+      (*i)->CtsTimeoutStart (duration);
+    }
+}
+void
+MacLow::NotifyCtsTimeoutResetNow ()
+{
+  for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++) 
+    {
+      (*i)->CtsTimeoutReset ();
+    }
+}
 
 void
 MacLow::ForwardDown (Ptr<const Packet> packet, WifiMacHeader const* hdr, 
@@ -945,6 +981,7 @@
   Time timerDelay = txDuration + GetCtsTimeout ();
 
   NS_ASSERT (m_ctsTimeoutEvent.IsExpired ());
+  NotifyCtsTimeoutStartNow (timerDelay);
   m_ctsTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::CtsTimeout, this);
 
   Ptr<Packet> packet = Create<Packet> ();
@@ -964,18 +1001,21 @@
     {
       Time timerDelay = txDuration + GetAckTimeout ();
       NS_ASSERT (m_normalAckTimeoutEvent.IsExpired ());
+      NotifyAckTimeoutStartNow (timerDelay);
       m_normalAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::NormalAckTimeout, this);
     } 
   else if (m_txParams.MustWaitFastAck ()) 
     {
       Time timerDelay = txDuration + GetPifs ();
       NS_ASSERT (m_fastAckTimeoutEvent.IsExpired ());
+      NotifyAckTimeoutStartNow (timerDelay);
       m_fastAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::FastAckTimeout, this);
     } 
   else if (m_txParams.MustWaitSuperFastAck ()) 
     {
       Time timerDelay = txDuration + GetPifs ();
       NS_ASSERT (m_superFastAckTimeoutEvent.IsExpired ());
+      NotifyAckTimeoutStartNow (timerDelay);
       m_superFastAckTimeoutEvent = Simulator::Schedule (timerDelay, 
                                                         &MacLow::SuperFastAckTimeout, this);
     } 
@@ -1080,7 +1120,7 @@
 
   struct SnrTag tag;
   tag.Set (rtsSnr);
-  packet->AddTag (tag);
+  packet->AddPacketTag (tag);
 
   ForwardDown (packet, &cts, ctsTxMode);
 }
@@ -1159,7 +1199,7 @@
 
   struct SnrTag tag;
   tag.Set (dataSnr);
-  packet->AddTag (tag);
+  packet->AddPacketTag (tag);
 
   ForwardDown (packet, &ack, ackTxMode);
 }
--- a/src/devices/wifi/mac-low.h	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/mac-low.h	Fri May 29 10:15:19 2009 +0400
@@ -100,10 +100,10 @@
  * and calls to its methods are forwards to the corresponding
  * ns3::Dcf methods.
  */
-class MacLowNavListener {
+class MacLowDcfListener {
 public:
-  MacLowNavListener ();
-  virtual ~MacLowNavListener ();
+  MacLowDcfListener ();
+  virtual ~MacLowDcfListener ();
   /**
    * \param duration duration of NAV timer
    */
@@ -112,6 +112,10 @@
    * \param duration duration of NAV timer
    */
   virtual void NavReset (Time duration) = 0;
+  virtual void AckTimeoutStart (Time duration) = 0;
+  virtual void AckTimeoutReset () = 0;
+  virtual void CtsTimeoutStart (Time duration) = 0;
+  virtual void CtsTimeoutReset () = 0;
 };
 
 /**
@@ -306,7 +310,7 @@
    * \param listener listen to NAV events for every incoming
    *        and outgoing packet.
    */
-  void RegisterNavListener (MacLowNavListener *listener);
+  void RegisterDcfListener (MacLowDcfListener *listener);
 
   /**
    * \param packet to send (does not include the 802.11 MAC header and checksum)
@@ -375,6 +379,10 @@
   void DoNavResetNow (Time duration);
   bool DoNavStartNow (Time duration);
   bool IsNavZero (void) const;
+  void NotifyAckTimeoutStartNow (Time duration);
+  void NotifyAckTimeoutResetNow ();
+  void NotifyCtsTimeoutStartNow (Time duration);
+  void NotifyCtsTimeoutResetNow ();
   void MaybeCancelPrevious (void);
   
   void NavCounterResetCtsMissed (Time rtsEndRxTime);
@@ -397,9 +405,9 @@
   Ptr<WifiPhy> m_phy;
   Ptr<WifiRemoteStationManager> m_stationManager;
   MacLowRxCallback m_rxCallback;
-  typedef std::vector<MacLowNavListener *>::const_iterator NavListenersCI;
-  typedef std::vector<MacLowNavListener *> NavListeners;
-  NavListeners m_navListeners;
+  typedef std::vector<MacLowDcfListener *>::const_iterator DcfListenersCI;
+  typedef std::vector<MacLowDcfListener *> DcfListeners;
+  DcfListeners m_dcfListeners;
 
   EventId m_normalAckTimeoutEvent;
   EventId m_fastAckTimeoutEvent;
--- a/src/devices/wifi/mgt-headers.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/mgt-headers.cc	Fri May 29 10:15:19 2009 +0400
@@ -109,6 +109,11 @@
 MgtProbeResponseHeader::~MgtProbeResponseHeader ()
 {}
 
+uint64_t
+MgtProbeResponseHeader::GetTimestamp()
+{
+	return m_timestamp;
+}
 Ssid 
 MgtProbeResponseHeader::GetSsid (void) const
 {
@@ -198,7 +203,7 @@
 MgtProbeResponseHeader::Deserialize (Buffer::Iterator start)
 {
   Buffer::Iterator i = start;
-  i.Next (8); // timestamp
+  m_timestamp = i.ReadNtohU64();
   m_beaconInterval = i.ReadNtohU16 ();
   m_beaconInterval *= 1024;
   i = m_capability.Deserialize (i);
--- a/src/devices/wifi/mgt-headers.h	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/mgt-headers.h	Fri May 29 10:15:19 2009 +0400
@@ -21,6 +21,7 @@
 #define MGT_HEADERS_H
 
 #include <stdint.h>
+//#include <vector>
 
 #include "ns3/header.h"
 #include "status-code.h"
@@ -117,6 +118,8 @@
   void SetBeaconIntervalUs (uint64_t us);
   void SetSupportedRates (SupportedRates rates);
 
+  uint64_t GetTimestamp();
+
   static TypeId GetTypeId (void);
   virtual TypeId GetInstanceTypeId (void) const;
   virtual void Print (std::ostream &os) const;
@@ -125,6 +128,7 @@
   virtual uint32_t Deserialize (Buffer::Iterator start);
 
 private:
+  uint64_t m_timestamp;
   Ssid m_ssid;
   uint64_t m_beaconInterval;
   SupportedRates m_rates;
--- a/src/devices/wifi/qos-utils.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/qos-utils.cc	Fri May 29 10:15:19 2009 +0400
@@ -59,7 +59,7 @@
 {
   QosTag qos;
   uint8_t tid = 8;
-  if (packet->FindFirstMatchingTag (qos))
+  if (packet->PeekPacketTag (qos))
     {
       if (qos.Get () < 8)
         {
--- a/src/devices/wifi/wifi-mac-header.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/wifi-mac-header.cc	Fri May 29 10:15:19 2009 +0400
@@ -128,6 +128,21 @@
   m_ctrlType = TYPE_DATA;
   m_ctrlSubtype = 0;
 }
+
+void
+WifiMacHeader::SetAction (void)
+{
+ m_ctrlType = TYPE_MGT;
+ m_ctrlSubtype = 0x0D;
+}
+
+void
+WifiMacHeader::SetMultihopAction (void)
+{
+ m_ctrlType = TYPE_MGT;
+ m_ctrlSubtype = 0x0F;
+}
+
 void 
 WifiMacHeader::SetType (enum WifiMacType type)
 {
@@ -191,6 +206,15 @@
   case WIFI_MAC_MGT_DEAUTHENTICATION:
     m_ctrlType = TYPE_MGT;
     m_ctrlSubtype = 12;
+  case WIFI_MAC_MGT_ACTION:
+    m_ctrlType = TYPE_MGT;
+    m_ctrlSubtype = 13;
+  case WIFI_MAC_MGT_ACTION_NO_ACK:
+    m_ctrlType = TYPE_MGT;
+    m_ctrlSubtype = 14;
+  case WIFI_MAC_MGT_MULTIHOP_ACTION:
+    m_ctrlType = TYPE_MGT;
+    m_ctrlSubtype = 15;
     break;
 
   case WIFI_MAC_DATA:
@@ -397,6 +421,15 @@
     case 12:
       return WIFI_MAC_MGT_DEAUTHENTICATION;
       break;
+    case 13:
+      return WIFI_MAC_MGT_ACTION;
+      break;
+    case 14:
+      return WIFI_MAC_MGT_ACTION_NO_ACK;
+      break;
+    case 15:
+      return WIFI_MAC_MGT_MULTIHOP_ACTION;
+      break;
 
     }
     break;
@@ -590,6 +623,16 @@
 {
   return (GetType () == WIFI_MAC_MGT_DEAUTHENTICATION)?true:false;
 }
+bool
+WifiMacHeader::IsAction (void) const
+{
+  return (GetType () == WIFI_MAC_MGT_ACTION)?true:false;
+}
+bool
+WifiMacHeader::IsMultihopAction (void) const
+{
+  return (GetType () == WIFI_MAC_MGT_MULTIHOP_ACTION)?true:false;
+}
 
 
 uint16_t 
@@ -810,6 +853,9 @@
     FOO (MGT_PROBE_RESPONSE);
     FOO (MGT_AUTHENTICATION);
     FOO (MGT_DEAUTHENTICATION);
+    FOO (MGT_ACTION);
+    FOO (MGT_ACTION_NO_ACK);
+    FOO (MGT_MULTIHOP_ACTION);
     
     FOO (DATA);
     FOO (DATA_CFACK);
@@ -895,6 +941,12 @@
          << ", BSSID=" << m_addr3 << ", FragNumber=" << m_seqFrag
          << ", SeqNumber=" << m_seqSeq;
       break;
+    case WIFI_MAC_MGT_ACTION:
+      // TODO
+    case WIFI_MAC_MGT_ACTION_NO_ACK:
+      // TODO
+    case WIFI_MAC_MGT_MULTIHOP_ACTION:
+      // TODO
     case WIFI_MAC_DATA:
       PrintFrameControl (os);
       os << " Duration/ID=" << m_duration << "us";
--- a/src/devices/wifi/wifi-mac-header.h	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/wifi-mac-header.h	Fri May 29 10:15:19 2009 +0400
@@ -46,6 +46,9 @@
   WIFI_MAC_MGT_PROBE_RESPONSE,
   WIFI_MAC_MGT_AUTHENTICATION,
   WIFI_MAC_MGT_DEAUTHENTICATION,
+  WIFI_MAC_MGT_ACTION,
+  WIFI_MAC_MGT_ACTION_NO_ACK,
+  WIFI_MAC_MGT_MULTIHOP_ACTION,
 
   WIFI_MAC_DATA,
   WIFI_MAC_DATA_CFACK,
@@ -98,6 +101,8 @@
   void SetProbeResp (void);
   void SetBeacon (void);
   void SetTypeData (void);
+  void SetAction ();
+  void SetMultihopAction();
   void SetDsFrom (void);
   void SetDsNotFrom (void);
   void SetDsTo (void);
@@ -150,6 +155,8 @@
   bool IsDisassociation (void) const;
   bool IsAuthentication (void) const;
   bool IsDeauthentication (void) const;
+  bool IsAction () const;
+  bool IsMultihopAction () const;
   uint16_t GetRawDuration (void) const;
   Time GetDuration (void) const;
   uint16_t GetSequenceControl (void) const;
--- a/src/devices/wifi/wifi-phy-test.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/wifi-phy-test.cc	Fri May 29 10:15:19 2009 +0400
@@ -167,7 +167,7 @@
 CollisionExperiment::SendA (void) const
 {
   Ptr<Packet> p = Create<Packet> (m_input.packetSizeA);
-  p->AddTag (FlowIdTag (m_flowIdA));
+  p->AddByteTag (FlowIdTag (m_flowIdA));
   m_txA->SendPacket (p, WifiMode (m_input.txModeA), 
 		     WIFI_PREAMBLE_SHORT, m_input.txPowerLevelA);
 }
@@ -176,7 +176,7 @@
 CollisionExperiment::SendB (void) const
 {
   Ptr<Packet> p = Create<Packet> (m_input.packetSizeB);
-  p->AddTag (FlowIdTag (m_flowIdB));
+  p->AddByteTag (FlowIdTag (m_flowIdB));
   m_txB->SendPacket (p, WifiMode (m_input.txModeB), 
 		     WIFI_PREAMBLE_SHORT, m_input.txPowerLevelB);
 }
@@ -185,7 +185,7 @@
 CollisionExperiment::Receive (Ptr<Packet> p, double snr, WifiMode mode, enum WifiPreamble preamble)
 {
   FlowIdTag tag;
-  p->FindFirstMatchingTag (tag);
+  p->FindFirstMatchingByteTag (tag);
   if (tag.GetFlowId () == m_flowIdA)
     {
       m_output.receivedA++;
--- a/src/devices/wifi/wifi-remote-station-manager.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/wifi-remote-station-manager.cc	Fri May 29 10:15:19 2009 +0400
@@ -433,7 +433,9 @@
 WifiRemoteStation::WifiRemoteStation ()
   : m_state (BRAND_NEW),
     m_ssrc (0),
-    m_slrc (0)
+    m_slrc (0),
+    m_avgSlrcCoefficient(0.9),
+    m_avgSlrc (0.0)
 {}
 WifiRemoteStation::~WifiRemoteStation ()
 {}
@@ -557,7 +559,11 @@
 {
   return GetControlAnswerMode (dataMode);
 }
-
+double
+WifiRemoteStation::GetAvgSlrc ()
+{
+  return m_avgSlrc;
+}
 uint32_t 
 WifiRemoteStation::GetNSupportedModes (void) const
 {
@@ -577,7 +583,7 @@
       return;
     }
   TxModeTag tag = TxModeTag (DoGetRtsMode (), DoGetDataMode (fullPacketSize));
-  packet->AddTag (tag);
+  packet->AddPacketTag (tag);
 }
 WifiMode 
 WifiRemoteStation::GetDataMode (Ptr<const Packet> packet, uint32_t fullPacketSize)
@@ -588,7 +594,7 @@
     }
   TxModeTag tag;
   bool found;
-  found = packet->FindFirstMatchingTag (tag);
+  found = ConstCast<Packet> (packet)->RemovePacketTag (tag);
   NS_ASSERT (found);
   return tag.GetDataMode ();
 }
@@ -601,7 +607,7 @@
     }
   TxModeTag tag;
   bool found;
-  found = packet->FindFirstMatchingTag (tag);
+  found = ConstCast<Packet> (packet)->RemovePacketTag (tag);
   NS_ASSERT (found);
   return tag.GetRtsMode ();
 }
@@ -712,6 +718,7 @@
 void 
 WifiRemoteStation::ReportDataOk (double ackSnr, WifiMode ackMode, double dataSnr)
 {
+  m_avgSlrc = m_avgSlrc * m_avgSlrcCoefficient + (double) m_slrc * (1 - m_avgSlrcCoefficient);
   m_slrc = 0;
   DoReportDataOk (ackSnr, ackMode, dataSnr);
 }
--- a/src/devices/wifi/wifi-remote-station-manager.h	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/wifi-remote-station-manager.h	Fri May 29 10:15:19 2009 +0400
@@ -260,7 +260,7 @@
    *          handshake.
    */
   WifiMode GetAckMode (WifiMode dataMode);
-
+  double GetAvgSlrc ();
 private:
   virtual Ptr<WifiRemoteStationManager> GetManager (void) const = 0;
   virtual WifiMode DoGetDataMode (uint32_t size) = 0;
@@ -289,6 +289,13 @@
   SupportedModes m_modes;
   TracedValue<uint32_t> m_ssrc;
   TracedValue<uint32_t> m_slrc;
+  ///\name needed to calculate average SLRC
+  ///\{
+  ///\brief the coefficient: we valculate averages slrc as 
+  //m_avgSlrc = m_avgSlr*coefficient + m_slrc*(1-coefficient);
+  double m_avgSlrcCoefficient;
+  double m_avgSlrc;
+  ///\}
 };
 
 } // namespace ns3 
--- a/src/devices/wifi/wscript	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/wscript	Fri May 29 10:15:19 2009 +0400
@@ -105,6 +105,13 @@
         'msdu-aggregator.h',
         'amsdu-subframe-header.h',
         'qos-tag.h',
+# Need this for module devices/mesh
+        'mgt-headers.h',
+        'status-code.h',
+        'capability-information.h',
+        'dcf-manager.h',
+        'mac-rx-middle.h', 
+        'mac-low.h',
         ]
 
     if bld.env['ENABLE_GSL']:
--- a/src/devices/wifi/yans-wifi-channel.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/yans-wifi-channel.cc	Fri May 29 10:15:19 2009 +0400
@@ -74,13 +74,25 @@
 YansWifiChannel::Send (Ptr<YansWifiPhy> sender, Ptr<const Packet> packet, double txPowerDbm,
                        WifiMode wifiMode, WifiPreamble preamble) const
 {
+  NS_LOG_DEBUG ("I am on channel "  << sender->GetFrequencyChannel()
+                << " : sending " << packet->GetUid ());
+  
   Ptr<MobilityModel> senderMobility = sender->GetMobility ()->GetObject<MobilityModel> ();
   NS_ASSERT (senderMobility != 0);
   uint32_t j = 0;
-  for (PhyList::const_iterator i = m_phyList.begin (); i != m_phyList.end (); i++)
-    {
+  for (PhyList::const_iterator i = m_phyList.begin (); i != m_phyList.end (); i++, j++)
+    { 
       if (sender != (*i))
         {
+          // For now don't account for interchannel interference
+          if ((*i)->GetFrequencyChannel() != sender->GetFrequencyChannel())
+            {
+              NS_LOG_DEBUG ("Dropped: " << (*i)->GetFrequencyChannel() 
+                            << " != " << sender->GetFrequencyChannel() );
+              continue;
+            }
+          NS_LOG_DEBUG ("Passed to receiver");
+          
           Ptr<MobilityModel> receiverMobility = (*i)->GetMobility ()->GetObject<MobilityModel> ();
           Time delay = m_delay->GetDelay (senderMobility, receiverMobility);
           double rxPowerDbm = m_loss->CalcRxPower (txPowerDbm, senderMobility, receiverMobility);
@@ -90,7 +102,6 @@
           Simulator::Schedule (delay, &YansWifiChannel::Receive, this, 
                                j, copy, rxPowerDbm, wifiMode, preamble);
         }
-      j++;
     }
 }
 
--- a/src/devices/wifi/yans-wifi-phy.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/yans-wifi-phy.cc	Fri May 29 10:15:19 2009 +0400
@@ -116,13 +116,21 @@
                    PointerValue (),
                    MakePointerAccessor (&YansWifiPhy::m_state),
                    MakePointerChecker<WifiPhyStateHelper> ())
+    .AddAttribute ("ChannelSwitchDelay",
+                   "Delay between two short frames transmitted on different frequencies",
+                   TimeValue (MicroSeconds (250)),
+                   MakeTimeAccessor (&YansWifiPhy::m_channelSwitchDelay), 
+                   MakeTimeChecker ())
+    
     ;
   return tid;
 }
 
 YansWifiPhy::YansWifiPhy ()
- : m_endSyncEvent (),
-   m_random (0.0, 1.0)
+ : m_channelId(0),
+   m_endSyncEvent (),
+   m_random (0.0, 1.0),
+   m_channelStartingFrequency(0.0)
 {
   NS_LOG_FUNCTION (this);
   m_state = CreateObject<WifiPhyStateHelper> ();
@@ -298,6 +306,32 @@
 {
   m_channel = channel;
   m_channel->Add (this);
+  m_channelId = 0;      // always start on channel starting frequency
+}
+
+void 
+YansWifiPhy::SetFrequencyChannel (uint16_t nch)
+{
+  Simulator::Schedule (m_channelSwitchDelay, &YansWifiPhy::DoSetChannelId, this, nch);
+}
+
+void
+YansWifiPhy::DoSetChannelId (uint16_t nch)
+{
+  NS_LOG_DEBUG("switching channel " << m_channelId << " -> " << nch);
+  m_channelId = nch;
+}
+
+uint16_t 
+YansWifiPhy::GetFrequencyChannel() const
+{
+  return m_channelId;
+}
+
+double
+YansWifiPhy::GetChannelCenterFrequency() const
+{
+  return m_channelStartingFrequency + 5e6 * GetFrequencyChannel();
 }
 
 void 
@@ -434,6 +468,7 @@
 {
   NS_LOG_FUNCTION (this);
   m_interference.Configure80211aParameters ();
+  m_channelStartingFrequency = 5e9; // 5 GHz 
   m_modes.push_back (WifiPhy::Get6mba ());
   m_modes.push_back (WifiPhy::Get9mba ());
   m_modes.push_back (WifiPhy::Get12mba ());
--- a/src/devices/wifi/yans-wifi-phy.h	Thu May 28 21:41:45 2009 -0700
+++ b/src/devices/wifi/yans-wifi-phy.h	Fri May 29 10:15:19 2009 +0400
@@ -69,6 +69,21 @@
   virtual ~YansWifiPhy ();
 
   void SetChannel (Ptr<YansWifiChannel> channel);
+  
+  /** 
+   * \brief Set channel number. 
+   * 
+   * Channel center frequency = Channel starting frequency + 5 × nch (MHz)
+   *
+   * where Starting channel frequency is standard-dependent, see SetStandard()
+   * as defined in IEEE 802.11-2007 17.3.8.3.2.
+   */ 
+  void SetFrequencyChannel (uint16_t id);
+  /// Return current channel ID, see SetChannelId()
+  uint16_t GetFrequencyChannel () const;
+  /// Return current center channel frequency in Hz, see SetChannelId()
+  double GetChannelCenterFrequency() const;
+  
   void StartReceivePacket (Ptr<Packet> packet,
                            double rxPowerDbm,
                            WifiMode mode,
@@ -94,6 +109,8 @@
   Ptr<ErrorRateModel> GetErrorRateModel (void) const;
   Ptr<Object> GetDevice (void) const;
   Ptr<Object> GetMobility (void);
+  
+  
 
 
   virtual double GetTxPowerStart (void) const;
@@ -133,6 +150,7 @@
   double RatioToDb (double ratio) const;
   double GetPowerDbm (uint8_t power) const;
   void EndSync (Ptr<Packet> packet, Ptr<InterferenceHelper::Event> event);
+  void DoSetChannelId(uint16_t id);
 
 private:
   double   m_edThresholdW;
@@ -144,14 +162,18 @@
   uint32_t m_nTxPower;
 
   Ptr<YansWifiChannel> m_channel;
+  uint16_t m_channelId;
   Ptr<Object> m_device;
   Ptr<Object> m_mobility;
   Modes m_modes;
   EventId m_endSyncEvent;
   UniformVariable m_random;
   WifiPhyStandard m_standard;
+  /// Standard-dependent center frequency of 0-th channel 
+  double m_channelStartingFrequency;
   Ptr<WifiPhyStateHelper> m_state;
   InterferenceHelper m_interference;
+  Time m_channelSwitchDelay;
 
 };
 
--- a/src/internet-stack/ipv4-l3-protocol.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/internet-stack/ipv4-l3-protocol.cc	Fri May 29 10:15:19 2009 +0400
@@ -31,16 +31,14 @@
 #include "ns3/object-vector.h"
 #include "ns3/ipv4-header.h"
 #include "ns3/boolean.h"
-#include "ns3/ipv4-routing-table-entry.h"
-#include "ns3/ipv4-static-routing.h"
+#include "arp-l3-protocol.h"
 
-#include "loopback-net-device.h"
-#include "arp-l3-protocol.h"
 #include "ipv4-l3-protocol.h"
 #include "ipv4-l4-protocol.h"
-#include "ipv4-list-routing-impl.h"
 #include "icmpv4-l4-protocol.h"
 #include "ipv4-interface.h"
+#include "ipv4-loopback-interface.h"
+#include "arp-ipv4-interface.h"
 #include "ipv4-raw-socket-impl.h"
 
 NS_LOG_COMPONENT_DEFINE ("Ipv4L3Protocol");
@@ -85,6 +83,8 @@
     m_identification (0)
 {
   NS_LOG_FUNCTION_NOARGS ();
+  m_staticRouting = CreateObject<Ipv4StaticRouting> ();
+  AddRoutingProtocol (m_staticRouting, 0);
 }
 
 Ipv4L3Protocol::~Ipv4L3Protocol ()
@@ -119,7 +119,6 @@
 Ipv4L3Protocol::SetNode (Ptr<Node> node)
 {
   m_node = node;
-  // Add a LoopbackNetDevice if needed, and an Ipv4Interface on top of it
   SetupLoopback ();
 }
 
@@ -146,48 +145,18 @@
     }
   return;
 }
-/*
- * This method is called by AddAgregate and completes the aggregation
- * by setting the node in the ipv4 stack
- */
-void
-Ipv4L3Protocol::NotifyNewAggregate ()
-{
-  Ptr<Node>node = this->GetObject<Node>();
-  // verify that it's a valid node and that
-  // the node has not been set before
-  if (node!= 0 && m_node == 0)
-    {
-      this->SetNode (node);
-    }
-  Object::NotifyNewAggregate ();
-}
-
-void 
-Ipv4L3Protocol::SetRoutingProtocol (Ptr<Ipv4RoutingProtocol> routing)
-{
-  NS_LOG_FUNCTION (this);
-  m_routingProtocol = routing;
-  // XXX should check all interfaces to see if any were set to Up state
-  // prior to a routing protocol being added
-  if (GetStaticRouting () != 0)
-    {
-      GetStaticRouting ()->AddHostRouteTo (Ipv4Address::GetLoopback (), 0);
-    }
-}
-
-
-Ptr<Ipv4RoutingProtocol> 
-Ipv4L3Protocol::GetRoutingProtocol (void) const
-{
-  return m_routingProtocol;
-}
 
 void 
 Ipv4L3Protocol::DoDispose (void)
 {
   NS_LOG_FUNCTION (this);
-  for (L4List_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
+ 
+  for (SocketList::iterator i = m_sockets.begin (); i != m_sockets.end (); ++i)
+    {
+      *i = 0;
+    }
+
+ for (L4List_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
     {
       *i = 0;
     }
@@ -198,12 +167,10 @@
       *i = 0;
     }
   m_interfaces.clear ();
+  m_routingProtocols.clear ();
   m_node = 0;
-  if (m_routingProtocol)
-    {
-      m_routingProtocol->Dispose ();
-      m_routingProtocol = 0;
-    }
+  m_staticRouting->Dispose ();
+  m_staticRouting = 0;
   Object::DoDispose ();
 }
 
@@ -212,33 +179,12 @@
 {
   NS_LOG_FUNCTION_NOARGS ();
 
-  Ptr<Ipv4Interface> interface = CreateObject<Ipv4Interface> ();
-  Ptr<LoopbackNetDevice> device = 0;
-  // First check whether an existing LoopbackNetDevice exists on the node
-  for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
-    {
-      if (device = DynamicCast<LoopbackNetDevice> (m_node->GetDevice (i)))
-        {
-          break;
-        }
-    }
-  if (device == 0)
-    {
-      device = CreateObject<LoopbackNetDevice> (); 
-      m_node->AddDevice (device);
-    }
-  interface->SetDevice (device);
+  Ptr<Ipv4LoopbackInterface> interface = CreateObject<Ipv4LoopbackInterface> ();
   interface->SetNode (m_node);
   Ipv4InterfaceAddress ifaceAddr = Ipv4InterfaceAddress (Ipv4Address::GetLoopback (), Ipv4Mask::GetLoopback ());
   interface->AddAddress (ifaceAddr);
   uint32_t index = AddIpv4Interface (interface);
-  Ptr<Node> node = GetObject<Node> ();
-  node->RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, this), 
-                                 Ipv4L3Protocol::PROT_NUMBER, device);
-  if (GetStaticRouting () != 0)
-    {
-      GetStaticRouting ()->AddHostRouteTo (Ipv4Address::GetLoopback (), index);
-    }
+  AddHostRouteTo (Ipv4Address::GetLoopback (), index);
   interface->SetUp ();
 }
 
@@ -249,24 +195,192 @@
   m_defaultTtl = ttl;
 }
     
-// XXX need to remove dependencies on Ipv4StaticRouting from this class
-Ptr<Ipv4StaticRouting>
-Ipv4L3Protocol::GetStaticRouting (void) const
+
+void 
+Ipv4L3Protocol::AddHostRouteTo (Ipv4Address dest, 
+                      Ipv4Address nextHop, 
+                      uint32_t interface)
+{
+  NS_LOG_FUNCTION (this << dest << nextHop << interface);
+  m_staticRouting->AddHostRouteTo (dest, nextHop, interface);
+}
+
+void 
+Ipv4L3Protocol::AddHostRouteTo (Ipv4Address dest, 
+				uint32_t interface)
+{
+  NS_LOG_FUNCTION (this << dest << interface);
+  m_staticRouting->AddHostRouteTo (dest, interface);
+}
+
+void 
+Ipv4L3Protocol::AddNetworkRouteTo (Ipv4Address network, 
+				   Ipv4Mask networkMask, 
+				   Ipv4Address nextHop, 
+				   uint32_t interface)
+{
+  NS_LOG_FUNCTION (this << network << networkMask << nextHop << interface);
+  m_staticRouting->AddNetworkRouteTo (network, networkMask, nextHop, interface);
+}
+
+void 
+Ipv4L3Protocol::AddNetworkRouteTo (Ipv4Address network, 
+				   Ipv4Mask networkMask, 
+				   uint32_t interface)
+{
+  NS_LOG_FUNCTION (this << network << networkMask << interface);
+  m_staticRouting->AddNetworkRouteTo (network, networkMask, interface);
+}
+
+void 
+Ipv4L3Protocol::SetDefaultRoute (Ipv4Address nextHop, 
+				 uint32_t interface)
+{
+  NS_LOG_FUNCTION (this << nextHop << interface);
+  m_staticRouting->SetDefaultRoute (nextHop, interface);
+}
+
+void
+Ipv4L3Protocol::Lookup (
+  Ipv4Header const &ipHeader,
+  Ptr<Packet> packet,
+  Ipv4RoutingProtocol::RouteReplyCallback routeReply)
+{
+  NS_LOG_FUNCTION (this << &ipHeader << packet << &routeReply);
+
+  Lookup (Ipv4RoutingProtocol::INTERFACE_ANY, ipHeader, packet, routeReply);
+}
+
+void
+Ipv4L3Protocol::Lookup (
+  uint32_t interface,
+  Ipv4Header const &ipHeader,
+  Ptr<Packet> packet,
+  Ipv4RoutingProtocol::RouteReplyCallback routeReply)
+{
+  NS_LOG_FUNCTION (this << interface << &ipHeader << packet << &routeReply);
+
+  for (Ipv4RoutingProtocolList::const_iterator rprotoIter = 
+         m_routingProtocols.begin ();
+       rprotoIter != m_routingProtocols.end (); 
+       rprotoIter++)
+    {
+      NS_LOG_LOGIC ("Requesting route");
+      if ((*rprotoIter).second->RequestRoute (interface, ipHeader, packet, 
+                                              routeReply))
+        return;
+    }
+
+  if (ipHeader.GetDestination ().IsMulticast () && 
+      interface == Ipv4RoutingProtocol::INTERFACE_ANY)
+    {
+      NS_LOG_LOGIC ("Multicast destination with local source");
+//
+// We have a multicast packet originating from the current node and were not
+// able to send it using the usual RequestRoute process.  Since the usual
+// process includes trying to use a default multicast route, this means that
+// there was no specific route out of the node found, and there was no default
+// multicast route set.
+//
+// The fallback position is to look for a default unicast route and use that
+// to get the packet off the node if we have one.
+//
+      Ipv4Route *route = m_staticRouting->GetDefaultRoute ();
+
+      if (route)
+        {
+          NS_LOG_LOGIC ("Local source. Using unicast default route for "
+            "multicast packet");
+
+          routeReply (true, *route, packet, ipHeader);
+          return;
+        }
+    }
+//
+// No route found
+//
+  routeReply (false, Ipv4Route (), packet, ipHeader);
+}
+
+void
+Ipv4L3Protocol::AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
+                                    int16_t priority)
+{
+  NS_LOG_FUNCTION (this << &routingProtocol << priority);
+  m_routingProtocols.push_back
+    (std::pair<int, Ptr<Ipv4RoutingProtocol> > (-priority, routingProtocol));
+  m_routingProtocols.sort ();
+}
+
+uint32_t 
+Ipv4L3Protocol::GetNRoutes (void)
 {
   NS_LOG_FUNCTION_NOARGS ();
-  Ptr<Ipv4StaticRouting> staticRouting;
-  if (m_routingProtocol != 0)
-    {
-      Ptr<Ipv4StaticRoutingImpl> sr = DynamicCast<Ipv4StaticRoutingImpl> (m_routingProtocol);
-      if (sr != 0)
-        {
-          return sr;
-        }
-      Ptr<Ipv4ListRoutingImpl> lr = DynamicCast<Ipv4ListRoutingImpl> (m_routingProtocol);
-      NS_ASSERT (lr);
-      staticRouting = lr->GetStaticRouting ();
-    }
-  return staticRouting;
+  return m_staticRouting->GetNRoutes ();
+}
+
+Ipv4Route 
+Ipv4L3Protocol::GetRoute (uint32_t index)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return *m_staticRouting->GetRoute (index);
+}
+
+void 
+Ipv4L3Protocol::RemoveRoute (uint32_t index)
+{
+  NS_LOG_FUNCTION (this << index);
+  m_staticRouting->RemoveRoute (index);
+}
+
+void 
+Ipv4L3Protocol::AddMulticastRoute (Ipv4Address origin,
+                                   Ipv4Address group,
+                                   uint32_t inputInterface,
+                                   std::vector<uint32_t> outputInterfaces)
+{
+  NS_LOG_FUNCTION (this << origin << group << inputInterface << &outputInterfaces);
+
+  m_staticRouting->AddMulticastRoute (origin, group, inputInterface,
+    outputInterfaces);
+}
+
+void 
+Ipv4L3Protocol::SetDefaultMulticastRoute (uint32_t outputInterface)
+{
+  NS_LOG_FUNCTION (this << outputInterface);
+
+  m_staticRouting->SetDefaultMulticastRoute (outputInterface);
+}
+
+uint32_t 
+Ipv4L3Protocol::GetNMulticastRoutes (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_staticRouting->GetNMulticastRoutes ();
+}
+
+Ipv4MulticastRoute 
+Ipv4L3Protocol::GetMulticastRoute (uint32_t index) const
+{
+  NS_LOG_FUNCTION (this << index);
+  return *m_staticRouting->GetMulticastRoute (index);
+}
+
+void 
+Ipv4L3Protocol::RemoveMulticastRoute (Ipv4Address origin,
+                                       Ipv4Address group,
+                                       uint32_t inputInterface)
+{
+  NS_LOG_FUNCTION (this << origin << group << inputInterface);
+  m_staticRouting->RemoveMulticastRoute (origin, group, inputInterface);
+}
+
+void 
+Ipv4L3Protocol::RemoveMulticastRoute (uint32_t index)
+{
+  NS_LOG_FUNCTION (this << index);
+  m_staticRouting->RemoveMulticastRoute (index);
 }
 
 uint32_t 
@@ -280,7 +394,7 @@
   node->RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (GetObject<ArpL3Protocol> ())),
                                  ArpL3Protocol::PROT_NUMBER, device);
 
-  Ptr<Ipv4Interface> interface = CreateObject<Ipv4Interface> ();
+  Ptr<ArpIpv4Interface> interface = CreateObject<ArpIpv4Interface> ();
   interface->SetNode (m_node);
   interface->SetDevice (device);
   return AddIpv4Interface (interface);
@@ -319,60 +433,60 @@
   return m_nInterfaces;
 }
 
-int32_t 
-Ipv4L3Protocol::GetInterfaceForAddress (
-  Ipv4Address address) const
+uint32_t 
+Ipv4L3Protocol::FindInterfaceForAddr (Ipv4Address addr) const
 {
-  NS_LOG_FUNCTION (this << address);
+  NS_LOG_FUNCTION (this << addr);
 
-  int32_t interface = 0;
+  uint32_t interface = 0;
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); 
        i != m_interfaces.end (); 
        i++, interface++)
     {
-      for (uint32_t j = 0; j < (*i)->GetNAddresses (); j++)
+      for (uint32_t j = 0; j < (*i)->GetNAddresses (); j++) 
         {
-          if ((*i)->GetAddress (j).GetLocal () == address)
+          if ((*i)->GetAddress (j).GetLocal () == addr)
             {
               return interface;
             }
         }
     }
 
-  return -1;
+  NS_FATAL_ERROR ("Ipv4L3Protocol::FindInterfaceForAddr (): "
+                  "Interface not found for IP address " << addr);
+  return 0;
 }
 
-int32_t 
-Ipv4L3Protocol::GetInterfaceForPrefix (
-  Ipv4Address address, 
-  Ipv4Mask mask) const
+uint32_t 
+Ipv4L3Protocol::FindInterfaceForAddr (Ipv4Address addr, Ipv4Mask mask) const
 {
-  NS_LOG_FUNCTION (this << address << mask);
+  NS_LOG_FUNCTION (this << addr << mask);
 
-  int32_t interface = 0;
+  uint32_t interface = 0;
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); 
        i != m_interfaces.end (); 
        i++, interface++)
     {
       for (uint32_t j = 0; j < (*i)->GetNAddresses (); j++)
         {
-          if ((*i)->GetAddress (j).GetLocal ().CombineMask (mask) == address.CombineMask (mask))
+          if ((*i)->GetAddress (j).GetLocal ().CombineMask (mask) == addr.CombineMask (mask))
             {
               return interface;
             }
         }
     }
 
-  return -1;
+  NS_ASSERT_MSG(false, "Ipv4L3Protocol::FindInterfaceForAddr (): "
+    "Interface not found for masked IP address");
+  return 0;
 }
 
 int32_t 
-Ipv4L3Protocol::GetInterfaceForDevice (
-  Ptr<const NetDevice> device) const
+Ipv4L3Protocol::FindInterfaceForDevice (Ptr<NetDevice> device) const
 {
-  NS_LOG_FUNCTION (this << device->GetIfIndex());
+  NS_LOG_FUNCTION (this << device);
 
-  int32_t interface = 0;
+  uint32_t interface = 0;
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); 
        i != m_interfaces.end (); 
        i++, interface++)
@@ -386,18 +500,31 @@
   return -1;
 }
 
+Ptr<Ipv4Interface>
+Ipv4L3Protocol::FindInterfaceForDevice (Ptr<const NetDevice> device)
+{
+  NS_LOG_FUNCTION (this << &device);
+  for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
+    {
+      if ((*i)->GetDevice () == device)
+        {
+          return *i;
+        }
+    }
+  return 0;
+}  
+
 void 
 Ipv4L3Protocol::Receive( Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol, const Address &from,
                          const Address &to, NetDevice::PacketType packetType)
 {
   NS_LOG_FUNCTION (this << &device << p << protocol <<  from);
 
-  NS_LOG_LOGIC ("Packet from " << from << " received on node " << 
-    m_node->GetId ());
+  NS_LOG_LOGIC ("Packet from " << from << " received on node " << m_node->GetId ());
 
-  uint32_t interface = 0;
   Ptr<Packet> packet = p->Copy ();
 
+  uint32_t index = 0;
   Ptr<Ipv4Interface> ipv4Interface;
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); 
        i != m_interfaces.end (); 
@@ -408,9 +535,9 @@
         {
           if (ipv4Interface->IsUp ())
             {
-              m_rxTrace (packet, interface);
+              m_rxTrace (packet, index);
               break;
-            }
+            } 
           else
             {
               NS_LOG_LOGIC ("Dropping received packet-- interface is down");
@@ -418,9 +545,8 @@
               return;
             }
         }
-      interface++;
+      index++;
     }
-
   Ipv4Header ipHeader;
   if (m_calcChecksum)
     {
@@ -440,13 +566,12 @@
       socket->ForwardUp (packet, ipHeader, device);
     }
 
-  m_routingProtocol->RouteInput (packet, ipHeader, device, 
-    MakeCallback (&Ipv4L3Protocol::IpForward, this),
-    MakeCallback (&Ipv4L3Protocol::IpMulticastForward, this),
-    MakeCallback (&Ipv4L3Protocol::LocalDeliver, this),
-    MakeNullCallback <void, Ptr<const Packet>, const Ipv4Header &> ()
-  );
+  if (Forwarding (index, packet, ipHeader, device)) 
+    {
+      return;
+    }
 
+  ForwardUp (packet, ipHeader, ipv4Interface);
 }
 
 Ptr<Icmpv4L4Protocol> 
@@ -473,35 +598,74 @@
 Ipv4L3Protocol::Send (Ptr<Packet> packet, 
             Ipv4Address source, 
             Ipv4Address destination,
-            uint8_t protocol,
-            Ptr<Ipv4Route> route)
+            uint8_t protocol)
 {
-  NS_LOG_FUNCTION (this << packet << source << destination << uint32_t(protocol) << route);
+  NS_LOG_FUNCTION (this << packet << source << destination << protocol);
 
   Ipv4Header ipHeader;
-  bool mayFragment = true;
-  uint8_t ttl = m_defaultTtl;
-  SocketIpTtlTag tag;
-  bool found = packet->FindFirstMatchingTag (tag);
+
+  if (m_calcChecksum)
+    {
+      ipHeader.EnableChecksum ();
+    }
+
+  ipHeader.SetSource (source);
+  ipHeader.SetDestination (destination);
+  ipHeader.SetProtocol (protocol);
+  ipHeader.SetPayloadSize (packet->GetSize ());
+  ipHeader.SetIdentification (m_identification);
+
+  m_identification ++;
+
+  SocketSetDontFragmentTag dfTag;
+  bool found = packet->RemovePacketTag (dfTag);
   if (found)
     {
-      ttl = tag.GetTtl ();
-      // XXX remove tag here?  
+      if (dfTag.IsEnabled ())
+        {
+          ipHeader.SetDontFragment ();
+        }
+      else
+        {
+          ipHeader.SetMayFragment ();
+        }
     }
+  
 
-  // Handle a few cases:
-  // 1) packet is destined to limited broadcast address
-  // 2) packet is destined to a subnet-directed broadcast address
-  // 3) packet is not broadcast, and is passed in with a route entry
-  // 4) packet is not broadcast, and is passed in with a route entry but route->GetGateway is not set (e.g., on-demand)
-  // 5) packet is not broadcast, and route is NULL (e.g., a raw socket call, or ICMP)
-  
-  // 1) packet is destined to limited broadcast address
+  // Set TTL to 1 if it is a broadcast packet of any type.  Otherwise,
+  // possibly override the default TTL if the packet is tagged
+  SocketIpTtlTag tag;
+  found = packet->RemovePacketTag (tag);
+
   if (destination.IsBroadcast ()) 
     {
-      NS_LOG_LOGIC ("Ipv4L3Protocol::Send case 1:  limited broadcast");
-      ttl = 1;
-      ipHeader = BuildHeader (source, destination, protocol, packet->GetSize (), ttl, mayFragment);
+      ipHeader.SetTtl (1);
+    }
+  else if (found)
+    {
+      ipHeader.SetTtl (tag.GetTtl ());
+    }
+  else
+    {
+      ipHeader.SetTtl (m_defaultTtl);
+      uint32_t ifaceIndex = 0;
+      for (Ipv4InterfaceList::iterator ifaceIter = m_interfaces.begin ();
+           ifaceIter != m_interfaces.end (); ifaceIter++, ifaceIndex++)
+        {
+          Ptr<Ipv4Interface> outInterface = *ifaceIter;
+          // XXX this logic might not be completely correct for multi-addressed interface
+          for (uint32_t j = 0; j < outInterface->GetNAddresses(); j++)
+            {
+              if (destination.IsSubnetDirectedBroadcast (
+                outInterface->GetAddress (j).GetMask ()))
+                {
+                  ipHeader.SetTtl (1);
+                }
+            }
+        }
+    }
+  if (destination.IsBroadcast ())
+    {
       uint32_t ifaceIndex = 0;
       for (Ipv4InterfaceList::iterator ifaceIter = m_interfaces.begin ();
            ifaceIter != m_interfaces.end (); ifaceIter++, ifaceIndex++)
@@ -509,216 +673,209 @@
           Ptr<Ipv4Interface> outInterface = *ifaceIter;
           Ptr<Packet> packetCopy = packet->Copy ();
 
-          NS_ASSERT (packetCopy->GetSize () <= outInterface->GetMtu ());
           packetCopy->AddHeader (ipHeader);
-          m_txTrace (packetCopy, ifaceIndex);
-          outInterface->Send (packetCopy, destination);
-        }
-      return;
-    }
-
-  // 2) check: packet is destined to a subnet-directed broadcast address
-  uint32_t ifaceIndex = 0;
-  for (Ipv4InterfaceList::iterator ifaceIter = m_interfaces.begin ();
-    ifaceIter != m_interfaces.end (); ifaceIter++, ifaceIndex++)
-    {
-      Ptr<Ipv4Interface> outInterface = *ifaceIter;
-      for (uint32_t j = 0; j < GetNAddresses (ifaceIndex); j++)
-        {
-          Ipv4InterfaceAddress ifAddr = GetAddress (ifaceIndex, j);
-          NS_LOG_LOGIC ("Testing address " << ifAddr.GetLocal () << " with mask " << ifAddr.GetMask ());
-          if (destination.IsSubnetDirectedBroadcast (ifAddr.GetMask ()) && 
-              destination.CombineMask (ifAddr.GetMask ()) == ifAddr.GetLocal ().CombineMask (ifAddr.GetMask ())   )  
+          // XXX Handle multiple address on interface
+          if (packetCopy->GetSize () > outInterface->GetMtu () &&
+              ipHeader.IsDontFragment () &&
+              IsUnicast (ipHeader.GetDestination (), outInterface->GetAddress (0).GetMask ()))
+            {
+              Ptr<Icmpv4L4Protocol> icmp = GetIcmp ();
+              NS_ASSERT (icmp != 0);
+              icmp->SendDestUnreachFragNeeded (ipHeader, packet, outInterface->GetMtu ());
+              m_dropTrace (packetCopy);
+            }
+          else if (packet->GetSize () > outInterface->GetMtu () &&
+                   !ipHeader.IsDontFragment ())
             {
-              NS_LOG_LOGIC ("Ipv4L3Protocol::Send case 2:  subnet directed bcast to " << ifAddr.GetLocal ());
-              ttl = 1;
-              ipHeader = BuildHeader (source, destination, protocol, packet->GetSize (), ttl, mayFragment);
-              Ptr<Packet> packetCopy = packet->Copy ();
-              packetCopy->AddHeader (ipHeader);
-              m_txTrace (packetCopy, ifaceIndex);
-              outInterface->Send (packetCopy, destination);
-              return;
+              NS_LOG_LOGIC ("Too big: need fragmentation but no frag support.");
+              m_dropTrace (packet);
+            }
+          else
+            {
+              NS_ASSERT (packetCopy->GetSize () <= outInterface->GetMtu ());
+              if (outInterface->IsUp ())
+                {
+                  m_txTrace (packetCopy, ifaceIndex);
+                  outInterface->Send (packetCopy, destination);
+                }
+              else
+                {
+                  m_dropTrace (packetCopy);
+                }
             }
         }
     }
-
-  // 3) packet is not broadcast, and is passed in with a route entry
-  //    with a valid Ipv4Address as the gateway
-  if (route && route->GetGateway () != Ipv4Address ())
-    {
-      NS_LOG_LOGIC ("Ipv4L3Protocol::Send case 3:  passed in with route");
-      ipHeader = BuildHeader (source, destination, protocol, packet->GetSize (), ttl, mayFragment);
-      SendRealOut (route, packet, ipHeader);
-      return; 
-    } 
-  // 4) packet is not broadcast, and is passed in with a route entry but route->GetGateway is not set (e.g., on-demand)
-  if (route && route->GetGateway () != Ipv4Address ())
-    {
-      // This could arise because the synchronous RouteOutput() call
-      // returned to the transport protocol with a source address but
-      // there was no next hop available yet (since a route may need
-      // to be queried).  So, call asynchronous version of RouteOutput?
-      NS_FATAL_ERROR("XXX This case not yet implemented");
-    }
-  // 5) packet is not broadcast, and route is NULL (e.g., a raw socket call)
-  NS_LOG_LOGIC ("Ipv4L3Protocol::Send case 4:  passed in with no route " << destination);
-  Socket::SocketErrno errno; 
-  uint32_t oif = 0; // unused for now
-  ipHeader = BuildHeader (source, destination, protocol, packet->GetSize (), ttl, mayFragment);
-  Ptr<Ipv4Route> newRoute = m_routingProtocol->RouteOutput (ipHeader, oif, errno);
-  if (newRoute)
-    {
-      SendRealOut (newRoute, packet, ipHeader);
-    }
   else
     {
-      NS_LOG_WARN ("No route to host.  Drop.");
-      m_dropTrace (packet);
+      // XXX Note here that in most ipv4 stacks in the world,
+      // the route calculation for an outgoing packet is not
+      // done in the ip layer. It is done within the application
+      // socket when the first packet is sent to avoid this
+      // costly lookup on a per-packet basis.
+      // That would require us to get the route from the packet,
+      // most likely with a packet tag. The higher layers do not
+      // do this yet for us.
+      Lookup (ipHeader, packet,
+              MakeCallback (&Ipv4L3Protocol::SendRealOut, this));
     }
 }
 
-// XXX when should we set ip_id?   check whether we are incrementing
-// m_identification on packets that may later be dropped in this stack
-// and whether that deviates from Linux
-Ipv4Header
-Ipv4L3Protocol::BuildHeader (
-            Ipv4Address source, 
-            Ipv4Address destination,
-            uint8_t protocol,
-            uint16_t payloadSize,
-            uint8_t ttl,
-            bool mayFragment)
-{
-  NS_LOG_FUNCTION_NOARGS ();
-  Ipv4Header ipHeader;
-  ipHeader.SetSource (source);
-  ipHeader.SetDestination (destination);
-  ipHeader.SetProtocol (protocol);
-  ipHeader.SetPayloadSize (payloadSize);
-  ipHeader.SetTtl (ttl);
-  if (mayFragment == true)
-    {
-      ipHeader.SetMayFragment ();
-      ipHeader.SetIdentification (m_identification);
-      m_identification ++;
-    }
-  else
-    {
-      ipHeader.SetDontFragment ();
-      // TBD:  set to zero here; will cause traces to change
-      ipHeader.SetIdentification (m_identification);
-      m_identification ++;
-    }
-  if (m_calcChecksum)
-    {
-      ipHeader.EnableChecksum ();
-    }
-  return ipHeader;
-}
-
 void
-Ipv4L3Protocol::SendRealOut (Ptr<Ipv4Route> route,
+Ipv4L3Protocol::SendRealOut (bool found,
+                             Ipv4Route const &route,
                              Ptr<Packet> packet,
                              Ipv4Header const &ipHeader)
 {
-  NS_LOG_FUNCTION (this << packet << &ipHeader);
+  NS_LOG_FUNCTION (this << found << &route << packet << &ipHeader);
 
-  // We add a header regardless of whether there is a route, since 
-  // we may want to drop trace
   packet->AddHeader (ipHeader);
-  if (route == 0)
+  if (!found)
     {
       NS_LOG_WARN ("No route to host.  Drop.");
       m_dropTrace (packet);
       return;
     }
 
-  Ptr<NetDevice> outDev = route->GetOutputDevice ();
-  int32_t interface = GetInterfaceForDevice (outDev);
-  NS_ASSERT (interface >= 0);
-  Ptr<Ipv4Interface> outInterface = GetInterface (interface);
-  NS_LOG_LOGIC ("Send via NetDevice ifIndex " << outDev->GetIfIndex () << " ipv4InterfaceIndex " << interface);
+  NS_LOG_LOGIC ("Send via interface " << route.GetInterface ());
 
-  NS_ASSERT (packet->GetSize () <= outInterface->GetMtu ());
-  if (!route->GetGateway ().IsEqual (Ipv4Address ("0.0.0.0"))) 
+  Ptr<Ipv4Interface> outInterface = GetInterface (route.GetInterface ());
+  // XXX handle multiple address on interface
+  if (packet->GetSize () > outInterface->GetMtu () &&
+      ipHeader.IsDontFragment () &&
+      IsUnicast (ipHeader.GetDestination (), outInterface->GetAddress (0).GetMask ()))
     {
-      if (outInterface->IsUp ())
-        {
-          NS_LOG_LOGIC ("Send to gateway " << route->GetGateway ());
-          m_txTrace (packet, interface);
-          outInterface->Send (packet, route->GetGateway ());
-        }
-      else
+      NS_LOG_LOGIC ("Too big: need fragmentation but not allowed");
+      Ptr<Icmpv4L4Protocol> icmp = GetIcmp ();
+      NS_ASSERT (icmp != 0);
+      Ptr<Packet> copyNoHeader = packet->Copy ();
+      Ipv4Header tmp;
+      copyNoHeader->RemoveHeader (tmp);
+      icmp->SendDestUnreachFragNeeded (ipHeader, copyNoHeader, outInterface->GetMtu ());
+      m_dropTrace (packet);
+    }
+  else if (packet->GetSize () > outInterface->GetMtu () &&
+           !ipHeader.IsDontFragment ())
+    {
+      NS_LOG_LOGIC ("Too big: need fragmentation but no frag support.");
+      m_dropTrace (packet);
+    }
+  else
+    {
+      if (route.IsGateway ()) 
         {
-          NS_LOG_LOGIC ("Dropping-- outgoing interface is down: " << route->GetGateway ());
-          m_dropTrace (packet);
-        }
-    } 
-  else 
-    {
-      if (outInterface->IsUp ())
+          if (outInterface->IsUp ())
+            {
+              NS_LOG_LOGIC ("Send to gateway " << route.GetGateway ());
+              m_txTrace (packet, route.GetInterface ());
+              outInterface->Send (packet, route.GetGateway ());
+            }
+          else
+            {
+              NS_LOG_LOGIC ("Dropping-- outgoing interface is down: " << route.GetGateway ());
+              m_dropTrace (packet);
+            }
+        } 
+      else 
         {
-          NS_LOG_LOGIC ("Send to destination " << ipHeader.GetDestination ());
-          m_txTrace (packet, interface);
-          outInterface->Send (packet, ipHeader.GetDestination ());
-        }
-      else
-        {
-          NS_LOG_LOGIC ("Dropping-- outgoing interface is down: " << ipHeader.GetDestination ());
-          m_dropTrace (packet);
+          if (outInterface->IsUp ())
+            {
+              NS_LOG_LOGIC ("Send to destination " << ipHeader.GetDestination ());
+              m_txTrace (packet, route.GetInterface ());
+              outInterface->Send (packet, ipHeader.GetDestination ());
+            }
+          else
+            {
+              NS_LOG_LOGIC ("Dropping-- outgoing interface is down: " << route.GetGateway ());
+              m_dropTrace (packet);
+            }
         }
     }
 }
 
-// This function analogous to Linux ip_mr_forward()
-void
-Ipv4L3Protocol::IpMulticastForward (Ptr<Ipv4MulticastRoute> mrtentry, Ptr<const Packet> p, const Ipv4Header &header)
+bool
+Ipv4L3Protocol::Forwarding (
+  uint32_t interface, 
+  Ptr<Packet> packet, 
+  Ipv4Header &ipHeader, 
+  Ptr<NetDevice> device)
 {
-  NS_LOG_FUNCTION (mrtentry << p << header);
-  NS_LOG_LOGIC ("Multicast forwarding logic for node: " << m_node->GetId ());
-  // The output interfaces we could forward this onto are encoded
-  // in the OutputTtl of the Ipv4MulticastRoute
-  for (uint32_t i = 0; i < Ipv4MulticastRoute::MAX_INTERFACES; i++)
+  NS_LOG_FUNCTION (interface << packet << &ipHeader<< device);
+  NS_LOG_LOGIC ("Forwarding logic for node: " << m_node->GetId ());
+
+  for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
+       i != m_interfaces.end (); i++) 
     {
-      if (mrtentry->GetOutputTtl (i) < Ipv4MulticastRoute::MAX_TTL)
+      for (uint32_t j = 0; j < (*i)->GetNAddresses (); j++)
         {
-          Ptr<Packet> packet = p->Copy ();
-          Ipv4Header h = header;
-          h.SetTtl (header.GetTtl () - 1);
-          if (h.GetTtl () == 0)
+          if ((*i)->GetAddress (j).GetLocal ().IsEqual (ipHeader.GetDestination ())) 
             {
-              NS_LOG_WARN ("TTL exceeded.  Drop.");
-              m_dropTrace (packet);
-              return;
+              NS_LOG_LOGIC ("For me (destination match)");
+              return false;
             }
-          NS_LOG_LOGIC ("Forward multicast via interface " << i);
-          Ptr<Ipv4Route> rtentry = Create<Ipv4Route> ();
-          rtentry->SetSource (h.GetSource ());
-          rtentry->SetDestination (h.GetDestination ());
-          rtentry->SetGateway (Ipv4Address::GetAny ());
-          rtentry->SetOutputDevice (GetNetDevice (i));
-          SendRealOut (rtentry, packet, h);
-          return; 
         }
     }
+  
+  for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
+       i != m_interfaces.end (); i++) 
+    {
+      Ptr<Ipv4Interface> interface = *i;
+      if (interface->GetDevice () == device)
+	{
+          // XXX multi-address case
+	  if (ipHeader.GetDestination ().IsEqual (interface->GetAddress (0).GetBroadcast ())) 
+	    {
+              NS_LOG_LOGIC ("For me (interface broadcast address)");
+	      return false;
+	    }
+	  break;
+	}
+    }
+      
+  if (ipHeader.GetDestination ().IsBroadcast ()) 
+    {
+      NS_LOG_LOGIC ("For me (Ipv4Addr broadcast address)");
+      return false;
+    }
+
+  if (ipHeader.GetDestination ().IsEqual (Ipv4Address::GetAny ())) 
+    {
+      NS_LOG_LOGIC ("For me (Ipv4Addr any address)");
+      return false;
+    }
+//  
+// If this is a to a multicast address and this node is a member of the 
+// indicated group we need to return false so the multicast is forwarded up.
+//        
+  for (Ipv4MulticastGroupList::const_iterator i = m_multicastGroups.begin ();
+       i != m_multicastGroups.end (); i++)
+    {
+      if ((*i).first.IsEqual (ipHeader.GetSource ()) &&
+          (*i).second.IsEqual (ipHeader.GetDestination ()))
+        {
+          NS_LOG_LOGIC ("For me (Joined multicast group)");
+          // We forward with a packet copy, since forwarding may change
+          // the packet, affecting our local delivery
+          NS_LOG_LOGIC ("Forwarding (multicast).");
+          DoForward (interface, packet->Copy (), ipHeader);
+          return false;
+        }   
+    }
+
+  DoForward (interface, packet, ipHeader);
+  return true;
 }
 
-// This function analogous to Linux ip_forward()
 void
-Ipv4L3Protocol::IpForward (Ptr<Ipv4Route> rtentry, Ptr<const Packet> p, const Ipv4Header &header)
+Ipv4L3Protocol::DoForward (uint32_t interface, 
+                           Ptr<Packet> packet, 
+                           Ipv4Header ipHeader)
 {
-  NS_LOG_FUNCTION (rtentry << p << header);
-  NS_LOG_LOGIC ("Forwarding logic for node: " << m_node->GetId ());
-  // Forwarding
-  Ipv4Header ipHeader = header;
-  Ptr<Packet> packet = p->Copy ();
+  NS_LOG_FUNCTION (this << interface << packet << ipHeader);
+
   ipHeader.SetTtl (ipHeader.GetTtl () - 1);
   // XXX handle multi-interfaces
   if (ipHeader.GetTtl () == 0)
     {
-      Ptr<NetDevice> outDev = rtentry->GetOutputDevice ();
-      int32_t interface = GetInterfaceForDevice (outDev);
-      NS_ASSERT (interface >= 0);
       if (IsUnicast (ipHeader.GetDestination (), GetInterface (interface)->GetAddress (0).GetMask ()))
         {
           Ptr<Icmpv4L4Protocol> icmp = GetIcmp ();
@@ -727,15 +884,18 @@
       NS_LOG_WARN ("TTL exceeded.  Drop.");
       m_dropTrace (packet);
       return;
-    }
-  SendRealOut (rtentry, packet, ipHeader);
+    }  
+  NS_LOG_LOGIC ("Not for me, forwarding.");
+  Lookup (interface, ipHeader, packet,
+          MakeCallback (&Ipv4L3Protocol::SendRealOut, this));
 }
 
+
 void
-Ipv4L3Protocol::LocalDeliver (Ptr<const Packet> packet, Ipv4Header const&ip, uint32_t iif)
+Ipv4L3Protocol::ForwardUp (Ptr<Packet> p, Ipv4Header const&ip,
+                           Ptr<Ipv4Interface> incomingInterface)
 {
-  NS_LOG_FUNCTION (this << packet << &ip);
-  Ptr<Packet> p = packet->Copy (); // need to pass a non-const packet up
+  NS_LOG_FUNCTION (this << p << &ip);
 
   Ptr<Ipv4L4Protocol> protocol = GetProtocol (ip.GetProtocol ());
   if (protocol != 0)
@@ -744,15 +904,15 @@
       // RX_ENDPOINT_UNREACH codepath
       Ptr<Packet> copy = p->Copy ();
       enum Ipv4L4Protocol::RxStatus status = 
-        protocol->Receive (p, ip.GetSource (), ip.GetDestination (), GetInterface (iif));
+        protocol->Receive (p, ip.GetSource (), ip.GetDestination (), incomingInterface);
       switch (status) {
       case Ipv4L4Protocol::RX_OK:
         // fall through
       case Ipv4L4Protocol::RX_CSUM_FAILED:
         break;
       case Ipv4L4Protocol::RX_ENDPOINT_UNREACH:
-        // XXX handle multi-interfaces
-        if (IsUnicast (ip.GetDestination (), GetInterface (iif)->GetAddress (0).GetMask ()))
+        // XXX handle multi-interface case
+        if (IsUnicast (ip.GetDestination (), incomingInterface->GetAddress (0).GetMask ()))
           {
             GetIcmp ()->SendDestUnreachPort (ip, copy);
           }
@@ -761,7 +921,32 @@
     }
 }
 
-uint32_t 
+void 
+Ipv4L3Protocol::JoinMulticastGroup (Ipv4Address origin, Ipv4Address group)
+{
+  NS_LOG_FUNCTION (this << origin << group);
+  m_multicastGroups.push_back(
+    std::pair<Ipv4Address, Ipv4Address> (origin, group));
+}
+
+void
+Ipv4L3Protocol::LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group)
+{
+  NS_LOG_FUNCTION (this << origin << group);
+
+  for (Ipv4MulticastGroupList::iterator i = m_multicastGroups.begin ();
+       i != m_multicastGroups.end (); 
+       i++)
+    {
+      if ((*i).first.IsEqual(origin) && (*i).second.IsEqual(group))
+        {
+          m_multicastGroups.erase (i);
+          return;
+        }
+    }
+}
+
+uint32_t
 Ipv4L3Protocol::AddAddress (uint32_t i, Ipv4InterfaceAddress address)
 {
   NS_LOG_FUNCTION (this << i << address);
@@ -769,7 +954,7 @@
   return interface->AddAddress (address);
 }
 
-Ipv4InterfaceAddress 
+Ipv4InterfaceAddress
 Ipv4L3Protocol::GetAddress (uint32_t interfaceIndex, uint32_t addressIndex) const
 {
   NS_LOG_FUNCTION (this << interfaceIndex << addressIndex);
@@ -777,7 +962,7 @@
   return interface->GetAddress (addressIndex);
 }
 
-uint32_t 
+uint32_t
 Ipv4L3Protocol::GetNAddresses (uint32_t interface) const
 {
   NS_LOG_FUNCTION (this << interface);
@@ -801,6 +986,76 @@
   return interface->GetMetric ();
 }
 
+bool
+Ipv4L3Protocol::GetInterfaceForDestination (
+  Ipv4Address destination, uint32_t& interface) const
+{
+  NS_LOG_FUNCTION (this << destination << &interface);
+//
+// The first thing we do in trying to determine a source address is to 
+// consult the routing protocols.  These will also check for a default route
+// if one has been set.
+//
+  for (Ipv4RoutingProtocolList::const_iterator i = m_routingProtocols.begin ();
+       i != m_routingProtocols.end (); 
+       i++)
+    {
+      NS_LOG_LOGIC ("Requesting Source Address");
+      uint32_t interfaceTmp;
+
+      if ((*i).second->RequestInterface (destination, interfaceTmp))
+        {
+          NS_LOG_LOGIC ("Found interface " << interfaceTmp);
+          interface = interfaceTmp;
+          return true;
+        }
+    }
+//
+// If there's no routing table entry telling us what *single* interface will 
+// be used to send a packet to this destination, we'll have to just pick one.  
+// If there's only one interface on this node, a good answer isn't very hard
+// to come up with.  Before jumping to any conclusions, remember that the 
+// zeroth interface is the loopback interface, so what we actually want is
+// a situation where there are exactly two interfaces on the node, in which
+// case interface one is the "single" interface connected to the outside world.
+//
+  if (GetNInterfaces () == 2)
+    {
+      NS_LOG_LOGIC ("One Interface.  Using interface 1.");
+      interface = 1;
+      return true;
+    }
+//
+// If we fall through to here, we have a node with multiple interfaces and
+// no routes to guide us in determining what interface to choose.  Either
+// no default route was found (for unicast or multicast), or in the case of a
+// multicast, the default route contained multiple outbound interfaces.
+//
+// The fallback position is to just get the unicast default route and use 
+// the outgoing interface specified there.  We don't want to leave the source
+// address unset, so we just assert here.
+//
+// N.B. that in the case of a multicast with a route containing multiple
+// outgoing interfaces, the source address of packets from that node will be
+// set to the IP address of the interface set in the default unicast route.
+// Also, in the case of a broadcast, the same will be true.
+//
+  NS_LOG_LOGIC ("Using default unicast route");
+  Ipv4Route *route = m_staticRouting->GetDefaultRoute ();
+
+  if (route == NULL)
+    {
+      NS_LOG_LOGIC ("Ipv4L3Protocol::GetInterfaceForDestination (): "
+                    "Unable to determine outbound interface.  No default route set");
+      return false;
+    }
+
+  interface = route->GetInterface ();
+
+  NS_LOG_LOGIC ("Default route specifies interface " << interface);
+  return true;
+}
+
 uint16_t 
 Ipv4L3Protocol::GetMtu (uint32_t i) const
 {
@@ -832,9 +1087,7 @@
       if (((interface->GetAddress (j).GetLocal ()) != (Ipv4Address ()))
           && (interface->GetAddress (j).GetMask ()) != (Ipv4Mask ()))
         {
-          NS_ASSERT_MSG (GetStaticRouting(), "SetUp:: No static routing");
-          GetStaticRouting ()->AddNetworkRouteTo (interface->GetAddress (j).GetLocal ().CombineMask (interface->GetAddress (j).GetMask ()),
-            interface->GetAddress (j).GetMask (), i);
+          AddNetworkRouteTo (interface->GetAddress (j).GetLocal ().CombineMask (interface->GetAddress (j).GetMask ()), interface->GetAddress (j).GetMask (), i);
         }
     }
 }
@@ -851,12 +1104,12 @@
   while (modified)
     {
       modified = false;
-      for (uint32_t i = 0; i < GetStaticRouting ()->GetNRoutes (); i++)
+      for (uint32_t i = 0; i < GetNRoutes (); i++)
         {
-          Ipv4RoutingTableEntry route = GetStaticRouting ()->GetRoute (i);
+          Ipv4Route route = GetRoute (i);
           if (route.GetInterface () == ifaceIndex)
             {
-              GetStaticRouting ()->RemoveRoute (i);
+              RemoveRoute (i);
               modified = true;
               break;
             }
@@ -864,23 +1117,43 @@
     }
 }
 
+// Note:  This method will be removed in Ipv4 routing work
+Ipv4Address
+Ipv4L3Protocol::GetSourceAddress (Ipv4Address destination) const
+{
+  uint32_t interface = 0xffffffff;
+
+  bool result = GetInterfaceForDestination (destination, interface);
+
+  if (result)
+    {
+      // if multiple addresses exist, search for the first one on the same subnet
+      for (uint32_t i = 0; i < GetNAddresses (interface); i++)
+        {
+          Ipv4InterfaceAddress ipv4InAddr = GetAddress (interface, i);
+          if (ipv4InAddr.GetLocal().CombineMask(ipv4InAddr.GetMask ()) == destination.CombineMask (ipv4InAddr.GetMask ()))
+            {
+              return ipv4InAddr.GetLocal ();
+            }
+        }
+      // Destination is off-link, so return first address.
+      return GetAddress (interface, 0).GetLocal ();
+    }
+  else
+    {
+//
+// If we can't find any address, just leave it 0.0.0.0
+//
+      return Ipv4Address::GetAny ();
+    }
+}
+
 Ptr<NetDevice>
 Ipv4L3Protocol::GetNetDevice (uint32_t i)
 {
   return GetInterface (i)-> GetDevice ();
 }
 
-void 
-Ipv4L3Protocol::SetIpForward (bool forward) 
-{
-  m_ipForward = forward;
-}
-
-bool 
-Ipv4L3Protocol::GetIpForward (void) const
-{
-  return m_ipForward;
-}
 
 
 }//namespace ns3
--- a/src/internet-stack/tcp-socket-impl.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/internet-stack/tcp-socket-impl.cc	Fri May 29 10:15:19 2009 +0400
@@ -563,6 +563,9 @@
       m_rxBufSize += i->second->GetSize()-avail;
     }
   }
+  SocketAddressTag tag;
+  tag.SetAddress (InetSocketAddress (m_remoteAddress, m_remotePort));
+  outPacket->AddPacketTag (tag);
   return outPacket;
 }
 
@@ -577,7 +580,7 @@
 
 Ptr<Packet>
 TcpSocketImpl::RecvFrom (uint32_t maxSize, uint32_t flags,
-  Address &fromAddress)
+                         Address &fromAddress)
 {
   NS_LOG_FUNCTION (this << maxSize << flags);
   Ptr<Packet> packet = Recv (maxSize, flags);
@@ -586,7 +589,7 @@
     {
       SocketAddressTag tag;
       bool found;
-      found = packet->FindFirstMatchingTag (tag);
+      found = packet->PeekPacketTag (tag);
       NS_ASSERT (found);
       fromAddress = tag.GetAddress ();
     }
@@ -1196,9 +1199,6 @@
       p = p->CreateFragment (0,s);
       m_nextRxSequence += s;           // Advance next expected sequence
       NS_LOG_LOGIC("Case 1, advanced nrxs to " << m_nextRxSequence );
-      SocketAddressTag tag;
-      tag.SetAddress (fromAddress);
-      p->AddTag (tag);
       //buffer this, it'll be read by call to Recv
       UnAckData_t::iterator i = 
           m_bufferedData.find (tcpHeader.GetSequenceNumber () );
@@ -1266,9 +1266,6 @@
           }
         }
       // Save for later delivery
-      SocketAddressTag tag;
-      tag.SetAddress (fromAddress);
-      p->AddTag (tag);
       m_bufferedData[startSeq] = p;  
       i = m_bufferedData.find (startSeq);
       next = i;
@@ -1295,9 +1292,6 @@
       p = p->CreateFragment (m_nextRxSequence - tcpHeader.GetSequenceNumber (),s);
       SequenceNumber start = m_nextRxSequence;
       m_nextRxSequence += s;           // Advance next expected sequence
-      SocketAddressTag tag;
-      tag.SetAddress (fromAddress);
-      p->AddTag (tag);
       //buffer the new fragment, it'll be read by call to Recv
       UnAckData_t::iterator i = m_bufferedData.find (start);
       if (i != m_bufferedData.end () ) //we found it already in the buffer
--- a/src/internet-stack/udp-socket-impl.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/internet-stack/udp-socket-impl.cc	Fri May 29 10:15:19 2009 +0400
@@ -23,8 +23,6 @@
 #include "ns3/inet-socket-address.h"
 #include "ns3/ipv4-route.h"
 #include "ns3/ipv4.h"
-#include "ns3/ipv4-header.h"
-#include "ns3/ipv4-routing-protocol.h"
 #include "ns3/udp-socket-factory.h"
 #include "ns3/trace-source-accessor.h"
 #include "udp-socket-impl.h"
@@ -72,7 +70,6 @@
 {
   NS_LOG_FUNCTION_NOARGS ();
 
-  // XXX todo:  leave any multicast groups that have been joined
   m_node = 0;
   if (m_endPoint != 0)
     {
@@ -311,6 +308,7 @@
       return -1;
     }
 
+  uint32_t localInterface;
   Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
 
   // Locally override the IP TTL for this socket
@@ -321,21 +319,22 @@
   // irrespective of what is set in these socket options.  So, this tagging  
   // may end up setting the TTL of a limited broadcast packet to be
   // the same as a unicast, but it will be fixed further down the stack
+  //NS_LOG_UNCOND ("IPttl: " << m_ipTtl);
   if (m_ipMulticastTtl != 0 && dest.IsMulticast ())
     {
       SocketIpTtlTag tag;
       tag.SetTtl (m_ipMulticastTtl);
-      p->AddTag (tag);
+      p->AddPacketTag (tag);
     }
   else if (m_ipTtl != 0 && !dest.IsMulticast () && !dest.IsBroadcast ())
     {
       SocketIpTtlTag tag;
       tag.SetTtl (m_ipTtl);
-      p->AddTag (tag);
+      p->AddPacketTag (tag);
     }
   {
     SocketSetDontFragmentTag tag;
-    bool found = p->FindFirstMatchingTag (tag);
+    bool found = p->RemovePacketTag (tag);
     if (!found)
       {
         if (m_mtuDiscover)
@@ -346,7 +345,7 @@
           {
             tag.Disable ();
           }
-        p->AddTag (tag);
+        p->AddPacketTag (tag);
       }
   }
   //
@@ -392,31 +391,14 @@
       NS_LOG_LOGIC ("Limited broadcast end.");
       return p->GetSize();
     }
-  else if (ipv4->GetRoutingProtocol () != 0)
+  else if (ipv4->GetInterfaceForDestination(dest, localInterface))
     {
-      Ipv4Header header;
-      header.SetDestination (dest);
-      Socket::SocketErrno errno;
-      Ptr<Ipv4Route> route;
-      uint32_t oif = 0; //specify non-zero if bound to a source address
-      // TBD-- we could cache the route and just check its validity
-      route = ipv4->GetRoutingProtocol ()->RouteOutput (header, oif, errno); 
-      if (route != 0)
-        {
-          NS_LOG_LOGIC ("Route exists");
-          header.SetSource (route->GetSource ());
-          m_udp->Send (p->Copy (), header.GetSource (), header.GetDestination (),
-                       m_endPoint->GetLocalPort (), port, route);
-          NotifyDataSent (p->GetSize ());
-          return p->GetSize();
-        }
-      else 
-        {
-          NS_LOG_LOGIC ("No route to destination");
-          NS_LOG_ERROR (errno);
-          m_errno = errno;
-          return -1;
-        }
+      NS_LOG_LOGIC ("Route exists");
+      m_udp->Send (p->Copy (), ipv4->GetSourceAddress (dest), dest,
+		   m_endPoint->GetLocalPort (), port);
+      NotifyDataSent (p->GetSize ());
+      NotifySend (GetTxAvailable ());
+      return p->GetSize();;
     }
   else
    {
@@ -482,7 +464,7 @@
 
 Ptr<Packet>
 UdpSocketImpl::RecvFrom (uint32_t maxSize, uint32_t flags, 
-  Address &fromAddress)
+                         Address &fromAddress)
 {
   NS_LOG_FUNCTION (this << maxSize << flags);
   Ptr<Packet> packet = Recv (maxSize, flags);
@@ -490,7 +472,7 @@
     {
       SocketAddressTag tag;
       bool found;
-      found = packet->FindFirstMatchingTag (tag);
+      found = packet->PeekPacketTag (tag);
       NS_ASSERT (found);
       fromAddress = tag.GetAddress ();
     }
@@ -512,34 +494,6 @@
   return 0;
 }
 
-int 
-UdpSocketImpl::MulticastJoinGroup (uint32_t interface, const Address &groupAddress)
-{
-  NS_LOG_FUNCTION (interface << groupAddress);
-  /*
-   1) sanity check interface
-   2) sanity check that it has not been called yet on this interface/group
-   3) determine address family of groupAddress
-   4) locally store a list of (interface, groupAddress)
-   5) call ipv4->MulticastJoinGroup () or Ipv6->MulticastJoinGroup ()
-  */
-  return 0;
-} 
-
-int 
-UdpSocketImpl::MulticastLeaveGroup (uint32_t interface, const Address &groupAddress) 
-{
-  NS_LOG_FUNCTION (interface << groupAddress);
-  /*
-   1) sanity check interface
-   2) determine address family of groupAddress
-   3) delete from local list of (interface, groupAddress); raise a LOG_WARN
-      if not already present (but return 0) 
-   5) call ipv4->MulticastLeaveGroup () or Ipv6->MulticastLeaveGroup ()
-  */
-  return 0;
-}
-
 void 
 UdpSocketImpl::ForwardUp (Ptr<Packet> packet, Ipv4Address ipv4, uint16_t port)
 {
@@ -554,7 +508,7 @@
       Address address = InetSocketAddress (ipv4, port);
       SocketAddressTag tag;
       tag.SetAddress (address);
-      packet->AddTag (tag);
+      packet->AddPacketTag (tag);
       m_deliveryQueue.push (packet);
       m_rxAvailable += packet->GetSize ();
       NotifyDataRecv ();
@@ -598,54 +552,30 @@
 }
 
 void 
-UdpSocketImpl::SetIpTtl (uint8_t ipTtl)
+UdpSocketImpl::SetIpTtl (uint32_t ipTtl)
 {
   m_ipTtl = ipTtl;
 }
 
-uint8_t 
+uint32_t 
 UdpSocketImpl::GetIpTtl (void) const
 {
   return m_ipTtl;
 }
 
 void 
-UdpSocketImpl::SetIpMulticastTtl (uint8_t ipTtl)
+UdpSocketImpl::SetIpMulticastTtl (uint32_t ipTtl)
 {
   m_ipMulticastTtl = ipTtl;
 }
 
-uint8_t 
+uint32_t 
 UdpSocketImpl::GetIpMulticastTtl (void) const
 {
   return m_ipMulticastTtl;
 }
 
 void 
-UdpSocketImpl::SetIpMulticastIf (int32_t ipIf)
-{
-  m_ipMulticastIf = ipIf;
-}
-
-int32_t 
-UdpSocketImpl::GetIpMulticastIf (void) const
-{
-  return m_ipMulticastIf;
-}
-
-void 
-UdpSocketImpl::SetIpMulticastLoop (bool loop)
-{
-  m_ipMulticastLoop = loop;
-}
-
-bool 
-UdpSocketImpl::GetIpMulticastLoop (void) const
-{
-  return m_ipMulticastLoop;
-}
-
-void 
 UdpSocketImpl::SetMtuDiscover (bool discover)
 {
   m_mtuDiscover = discover;
@@ -658,3 +588,207 @@
 
 
 } //namespace ns3
+
+
+#ifdef RUN_SELF_TESTS
+
+#include "ns3/test.h"
+#include "ns3/socket-factory.h"
+#include "ns3/udp-socket-factory.h"
+#include "ns3/simulator.h"
+#include "ns3/simple-channel.h"
+#include "ns3/simple-net-device.h"
+#include "ns3/drop-tail-queue.h"
+#include "internet-stack.h"
+#include <string>
+
+namespace ns3 {
+
+class UdpSocketImplTest: public Test
+{
+  Ptr<Packet> m_receivedPacket;
+  Ptr<Packet> m_receivedPacket2;
+
+public:
+  virtual bool RunTests (void);
+  UdpSocketImplTest ();
+
+  void ReceivePacket (Ptr<Socket> socket, Ptr<Packet> packet, const Address &from);
+  void ReceivePacket2 (Ptr<Socket> socket, Ptr<Packet> packet, const Address &from);
+  void ReceivePkt (Ptr<Socket> socket);
+  void ReceivePkt2 (Ptr<Socket> socket);
+};
+
+
+UdpSocketImplTest::UdpSocketImplTest ()
+  : Test ("UdpSocketImpl") 
+{
+}
+
+void UdpSocketImplTest::ReceivePacket (Ptr<Socket> socket, Ptr<Packet> packet, const Address &from)
+{
+  m_receivedPacket = packet;
+}
+
+void UdpSocketImplTest::ReceivePacket2 (Ptr<Socket> socket, Ptr<Packet> packet, const Address &from)
+{
+  m_receivedPacket2 = packet;
+}
+
+void UdpSocketImplTest::ReceivePkt (Ptr<Socket> socket)
+{
+  uint32_t availableData;
+  availableData = socket->GetRxAvailable ();
+  m_receivedPacket = socket->Recv (std::numeric_limits<uint32_t>::max(), 0);
+  NS_ASSERT (availableData == m_receivedPacket->GetSize ());
+}
+
+void UdpSocketImplTest::ReceivePkt2 (Ptr<Socket> socket)
+{
+  uint32_t availableData;
+  availableData = socket->GetRxAvailable ();
+  m_receivedPacket2 = socket->Recv (std::numeric_limits<uint32_t>::max(), 0);
+  NS_ASSERT (availableData == m_receivedPacket2->GetSize ());
+}
+
+bool
+UdpSocketImplTest::RunTests (void)
+{
+  bool result = true;
+
+  // Create topology
+  
+  // Receiver Node
+  Ptr<Node> rxNode = CreateObject<Node> ();
+  AddInternetStack (rxNode);
+  Ptr<SimpleNetDevice> rxDev1, rxDev2;
+  { // first interface
+    rxDev1 = CreateObject<SimpleNetDevice> ();
+    rxDev1->SetAddress (Mac48Address::Allocate ());
+    rxNode->AddDevice (rxDev1);
+    Ptr<Ipv4> ipv4 = rxNode->GetObject<Ipv4> ();
+    uint32_t netdev_idx = ipv4->AddInterface (rxDev1);
+    Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.0.1"), Ipv4Mask (0xffff0000U));
+    ipv4->AddAddress (netdev_idx, ipv4Addr);
+    ipv4->SetUp (netdev_idx);
+  }
+
+  { // second interface
+    rxDev2 = CreateObject<SimpleNetDevice> ();
+    rxDev2->SetAddress (Mac48Address::Allocate ());
+    rxNode->AddDevice (rxDev2);
+    Ptr<Ipv4> ipv4 = rxNode->GetObject<Ipv4> ();
+    uint32_t netdev_idx = ipv4->AddInterface (rxDev2);
+    Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.1.1"), Ipv4Mask (0xffff0000U));
+    ipv4->AddAddress (netdev_idx, ipv4Addr);
+    ipv4->SetUp (netdev_idx);
+  }
+  
+  // Sender Node
+  Ptr<Node> txNode = CreateObject<Node> ();
+  AddInternetStack (txNode);
+  Ptr<SimpleNetDevice> txDev1;
+  {
+    txDev1 = CreateObject<SimpleNetDevice> ();
+    txDev1->SetAddress (Mac48Address::Allocate ());
+    txNode->AddDevice (txDev1);
+    Ptr<Ipv4> ipv4 = txNode->GetObject<Ipv4> ();
+    uint32_t netdev_idx = ipv4->AddInterface (txDev1);
+    Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.0.2"), Ipv4Mask (0xffff0000U));
+    ipv4->AddAddress (netdev_idx, ipv4Addr);
+    ipv4->SetUp (netdev_idx);
+  }
+  Ptr<SimpleNetDevice> txDev2;
+  {
+    txDev2 = CreateObject<SimpleNetDevice> ();
+    txDev2->SetAddress (Mac48Address::Allocate ());
+    txNode->AddDevice (txDev2);
+    Ptr<Ipv4> ipv4 = txNode->GetObject<Ipv4> ();
+    uint32_t netdev_idx = ipv4->AddInterface (txDev2);
+    Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.1.2"), Ipv4Mask (0xffff0000U));
+    ipv4->AddAddress (netdev_idx, ipv4Addr);
+    ipv4->SetUp (netdev_idx);
+  }
+
+  // link the two nodes
+  Ptr<SimpleChannel> channel1 = CreateObject<SimpleChannel> ();
+  rxDev1->SetChannel (channel1);
+  txDev1->SetChannel (channel1);
+
+  Ptr<SimpleChannel> channel2 = CreateObject<SimpleChannel> ();
+  rxDev2->SetChannel (channel2);
+  txDev2->SetChannel (channel2);
+
+
+  // Create the UDP sockets
+  Ptr<SocketFactory> rxSocketFactory = rxNode->GetObject<UdpSocketFactory> ();
+  Ptr<Socket> rxSocket = rxSocketFactory->CreateSocket ();
+  NS_TEST_ASSERT_EQUAL (rxSocket->Bind (InetSocketAddress (Ipv4Address ("10.0.0.1"), 1234)), 0);
+  rxSocket->SetRecvCallback (MakeCallback (&UdpSocketImplTest::ReceivePkt, this));
+
+  Ptr<Socket> rxSocket2 = rxSocketFactory->CreateSocket ();
+  rxSocket2->SetRecvCallback (MakeCallback (&UdpSocketImplTest::ReceivePkt2, this));
+  NS_TEST_ASSERT_EQUAL (rxSocket2->Bind (InetSocketAddress (Ipv4Address ("10.0.1.1"), 1234)), 0);
+
+  Ptr<SocketFactory> txSocketFactory = txNode->GetObject<UdpSocketFactory> ();
+  Ptr<Socket> txSocket = txSocketFactory->CreateSocket ();
+
+  // ------ Now the tests ------------
+
+  // Unicast test
+  m_receivedPacket = Create<Packet> ();
+  m_receivedPacket2 = Create<Packet> ();
+  NS_TEST_ASSERT_EQUAL (txSocket->SendTo ( Create<Packet> (123), 0, 
+    InetSocketAddress (Ipv4Address("10.0.0.1"), 1234)), 123);
+  Simulator::Run ();
+  NS_TEST_ASSERT_EQUAL (m_receivedPacket->GetSize (), 123);
+  NS_TEST_ASSERT_EQUAL (m_receivedPacket2->GetSize (), 0); // second interface should receive it
+
+  m_receivedPacket->RemoveAllPacketTags ();
+  m_receivedPacket2->RemoveAllPacketTags ();
+
+  // Simple broadcast test
+
+  m_receivedPacket = Create<Packet> ();
+  m_receivedPacket2 = Create<Packet> ();
+  NS_TEST_ASSERT_EQUAL (txSocket->SendTo ( Create<Packet> (123), 0, 
+    InetSocketAddress (Ipv4Address("255.255.255.255"), 1234)), 123);
+  Simulator::Run ();
+  NS_TEST_ASSERT_EQUAL (m_receivedPacket->GetSize (), 123);
+  // second socket should not receive it (it is bound specifically to the second interface's address
+  NS_TEST_ASSERT_EQUAL (m_receivedPacket2->GetSize (), 0);
+
+  m_receivedPacket->RemoveAllPacketTags ();
+  m_receivedPacket2->RemoveAllPacketTags ();
+
+  // Broadcast test with multiple receiving sockets
+
+  // When receiving broadcast packets, all sockets sockets bound to
+  // the address/port should receive a copy of the same packet -- if
+  // the socket address matches.
+  rxSocket2->Dispose ();
+  rxSocket2 = rxSocketFactory->CreateSocket ();
+  rxSocket2->SetRecvCallback (MakeCallback (&UdpSocketImplTest::ReceivePkt2, this));
+  NS_TEST_ASSERT_EQUAL (rxSocket2->Bind (InetSocketAddress (Ipv4Address ("0.0.0.0"), 1234)), 0);
+
+  m_receivedPacket = Create<Packet> ();
+  m_receivedPacket2 = Create<Packet> ();
+  NS_TEST_ASSERT_EQUAL (txSocket->SendTo (Create<Packet> (123), 0,
+InetSocketAddress (Ipv4Address("255.255.255.255"), 1234)), 123);
+  Simulator::Run ();
+  NS_TEST_ASSERT_EQUAL (m_receivedPacket->GetSize (), 123);
+  NS_TEST_ASSERT_EQUAL (m_receivedPacket2->GetSize (), 123);
+
+  m_receivedPacket->RemoveAllPacketTags ();
+  m_receivedPacket2->RemoveAllPacketTags ();
+
+  Simulator::Destroy ();
+
+  return result;
+}
+
+static UdpSocketImplTest gUdpSocketImplTest;
+
+}; // namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- a/src/node/address.h	Thu May 28 21:41:45 2009 -0700
+++ b/src/node/address.h	Fri May 29 10:15:19 2009 +0400
@@ -91,7 +91,7 @@
    * can be stored in an Address instance.
    */
   enum MaxSize_e {
-    MAX_SIZE = 30
+    MAX_SIZE = 20
   };
 
   /**
--- a/src/node/packet-socket.cc	Thu May 28 21:41:45 2009 -0700
+++ b/src/node/packet-socket.cc	Fri May 29 10:15:19 2009 +0400
@@ -52,7 +52,7 @@
 
 PacketSocket::PacketSocket () : m_rxAvailable (0)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this);
   m_state = STATE_OPEN;
   m_shutdownSend = false;
   m_shutdownRecv = false;
@@ -64,40 +64,40 @@
 void 
 PacketSocket::SetNode (Ptr<Node> node)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this << node);
   m_node = node;
 }
 
 PacketSocket::~PacketSocket ()
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this);
 }
 
 void 
 PacketSocket::DoDispose (void)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this);
   m_device = 0;
 }
 
 enum Socket::SocketErrno
 PacketSocket::GetErrno (void) const
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this);
   return m_errno;
 }
 
 Ptr<Node>
 PacketSocket::GetNode (void) const
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this);
   return m_node;
 }
 
 int
 PacketSocket::Bind (void)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this);
   PacketSocketAddress address;
   address.SetProtocol (0);
   address.SetAllDevices ();
@@ -107,7 +107,7 @@
 int
 PacketSocket::Bind (const Address &address)
 { 
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this << address);
   if (!PacketSocketAddress::IsMatchingType (address))
     {
       m_errno = ERROR_INVAL;
@@ -120,7 +120,7 @@
 int
 PacketSocket::DoBind (const PacketSocketAddress &address)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this << address);
   if (m_state == STATE_BOUND ||
       m_state == STATE_CONNECTED)
     {
@@ -153,7 +153,7 @@
 int
 PacketSocket::ShutdownSend (void)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this);
   if (m_state == STATE_CLOSED)
     {
       m_errno = ERROR_BADF;
@@ -166,7 +166,7 @@
 int
 PacketSocket::ShutdownRecv (void)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this);
   if (m_state == STATE_CLOSED)
     {
       m_errno = ERROR_BADF;
@@ -179,7 +179,7 @@
 int
 PacketSocket::Close(void)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this);
   if (m_state == STATE_CLOSED)
     {
       m_errno = ERROR_BADF;
@@ -192,7 +192,7 @@
 int
 PacketSocket::Connect(const Address &ad)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this << ad);
   PacketSocketAddress address;
   if (m_state == STATE_CLOSED)
     {
@@ -233,7 +233,7 @@
 int
 PacketSocket::Send (Ptr<Packet> p, uint32_t flags)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this << p << flags);
   if (m_state == STATE_OPEN ||
       m_state == STATE_BOUND)
     {
@@ -278,7 +278,7 @@
 int
 PacketSocket::SendTo (Ptr<Packet> p, uint32_t flags, const Address &address)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this << p << flags << address);
   PacketSocketAddress ad;
   if (m_state == STATE_CLOSED)
     {
@@ -351,7 +351,7 @@
                          uint16_t protocol, const Address &from,
                          const Address &to, NetDevice::PacketType packetType)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this << device << packet << protocol << from << to << packetType);
   if (m_shutdownRecv)
     {
       return;
@@ -365,10 +365,11 @@
 
   if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize)
     {
+      Ptr<Packet> copy = packet->Copy ();
       SocketAddressTag tag;
       tag.SetAddress (address);
-      packet->AddTag (tag);
-      m_deliveryQueue.push (packet->Copy ());
+      copy->AddPacketTag (tag);
+      m_deliveryQueue.push (copy);
       m_rxAvailable += packet->GetSize ();
       NS_LOG_LOGIC ("UID is " << packet->GetUid() << " PacketSocket " << this);
       NotifyDataRecv ();
@@ -388,7 +389,7 @@
 uint32_t
 PacketSocket::GetRxAvailable (void) const
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this);
   // We separately maintain this state to avoid walking the queue 
   // every time this might be called
   return m_rxAvailable;
@@ -397,7 +398,7 @@
 Ptr<Packet> 
 PacketSocket::Recv (uint32_t maxSize, uint32_t flags)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this << maxSize << flags);
   if (m_deliveryQueue.empty() )
     {
       return 0;
@@ -418,13 +419,13 @@
 Ptr<Packet>
 PacketSocket::RecvFrom (uint32_t maxSize, uint32_t flags, Address &fromAddress)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this << maxSize << flags << fromAddress);
   Ptr<Packet> packet = Recv (maxSize, flags);
   if (packet != 0)
     {
       SocketAddressTag tag;
       bool found;
-      found = packet->FindFirstMatchingTag (tag);
+      found = packet->PeekPacketTag (tag);
       NS_ASSERT (found);
       fromAddress = tag.GetAddress ();
     }
@@ -434,7 +435,7 @@
 int
 PacketSocket::GetSockName (Address &address) const
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (this << address);
   PacketSocketAddress ad = PacketSocketAddress::ConvertFrom(address);
   
   ad.SetProtocol (m_protocol);
--- a/src/wscript	Thu May 28 21:41:45 2009 -0700
+++ b/src/wscript	Fri May 29 10:15:19 2009 +0400
@@ -33,6 +33,8 @@
     'helper',
     'contrib/stats',
     'applications/v4ping',
+    'devices/mesh',
+    'devices/mesh/dot11s',
     )
 
 def set_options(opt):
--- a/utils/bench-packets.cc	Thu May 28 21:41:45 2009 -0700
+++ b/utils/bench-packets.cc	Fri May 29 10:15:19 2009 +0400
@@ -168,14 +168,14 @@
 
   for (uint32_t i = 0; i < n; i++) {
     Ptr<Packet> p = Create<Packet> (2000);
-    p->AddTag (tag1);
+    p->AddPacketTag (tag1);
     p->AddHeader (udp);
-    p->FindFirstMatchingTag (tag1);
-    p->AddTag (tag2);
+    p->RemovePacketTag (tag1);
+    p->AddPacketTag (tag2);
     p->AddHeader (ipv4);
     Ptr<Packet> o = p->Copy ();
     o->RemoveHeader (ipv4);
-    p->FindFirstMatchingTag (tag2);
+    p->RemovePacketTag (tag2);
     o->RemoveHeader (udp);
   }
 }