zigbee: Add Groupcast (Multicast) support

This commit is contained in:
Alberto Gallegos Ramonet
2025-07-25 16:07:42 +09:00
parent 50fe52d74d
commit 711a55857f
14 changed files with 1186 additions and 276 deletions

View File

@@ -20,10 +20,11 @@ This file is a best-effort approach to solving this issue; we will do our best b
### Changes to existing API
* (antenna) Reformatted documentation
* (antenna) Reformatted documentation.
* (internet) Added check for longest prefix match in GlobalRouting.
* (lr-wpan) Debloat MAC PD-DATA.indication and reduce packet copies.
* (zigbee) Added group table
* (internet) Added check for longest prefix match in GlobalRouting
* (zigbee) Added group table.
* (zigbee) Added Groupcast (Multicast) support.
### Changes to build system

View File

@@ -35,6 +35,7 @@ ns-3 has switched to the C++23 standard by default.
- (antenna) !2516 - Reformatted documentation
- (core) A stacktrace will now be printed on fatal errors in supported platforms.
- (wifi) !2524 - Fix corrupted radiotap header when EHT is used.
- (zigbee) !2512 - Added Groupcast (Multicast) support
### Bugs fixed

View File

@@ -55,11 +55,13 @@ The NWK has the following limitations:
- Address duplication detection is not supported.
- Beacon mode is not througly tested.
- 16-bit address resolution from a IEEE address at NWK layer is not supported.
- Route Maintenance is not supported.
The APS has the following limitations:
- No groupcasting support (Similar to multicast)
- No binding table support
- No security handling
- No fragmentation support
- No duplicates detection
- No acknowledged transmissions
@@ -82,13 +84,13 @@ These primitives are implemented in |ns3| with a combination of functions and ca
The following is a list of NWK primitives supported:
- NLME-NETWORK-DISCOVERY (Request, Confirm)
- NLME-ROUTE-DISCOVERY (Request, Confirm)
- NLME-NETWORK-FORMATION (Request, Confirm)
- NLME-JOIN (Request, Confirm, Indication)
- NLME-DIRECT-JOIN (Request, Confirm)
- NLME-START-ROUTER (Request, Confirm)
- NLDE-DATA (Request, Confirm, Indication)
- ``NLME-NETWORK-DISCOVERY`` (Request, Confirm)
- ``NLME-ROUTE-DISCOVERY`` (Request, Confirm)
- ``NLME-NETWORK-FORMATION`` (Request, Confirm)
- ``NLME-JOIN`` (Request, Confirm, Indication)
- ``NLME-DIRECT-JOIN`` (Request, Confirm)
- ``NLME-START-ROUTER`` (Request, Confirm)
- ``NLDE-DATA`` (Request, Confirm, Indication)
For details on how to use these primitives, please consult the Zigbee Pro specification.
@@ -98,7 +100,7 @@ must interact directly with the NWK.
The following is a brief explanation of how users can interact with the NWK and what are the supported capabilities.
Network joining
Network Joining
~~~~~~~~~~~~~~~
In a Zigbee network, before devices attempt to exchange data with one another, they must first be organized and related to one another based on their specific roles.
@@ -111,7 +113,8 @@ There are three primary roles in a Zigbee network:
Devices must first join a Zigbee network before they can upgrade their roles to either routers or remain as end devices.
There are two ways for devices to join a Zigbee network: they can either go through the MAC association process or directly join the network.
**MAC Association Join**
MAC Association Join
^^^^^^^^^^^^^^^^^^^^
This method is the default approach used by Zigbee. As the name suggests, it utilizes the underlying MAC layer association mechanism to connect to the Zigbee network.
For a comprehensive explanation of the association mechanism occurring in the MAC, please refer to the lr-wpan model documentation.
@@ -119,17 +122,17 @@ For a comprehensive explanation of the association mechanism occurring in the MA
When employing the association mechanism, devices communicate with each other to join an existing network via the network coordinator or a designated router within the network.
As a result of this joining process, devices are assigned a short address (16-bit address) that they use for routing and data exchange operations. Below is a summary of the MAC association join process:
1. At least one coordinator must be operational and capable of receiving join requests (i.e. A device successfully completed a `NLME-NETWORK-FORMATION.request` primitive).
2. Devices must issue a `NLME-NETWORK-DISCOVERY.request` to look for candidate coordinators/routers to join. The parameters channel numbers (represented by a bitmap for channels 11-26) and scan duration (ranging from 0 to 14) must also be specified to define the channel in which the device will search for a coordinator or router and the duration of that search.
1. At least one coordinator must be operational and capable of receiving join requests (i.e. A device successfully completed a ``NLME-NETWORK-FORMATION.request`` primitive).
2. Devices must issue a ``NLME-NETWORK-DISCOVERY.request`` to look for candidate coordinators/routers to join. The parameters channel numbers (represented by a bitmap for channels 11-26) and scan duration (ranging from 0 to 14) must also be specified to define the channel in which the device will search for a coordinator or router and the duration of that search.
3. If a coordinator (or a capable router) is found on the designated channel and within communication range, it will respond to the device's request with a beacon that contains both a PAN descriptor and a beacon payload describing the capabilities of the coordinator or router.
4. Upon receiving these beacons, the device will select "the most ideal coordinator or router candidate" to join.
5. After selecting the candidate, devices must issue a `NLME-JOIN.request` primitive with the network parameter set to `ASSOCIATION`. This will initiate the join process.
5. After selecting the candidate, devices must issue a ``NLME-JOIN.request`` primitive with the network parameter set to ``ASSOCIATION``. This will initiate the join process.
6. If the association is successful, the device will receive a confirmation from the coordinator or router, along with a short address that the device will use for its operations within the Zigbee network.
7. Short addresses are assigned by the coordinator randomly, which means there could be instances of address duplication. Although the Zigbee specification includes a mechanism for detecting address duplication, this feature is not currently supported in this implementation.
8. If the association request fails, the device will receive a confirmation with a status indicating failure, rather than `SUCCESSFUL`, and the short address FF:FF will be received (indicating that the device is not associated).
8. If the association request fails, the device will receive a confirmation with a status indicating failure, rather than ``SUCCESSFUL``, and the short address FF:FF will be received (indicating that the device is not associated).
Note: The process described above outlines the steps for joining the network using a MAC association join.
However, devices that are required to act as routers must also issue an additional `NLME-START-ROUTER.request` primitive after joining the network in order to begin functioning as routers.
However, devices that are required to act as routers must also issue an additional ``NLME-START-ROUTER.request`` primitive after joining the network in order to begin functioning as routers.
In |ns3|, Zigbee NWK, coordinators or routers can be found using the following primitive::
@@ -158,8 +161,8 @@ In |ns3| a Zigbee NWK join request (using MAC association) is used as follows::
See zigbee/examples for detailed examples using network joining.
**Direct Join (a.k.a. Orphaning process)**
Direct Join (a.k.a. Orphaning process)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Direct Join is employed when the number of nodes in the network and their relationships are known in advance.
As the name suggests, this method involves registering devices directly with a coordinator or router.
Subsequently, these devices confirm their registration with the coordinator to receive a network address.
@@ -167,12 +170,12 @@ Subsequently, these devices confirm their registration with the coordinator to r
This process is simpler than the association method of joining a network, but it is less flexible since it requires manual intervention.
Below is a summary of the direct join process:
1. If a coordinator device or router is already operational, devices that can communicate with this coordinator must be manually registered using the primitive `NLME-DIRECT-JOIN.request`.
2. After this registration, the devices registered in step 1 will send a `NLME-JOIN.request` with the rejoin network parameter set to `DIRECT_OR_REJOIN`. This action triggers a MAC orphaning request message, which is used to confirm the device's existence with the coordinator.
1. If a coordinator device or router is already operational, devices that can communicate with this coordinator must be manually registered using the primitive ``NLME-DIRECT-JOIN.request``.
2. After this registration, the devices registered in step 1 will send a ``NLME-JOIN.request`` with the rejoin network parameter set to ``DIRECT_OR_REJOIN``. This action triggers a MAC orphaning request message, which is used to confirm the device's existence with the coordinator.
3. The coordinator or router will respond to the orphaning message by providing an assigned short address.
4. The device accepts this short address and successfully joins the network.
Similar to the MAC association mechanism, devices that want to function as routers must issue an additional `NLME-START-ROUTER.request` once the joining process is completed.
Similar to the MAC association mechanism, devices that want to function as routers must issue an additional ``NLME-START-ROUTER.request`` once the joining process is completed.
In |ns3|, a direct join primitive is used as follows::
@@ -209,7 +212,8 @@ Despite the common belief that the routing protocol contained in Zigbee is AODV,
In fact, Zigbee supports not one but 4 different methods of routing: Mesh routing, Many-To-One routing, Source routing, and Tree routing.
From these routing protocols, the current |ns3| implementation only supports the first two.
**Many-To-One Routing**
Many-To-One Routing
^^^^^^^^^^^^^^^^^^^
In Zigbee networks, it's common for multiple nodes to need to communicate with a single node, often referred to as a concentrator.
If all nodes perform a Mesh route discovery for this single point in the network, it can lead to an overwhelming number of route request messages, which may degrade network performance.
@@ -241,12 +245,13 @@ In |ns3|, Many-To-One routing is achieved by using the ``NLME-ROUTE-DISCOVERY.re
zstack->GetNwk()->NlmeRouteDiscoveryRequest(routeDiscParams);
.. note::
Important: The process described above assumes that devices have already joined the network.
The process described above assumes that devices have already joined the network.
A route discovery request issued before a device is part of the network (join process) will result in failure.
**Mesh Routing**
Mesh Routing
^^^^^^^^^^^^
Mesh routing in Zigbee is often attributed to the mechanisms used by the AODV routing protocol (`RFC 3561 <https://datatracker.ietf.org/doc/html/rfc3561>`_).
Mesh routing in Zigbee is often attributed to the mechanisms used by the AODV routing protocol (:rfc3561).
Although Zigbee mesh routing and the AODV protocol share some similarities, there are significant differences between them that directly influence performance.
Firstly, AODV was designed for IP-based networks, whereas Zigbee operates without the concept of IP addresses, thus eliminating their associated overhead.
@@ -309,37 +314,140 @@ Alternatively, a Mesh route discovery can be performed along a data transmission
zstack->GetNwk()->NldeDataRequest(dataReqParams, p);
.. note::
Important: The process described above assumes that devices have already joined the network.
The process described above assumes that devices have already joined the network.
A route discovery request issued before a device is part of the network (join process) will result in failure.
The application support sub-layer (APS)
---------------------------------------
As its name suggests, this intermediate layer exists between the Network (NWK) layer and the Application Framework (AF).
As its name suggests, the APS (Application Support) layer acts as an intermediate layer between the Network (NWK) layer and the Application Framework (AF).
It provides services to both the Zigbee Device Object (ZDO) and the AF.
The APS layer introduces abstract concepts such as **EndPoints**, **Clusters**, and **Profiles**; however, it does not assign specific meanings to these concepts.
Instead, it simply adds this information to the transmitted frames.
Effective management of **EndPoints**, **Clusters**, and **Profile IDs** requires the use of the Zigbee Cluster Library (ZCL) and the ZDO, which are not currently supported by this implementation.
This implementation offers only the most basic functions of the APS, allowing data transmission using known 16-bit address destinations.
Features such as groupcasting, transmission to IEEE addresses (64-bit address destinations), fragmentation, duplication detection, and security are not currently supported but are under development.
The primary functions of the APS layer include:
By default, the APS layer is integrated within the Zigbee stack.
- Handling security and data integrity through encryption and decryption of data.
- Managing the binding table, which establishes relationships between devices.
- Managing the group table, which facilitates group destinations similar to multicast groups.
- Offering various data transmission modes, such as unicast, broadcast, and groupcast.
- Detecting and filtering duplicate data transmissions.
- Managing the fragmentation and reassembly of data packets.
- Providing a mechanism for data acknowledgment and retransmission.
The APS layer introduces abstract concepts such as **EndPoints**, **Clusters**, and **Profiles**.
However, it does not assign specific meanings to these concepts; instead, it simply adds ID information to the transmitted frames.
Effective interpretation and management of **EndPoints**, **Clusters**, and **Profile IDs** require the use of the Zigbee Cluster Library (ZCL) and the ZDO, which are not currently supported in this implementation.
Similarly, the APS layer can transmit data that includes information about source and destination endpoints, but it cannot initiate network formation or joining procedures. Typically, these processes are managed by the ZDO; however, since the ZDO is currently unavailable, users must interact directly with the NWK layers network formation and joining primitives to initiate these options.
This implementation provides only the most basic functions of the APS, enabling data transmission using 16-bit or group address destinations.
Features such as transmission to IEEE addresses (64-bit address destinations), fragmentation, duplication detection, and security are not currently supported.
By default, the APS layer is integrated and active within the Zigbee stack.
However, users can choose to work solely with the NWK layer.
To do this, they must disable the APS by using the `SetNwkLayerOnly()` function in the Zigbee helper.
To do this, they must disable the APS by using the ``SetNwkLayerOnly()`` function in the Zigbee helper.
The APS layer can transmit data that includes information regarding source and destination endpoints, but it cannot initiate network formation or network joining procedures.
Typically, the ZDO manages these processes; however, since we currently do not have the ZDO, users must directly interact with the NWK layers network formation and joining primitives to trigger these options.
The following is a list of APS primitives are included:
- APSDE-DATA (Request, Confirm, Indication) <------ Only Address mode 0x02 (16-bit address and destination endpoint present) supported.
- APSME-BIND (Request, Confirm) <----Included but inconsequential without group table support
- APSME-UNBIND (Request, Confirm) <----Included but inconsequential without group table support
- ``APSDE-DATA`` (Request, Confirm, Indication) : Only Address mode 0x01 and 0x02 (Regular unicast and groupcast) supported.
- ``APSME-BIND`` (Request, Confirm)
- ``APSME-UNBIND`` (Request, Confirm)
- ``APSME-ADD-GROUP`` (Request, Confirm)
- ``APSME-REMOVE-GROUP`` (Request, Confirm)
- ``APSME-REMOVE-ALL-GROUPS`` (Request, Confirm)
Data Transmission
~~~~~~~~~~~~~~~~~
The APS layer must transmit data using the ``APSD-DATA.request`` primitive. This primitive supports 4 types of destination address modes:
- **0x00**: No address (Use Binding table to establish destinations) <Not supported>
- **0x01**: Group address (Groupcasting)
- **0x02**: 16-bit address with destination endpoint present (Regular Unicast or Broadcast)
- **0x03**: 64-bit address with destination endpoint not present (Regular Unicast) <Not supported>
GroupCasting (Address Mode: 0x01)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Group casting (Multicasting) is a method of transmitting data to multiple devices endpoints within a specific group.
This is particularly useful in scenarios where a device needs to send the same data to multiple endpoints simultaneously,
such as in lighting control systems or sensor networks.
In Zigbee, group addresses are used to facilitate this type of communication.
The APS layer manages group addresses and ensures that data is delivered to all devices in the group.
To use group casting, devices must first be added to a group. This is done using the ``APSME-ADD-GROUP`` primitive, which allows a device to join a group by specifying the group ID.::
// Multiple groups can be added to the same device.
// Multiple endpoints can be added to the same group.
// The group address is a 16-bit address.
// In this example, group [BE:EF] and endpoint 5 is added to a device.
ApsmeGroupRequestParams groupParams;
groupParams.m_groupAddress = Mac16Address("BE:EF");
groupParams.m_endPoint = 5;
zstack->GetNwk()->GetAps()->ApsmeAddGroupRequest(groupParams);
Once a device is part of a group, any device can send data to ALL the endpoints in the group using the APSDE-DATA.request primitive with
the destination address mode ``GROUP_ADDR_DST_ENDPOINT_NOT_PRESENT`` (i.e., 0x01 address mode) and the appropriate group address.::
// The message will be delivered to ALL the endpoints in any device in the network
// that is part of the group [BE:EF].
ApsdeDataRequestParams dataReqParams;
ZigbeeApsTxOptions txOptions;
dataReqParams.m_useAlias = false;
// Default, use 16 bit address destination (No option), equivalent to 0x00
dataReqParams.m_txOptions = txOptions.GetTxOptions();
dataReqParams.m_srcEndPoint = 4; // Arbitrary value, must not be 0
dataReqParams.m_clusterId = 5; // Arbitrary value (depends on the application)
dataReqParams.m_profileId = 2; // Arbitrary value (depends on the application)
dataReqParams.m_dstAddrMode = ApsDstAddressMode::GROUP_ADDR_DST_ENDPOINT_NOT_PRESENT; // dstAddrMode 0x01
dataReqParams.m_dstAddr16 = Mac16Address("BE:EF"); // The destination group address
zstack->GetNwk()->GetAps()->ApsdeDataRequest(dataReqParams, p);
Prior Zigbee Specification Revision 22 1.0 (2017), groupcasting used a form of controlled broadcast to propagate data to all group members in the network.
However, the current specification has changed this behavior to a more efficient group addressing scheme. In the new scheme, data transmissions,
propagate differently depending on whether or not the receiving or initiating device is member of the group.
If the devices are members of the group, they broadcast the data to the nearby devices (like in the old approach),
however, if device are not a members of the group, group addresses are treated as regular unicast addresses, and a route discovery is performed
to find the closest device which is part of the group. These route are stored in the routing table, and subsequent transmissions to the same group address will use the stored route.
In this way, the group address is treated as a unicast address, and the APS layer will not broadcast the data to all devices in the network.
This change improves the efficiency of groupcasting by reducing unnecessary broadcasts.
UniCasting (Address Mode: 0x02)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Unicasting is a method of transmitting data to a single specific device endpoint.
In Zigbee, this is achieved by using the ``APSDE-DATA.request`` primitive with the appropriate destination address mode and address information.
To use unicasting, the sender must know the 16-bit address of the destination device and the endpoint it wants to communicate with.
The ``APSDE-DATA.request`` primitive is used to send data to a specific device endpoint using the address mode 0x02 (Regular Unicast).
The following example demonstrates how to send data to a specific device endpoint using the APSDE-DATA.request primitive with address mode 0x02::
// The message will be delivered to the endpoint 5 of the device with address AB:1C
ApsdeDataRequestParams dataReqParams;
ZigbeeApsTxOptions txOptions;
dataReqParams.m_useAlias = false;
// Default, use 16 bit address destination (No option), equivalent to 0x00
dataReqParams.m_txOptions = txOptions.GetTxOptions();
dataReqParams.m_srcEndPoint = 4; // Arbitrary value, must not be 0
dataReqParams.m_clusterId = 5; // Arbitrary value (depends on the application)
dataReqParams.m_profileId = 2; // Arbitrary value (depends on the application)
dataReqParams.m_dstAddrMode = ApsDstAddressMode::DST_ADDR16_DST_ENDPOINT_PRESENT; // dstAddrMode 0x02
dataReqParams.m_dstAddr16 = Mac16Address("AB:1C"); // The destination device address
dataReqParams.m_dstEndPoint = 5; // The destination endpoint, must not be 0
zstack->GetNwk()->GetAps()->ApsdeDataRequest(dataReqParams, p);
Usage
-----
Zigbee is implemented as a |ns3| module, which means it can be used in the same way as other |ns3| modules.
It requires the ``lr-wpan`` module to be installed and operational, as it relies on the lr-wpan MAC layer to function.
Zigbee networks can be created by using the ``ZigbeeHelper`` class,
which simplifies the process of configuring and installing the Zigbee stack but it also possible to create and configure
Zigbee stacks manually.
Helpers
~~~~~~~
@@ -395,8 +503,6 @@ Below is a list of the currently supported attributes:
- ``NwkcMaxRREQJitter``: [Constant] The duration between retries of a broadcast RREQ (msec).
- ``MaxPendingTxQueueSize``: The maximum size of the table storing pending packets awaiting to be transmitted after discovering a route to the destination.
Traces
~~~~~~
@@ -417,7 +523,7 @@ All the examples listed here shows scenarios in which a quasi-layer implementati
* ``zigbee-association-join.cc``: An example showing the NWK layer join process of 3 devices in a zigbee network (MAC association).
* ``zigbee-nwk-routing.cc``: Shows a simple topology of 5 router devices sequentially joining a network. Data transmission and route discovery (MESH routing) are also shown in this example
* ``zigbee-nwk-routing-grid.cc``: Shows a complex grid topology of 50 router devices sequentially joining a network. Route discovery (MANY-TO-ONE routing) is also shown in this example.
* ``zigbee-aps-data.cc``: Demonstrates the usage of the APS layer to transmit data.
* ``zigbee-aps-data.cc``: Demonstrates the usage of the APS layer to transmit data (Unicast and Groupcast).)
The following unit test have been developed to ensure the correct behavior of the module:

View File

@@ -16,6 +16,10 @@
* handle automatically by the NWK layer. There is no ZDO, therefore we need to manually
* use the NWK to form the network and establish the router devices.
*
* The example demonstrates the following:
* - Sending data using the APS layer (Unicast and Groupcast destinations).
* - Using the APS layer to establish groupcast groups and endpoints.
*
*
* Network Extended PAN id: 0X000000000000CA:FE (based on the PAN coordinator address)
*
@@ -29,10 +33,14 @@
*
* Topology:
*
* ZC--------ZR1------------ZR2----------ZR3
* ZC--------ZR1------------ZR2----------ZR3 (GroupID Member: [01:23] | Endpoints: 3)
* |
* |
* ZR4
* ZR4 (GroupID Member: [01:23] | Endpoints: 3, 9)
*
*
* In example, Both ZR4 and ZR3 are part of the multicast group [01:23].
* ZR4 has two endpoints in the group, 3 and 9. ZR3 has only one endpoint in the group, 3.
*/
#include "ns3/constant-position-mobility-model.h"
@@ -56,67 +64,31 @@ NS_LOG_COMPONENT_DEFINE("ZigbeeRouting");
ZigbeeStackContainer zigbeeStacks;
static void
TraceRoute(Mac16Address src, Mac16Address dst)
{
std::cout << "\nTime " << Simulator::Now().As(Time::S) << " | "
<< "Traceroute to destination [" << dst << "]:\n";
Mac16Address target = src;
uint32_t count = 1;
while (target != Mac16Address("FF:FF") && target != dst)
{
Ptr<ZigbeeStack> zstack;
for (auto i = zigbeeStacks.Begin(); i != zigbeeStacks.End(); i++)
{
zstack = *i;
if (zstack->GetNwk()->GetNetworkAddress() == target)
{
break;
}
}
bool neighbor = false;
target = zstack->GetNwk()->FindRoute(dst, neighbor);
if (target == Mac16Address("FF:FF"))
{
std::cout << count << ". Node " << zstack->GetNode()->GetId() << " ["
<< zstack->GetNwk()->GetNetworkAddress() << " | "
<< zstack->GetNwk()->GetIeeeAddress() << "]: "
<< " Destination Unreachable\n";
}
else
{
std::cout << count << ". Node " << zstack->GetNode()->GetId() << " ["
<< zstack->GetNwk()->GetNetworkAddress() << " | "
<< zstack->GetNwk()->GetIeeeAddress() << "]: "
<< "NextHop [" << target << "] ";
if (neighbor)
{
std::cout << "(*Neighbor)\n";
}
else
{
std::cout << "\n";
}
count++;
}
}
std::cout << "\n";
}
static void
ApsDataIndication(Ptr<ZigbeeStack> stack, ApsdeDataIndicationParams params, Ptr<Packet> p)
{
std::cout << Simulator::Now().As(Time::S) << " Node " << stack->GetNode()->GetId() << " | "
<< "ApsdeDataIndication: Received packet of size " << p->GetSize()
std::cout << Simulator::Now().As(Time::S) << " Node " << stack->GetNode()->GetId() << " | ";
if (params.m_dstAddrMode == ApsDstAddressMode::DST_ADDR16_DST_ENDPOINT_PRESENT)
{
std::cout << "UCST | ";
}
else if (params.m_dstAddrMode == ApsDstAddressMode::GROUP_ADDR_DST_ENDPOINT_NOT_PRESENT)
{
std::cout << "GROUPCAST | ";
}
else
{
std::cout << "Unknown | ";
}
std::cout << "ApsdeDataIndication: Received DATA packet with size " << p->GetSize()
<< " for destination EndPoint " << params.m_dstEndPoint << "\n";
}
static void
NwkNetworkFormationConfirm(Ptr<ZigbeeStack> stack, NlmeNetworkFormationConfirmParams params)
{
std::cout << "NlmeNetworkFormationConfirmStatus = " << params.m_status << "\n";
std::cout << Simulator::Now().As(Time::S) << " Node " << stack->GetNode()->GetId() << " | "
<< "NlmeNetworkFormationConfirmStatus = " << params.m_status << "\n";
}
static void
@@ -129,19 +101,9 @@ NwkNetworkDiscoveryConfirm(Ptr<ZigbeeStack> stack, NlmeNetworkDiscoveryConfirmPa
if (params.m_status == NwkStatus::SUCCESS)
{
std::cout << " Network discovery confirm Received. Networks found ("
<< params.m_netDescList.size() << "):\n";
for (const auto& netDescriptor : params.m_netDescList)
{
std::cout << " ExtPanID: 0x" << std::hex << netDescriptor.m_extPanId << "\n"
<< std::dec << " CH: " << static_cast<uint32_t>(netDescriptor.m_logCh)
<< "\n"
<< std::hex << " Pan ID: 0x" << netDescriptor.m_panId << "\n"
<< " Stack profile: " << std::dec
<< static_cast<uint32_t>(netDescriptor.m_stackProfile) << "\n"
<< "--------------------\n";
}
std::cout << Simulator::Now().As(Time::S) << " Node " << stack->GetNode()->GetId() << " | "
<< " Network discovery confirm Received. Networks found ("
<< params.m_netDescList.size() << ")\n";
NlmeJoinRequestParams joinParams;
@@ -168,7 +130,7 @@ NwkJoinConfirm(Ptr<ZigbeeStack> stack, NlmeJoinConfirmParams params)
{
std::cout << Simulator::Now().As(Time::S) << " Node " << stack->GetNode()->GetId() << " | "
<< " The device joined the network SUCCESSFULLY with short address " << std::hex
<< params.m_networkAddress << " on the Extended PAN Id: " << std::hex
<< params.m_networkAddress << " on the Extended PAN Id: 0x" << std::hex
<< params.m_extendedPanId << "\n"
<< std::dec;
@@ -193,7 +155,7 @@ NwkRouteDiscoveryConfirm(Ptr<ZigbeeStack> stack, NlmeRouteDiscoveryConfirmParams
}
static void
SendData(Ptr<ZigbeeStack> stackSrc, Ptr<ZigbeeStack> stackDst)
SendDataUcst(Ptr<ZigbeeStack> stackSrc, Ptr<ZigbeeStack> stackDst)
{
// Send data from a device with stackSrc to device with stackDst.
@@ -213,32 +175,39 @@ SendData(Ptr<ZigbeeStack> stackSrc, Ptr<ZigbeeStack> stackDst)
dataReqParams.m_useAlias = false;
// Default, use 16 bit address destination (No option), equivalent to 0x00
dataReqParams.m_txOptions = txOptions.GetTxOptions();
dataReqParams.m_srcEndPoint = 3;
dataReqParams.m_clusterId = 5; // Arbitrary value
dataReqParams.m_profileId = 2; // Arbitrary value
dataReqParams.m_srcEndPoint = 4; // Arbitrary value, must not be 0
dataReqParams.m_clusterId = 5; // Arbitrary value
dataReqParams.m_profileId = 2; // Arbitrary value
dataReqParams.m_dstAddrMode = ApsDstAddressMode::DST_ADDR16_DST_ENDPOINT_PRESENT;
dataReqParams.m_dstAddr16 = stackDst->GetNwk()->GetNetworkAddress();
dataReqParams.m_dstEndPoint = 4;
dataReqParams.m_dstEndPoint = 3;
Simulator::ScheduleNow(&ZigbeeAps::ApsdeDataRequest, stackSrc->GetAps(), dataReqParams, p);
}
// Give a few seconds to allow the creation of the route and
// then print the route trace and tables from the source
Simulator::Schedule(Seconds(3),
&TraceRoute,
stackSrc->GetNwk()->GetNetworkAddress(),
stackDst->GetNwk()->GetNetworkAddress());
static void
SendDataGcst(Ptr<ZigbeeStack> stackSrc)
{
Ptr<Packet> p = Create<Packet>(5);
// Src and Dst Endpoints must not be 0, because this is reserved for the ZDO.
// Other Endpoint numbers can help to differentiate between different applications
// running in the same node (similar to the concept of a port in TCP/IP).
// Likewise, because we currently do not have ZDO or ZCL or AF, clusterId
// and profileId numbers are non-sensical.
ApsdeDataRequestParams dataReqParams;
ZigbeeApsTxOptions txOptions;
dataReqParams.m_useAlias = false;
// Default, use 16 bit address destination (No option), equivalent to 0x00
dataReqParams.m_txOptions = txOptions.GetTxOptions();
dataReqParams.m_srcEndPoint = 4; // Arbitrary value, must not be 0
dataReqParams.m_clusterId = 5; // Arbitrary value
dataReqParams.m_profileId = 2; // Arbitrary value
Ptr<OutputStreamWrapper> stream = Create<OutputStreamWrapper>(&std::cout);
Simulator::Schedule(Seconds(4), &ZigbeeNwk::PrintNeighborTable, stackSrc->GetNwk(), stream);
dataReqParams.m_dstAddrMode = ApsDstAddressMode::GROUP_ADDR_DST_ENDPOINT_NOT_PRESENT;
dataReqParams.m_dstAddr16 = Mac16Address("01:23"); // The destination group address
Simulator::Schedule(Seconds(4), &ZigbeeNwk::PrintRoutingTable, stackSrc->GetNwk(), stream);
Simulator::Schedule(Seconds(4),
&ZigbeeNwk::PrintRouteDiscoveryTable,
stackSrc->GetNwk(),
stream);
Simulator::ScheduleNow(&ZigbeeAps::ApsdeDataRequest, stackSrc->GetAps(), dataReqParams, p);
}
int
@@ -247,6 +216,7 @@ main(int argc, char* argv[])
LogComponentEnableAll(LogLevel(LOG_PREFIX_TIME | LOG_PREFIX_FUNC | LOG_PREFIX_NODE));
// Enable logs for further details
// LogComponentEnable("ZigbeeNwk", LOG_LEVEL_DEBUG);
// LogComponentEnable("ZigbeeAps", LOG_LEVEL_DEBUG);
RngSeedManager::SetSeed(3);
RngSeedManager::SetRun(4);
@@ -373,6 +343,11 @@ main(int argc, char* argv[])
zstack4->GetAps()->SetApsdeDataIndicationCallback(
MakeBoundCallback(&ApsDataIndication, zstack4));
// NWK Layer
// We do not have a ZDO, therefore we need to manually
// initiate the network formation and discovery procedures
// using the NWK layer.
// 1 - Initiate the Zigbee coordinator, start the network
// ALL_CHANNELS = 0x07FFF800 (Channels 11~26)
NlmeNetworkFormationRequestParams netFormParams;
@@ -431,9 +406,49 @@ main(int argc, char* argv[])
zstack4->GetNwk(),
netDiscParams4);
// 5- Find Route and Send data (Call to APS layer)
// APS Layer
// 4- Establish the Groupcast groups and its endpoints
// Add group [01:23] and endpoint 3 to Devices 3 and 4
// Also add endpoint 9 to device 4 in the same group.
ApsmeGroupRequestParams groupParams;
groupParams.m_groupAddress = Mac16Address("01:23");
groupParams.m_endPoint = 3;
Simulator::ScheduleWithContext(zstack3->GetNode()->GetId(),
Seconds(7),
&ZigbeeAps::ApsmeAddGroupRequest,
zstack3->GetAps(),
groupParams);
Simulator::Schedule(Seconds(8), &SendData, zstack0, zstack3);
Simulator::ScheduleWithContext(zstack4->GetNode()->GetId(),
Seconds(7),
&ZigbeeAps::ApsmeAddGroupRequest,
zstack4->GetAps(),
groupParams);
groupParams.m_endPoint = 9; // Add endpoint 9 to the same group
Simulator::ScheduleWithContext(zstack4->GetNode()->GetId(),
Seconds(7),
&ZigbeeAps::ApsmeAddGroupRequest,
zstack4->GetAps(),
groupParams);
// 4- Send data using the APS layer
// GROUPCAST
// Transmit data to all endpoints in devices that are
// part of the group [01:23] (i.e. endpoints in the ZR3 and ZR4).
Simulator::Schedule(Seconds(9), &SendDataGcst, zstack0);
// UNICAST
// Transmit data to a specific endpoint in a device
// In this case, we send data to the endpoint 3 of ZR3.
// We require the destination address, but we do not know this apriori,
// therefore we can request it from zstack3 on runtime.
Simulator::Schedule(Seconds(10), &SendDataUcst, zstack0, zstack3);
// Print the contents of the routing table in the initiator device (ZC)
Ptr<OutputStreamWrapper> stream = Create<OutputStreamWrapper>(&std::cout);
Simulator::Schedule(Seconds(11), &ZigbeeNwk::PrintRoutingTable, zstack0->GetNwk(), stream);
Simulator::Stop(Seconds(20));
Simulator::Run();

View File

@@ -26,7 +26,7 @@ namespace zigbee
{
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* APS Destination Address Mode for Binding
* Zigbee Specification r22.1.0, Table 2-6
@@ -39,7 +39,7 @@ enum class ApsDstAddressModeBind : std::uint8_t
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* The status resulting of interactions with the binding table.
*/
@@ -53,7 +53,7 @@ enum class BindingTableStatus : std::uint8_t
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* Binding Table entry: Source portion of the table.
* As described in Zigbee Specification r22.1.0, Table 2-134

View File

@@ -28,7 +28,13 @@ ZigbeeAps::GetTypeId()
static TypeId tid = TypeId("ns3::zigbee::ZigbeeAps")
.SetParent<Object>()
.SetGroupName("Zigbee")
.AddConstructor<ZigbeeAps>();
.AddConstructor<ZigbeeAps>()
.AddAttribute("ApsNonMemberRadius",
"The value to be used for the NonmemberRadius parameter"
" when using NWK layer multicast",
UintegerValue(0x02),
MakeUintegerAccessor(&ZigbeeAps::m_apsNonMemberRadius),
MakeUintegerChecker<uint8_t>());
return tid;
}
@@ -71,6 +77,12 @@ ZigbeeAps::SetNwk(Ptr<ZigbeeNwk> nwk)
m_nwk = nwk;
}
void
ZigbeeAps::SetGroupTable(Ptr<ZigbeeGroupTable> groupTable)
{
m_apsGroupTable = groupTable;
}
Ptr<ZigbeeNwk>
ZigbeeAps::GetNwk() const
{
@@ -125,8 +137,8 @@ ZigbeeAps::ApsdeDataRequest(ApsdeDataRequestParams params, Ptr<Packet> asdu)
break;
}
case ApsDstAddressMode::GROUP_ADDR_DST_ENDPOINT_NOT_PRESENT: {
// TODO: Add Groupcast (multicast) support
NS_ABORT_MSG("GROUP ADDRESS (MCST) not supported");
// Groupcast (a kind of multicast) support
SendDataGroup(params, asdu);
break;
}
case ApsDstAddressMode::DST_ADDR16_DST_ENDPOINT_PRESENT: {
@@ -304,6 +316,55 @@ ZigbeeAps::SendDataUcstBcst(ApsdeDataRequestParams params, Ptr<Packet> asdu)
Simulator::ScheduleNow(&ZigbeeNwk::NldeDataRequest, m_nwk, nwkParams, asdu);
}
void
ZigbeeAps::SendDataGroup(ApsdeDataRequestParams params, Ptr<Packet> asdu)
{
NS_LOG_FUNCTION(this);
// Fill APSDE-data.confirm parameters in case we need to return an error
ApsdeDataConfirmParams confirmParams;
confirmParams.m_dstAddrMode = params.m_dstAddrMode;
confirmParams.m_dstAddr16 = params.m_dstAddr16;
confirmParams.m_dstAddr64 = params.m_dstAddr64;
confirmParams.m_dstEndPoint = params.m_dstEndPoint;
confirmParams.m_srcEndPoint = params.m_srcEndPoint;
if (params.m_dstAddr16 == Mac16Address("00:00"))
{
if (!m_apsdeDataConfirmCallback.IsNull())
{
confirmParams.m_status = ApsStatus::INVALID_GROUP;
confirmParams.m_txTime = Simulator::Now();
m_apsdeDataConfirmCallback(confirmParams);
}
return;
}
// APS Header
ZigbeeApsTxOptions txOptions(params.m_txOptions);
ZigbeeApsHeader apsHeader;
apsHeader.SetFrameType(ApsFrameType::APS_DATA);
apsHeader.SetSrcEndpoint(params.m_srcEndPoint);
apsHeader.SetProfileId(params.m_profileId);
apsHeader.SetClusterId(params.m_clusterId);
apsHeader.SetExtHeaderPresent(false);
apsHeader.SetDeliveryMode(ApsDeliveryMode::APS_GROUP_ADDRESSING);
apsHeader.SetGroupAddress(params.m_dstAddr16.ConvertToInt());
// NLDE-data.request params
NldeDataRequestParams nwkParams;
nwkParams.m_radius = params.m_radius;
nwkParams.m_discoverRoute = DiscoverRouteType::ENABLE_ROUTE_DISCOVERY;
nwkParams.m_securityEnable = txOptions.IsSecurityEnabled();
nwkParams.m_dstAddrMode = AddressMode::MCST;
nwkParams.m_dstAddr = params.m_dstAddr16;
nwkParams.m_nonMemberRadius = m_apsNonMemberRadius;
asdu->AddHeader(apsHeader);
Simulator::ScheduleNow(&ZigbeeNwk::NldeDataRequest, m_nwk, nwkParams, asdu);
}
void
ZigbeeAps::ApsmeBindRequest(ApsmeBindRequestParams params)
{
@@ -374,9 +435,72 @@ ZigbeeAps::ApsmeUnbindRequest(ApsmeBindRequestParams params)
{
}
void
ZigbeeAps::ApsmeAddGroupRequest(ApsmeGroupRequestParams params)
{
NS_LOG_FUNCTION(this);
ApsmeGroupConfirmParams confirmParams;
confirmParams.m_status = ApsStatus::SUCCESS;
confirmParams.m_groupAddress = params.m_groupAddress;
confirmParams.m_endPoint = params.m_endPoint;
if (!m_apsGroupTable->AddEntry(params.m_groupAddress.ConvertToInt(), params.m_endPoint))
{
confirmParams.m_status = ApsStatus::TABLE_FULL;
}
if (!m_apsmeAddGroupConfirmCallback.IsNull())
{
m_apsmeAddGroupConfirmCallback(confirmParams);
}
}
void
ZigbeeAps::ApsmeRemoveGroupRequest(ApsmeGroupRequestParams params)
{
NS_LOG_FUNCTION(this);
ApsmeGroupConfirmParams confirmParams;
confirmParams.m_status = ApsStatus::SUCCESS;
confirmParams.m_groupAddress = params.m_groupAddress;
confirmParams.m_endPoint = params.m_endPoint;
if (!m_apsGroupTable->RemoveEntry(params.m_groupAddress.ConvertToInt(), params.m_endPoint))
{
confirmParams.m_status = ApsStatus::INVALID_GROUP;
}
if (!m_apsmeRemoveGroupConfirmCallback.IsNull())
{
m_apsmeRemoveGroupConfirmCallback(confirmParams);
}
}
void
ZigbeeAps::ApsmeRemoveAllGroupsRequest(uint8_t endPoint)
{
NS_LOG_FUNCTION(this);
ApsmeRemoveAllGroupsConfirmParams confirmParams;
confirmParams.m_status = ApsStatus::SUCCESS;
confirmParams.m_endPoint = endPoint;
if (!m_apsGroupTable->RemoveMembership(endPoint))
{
confirmParams.m_status = ApsStatus::INVALID_PARAMETER;
}
if (!m_apsmeRemoveAllGroupsConfirmCallback.IsNull())
{
m_apsmeRemoveAllGroupsConfirmCallback(confirmParams);
}
}
void
ZigbeeAps::NldeDataConfirm(NldeDataConfirmParams params)
{
// TODO: Handle the confirmation of the data request
}
void
@@ -384,64 +508,124 @@ ZigbeeAps::NldeDataIndication(NldeDataIndicationParams params, Ptr<Packet> nsdu)
{
NS_LOG_FUNCTION(this);
// See section 2.2.4.1.3.
// - TODO: Handle Security
// - Handle groupcast (MCST) delivery (Note group table shared by NWK and APS)
// - Handle UCST, BCST delivery
// - TODO: Handle binding
// - TODO: Handle fragmentation
// - TODO: Detect Duplicates
// - TODO: Handle ACK
// - TODO: Handle other frame types (APS Command, APS Inter-PAN)
ZigbeeApsHeader apsHeader;
nsdu->RemoveHeader(apsHeader);
ApsdeDataIndicationParams indicationParams;
indicationParams.m_status = ApsStatus::SUCCESS;
// TODO:
// See section 2.2.4.1.3.
// - Handle Security
// - Handle grouping(MCST) (Note group table shared by NWK and APS)
// - Handle binding
// - Handle fragmentation
// - Detect Duplicates
// - Handle ACK
// Check if packet is fragmented
if (apsHeader.IsExtHeaderPresent())
{
indicationParams.m_status = ApsStatus::DEFRAG_UNSUPPORTED;
if (!m_apsdeDataIndicationCallback.IsNull())
{
ApsdeDataIndicationParams indicationParams;
indicationParams.m_status = ApsStatus::DEFRAG_UNSUPPORTED;
m_apsdeDataIndicationCallback(indicationParams, nsdu);
}
NS_LOG_WARN("Extended Header (Fragmentation) not supported");
return;
// TODO: Handle fragmentation See 2.2.8.4.5
}
// TODO: IF security is present, remove as described in Section 4.4.
if (params.m_securityUse)
{
NS_LOG_ERROR("Security is not currently supported");
}
// TODO: Duplicate detection here
// See last paragraph of section 2.2.8.4.2
switch (apsHeader.GetFrameType())
{
case ApsFrameType::APS_DATA:
// Zigbee Specification, Section 2.2.8.4.2
// Reception and Rejection
ReceiveData(apsHeader, params, nsdu);
break;
case ApsFrameType::APS_ACK:
NS_LOG_ERROR("APS ACK frames are not supported");
break;
case ApsFrameType::APS_COMMAND:
NS_LOG_ERROR("APS Command frames are not supported");
break;
case ApsFrameType::APS_INTERPAN_APS:
NS_LOG_ERROR("APS Inter-PAN frames are not supported");
break;
}
}
void
ZigbeeAps::ReceiveData(const ZigbeeApsHeader& apsHeader,
const NldeDataIndicationParams& params,
Ptr<Packet> nsdu)
{
NS_LOG_FUNCTION(this);
ApsdeDataIndicationParams indicationParams;
indicationParams.m_status = ApsStatus::SUCCESS;
indicationParams.m_srcAddress16 = params.m_srcAddr;
indicationParams.m_srcEndpoint = apsHeader.GetSrcEndpoint();
indicationParams.m_profileId = apsHeader.GetProfileId();
indicationParams.m_clusterId = apsHeader.GetClusterId();
indicationParams.asduLength = nsdu->GetSize();
indicationParams.m_securityStatus = ApsSecurityStatus::UNSECURED;
indicationParams.m_linkQuality = params.m_linkQuality;
indicationParams.m_rxTime = Simulator::Now();
// UNICAST or BROADCAST delivery
if (apsHeader.GetDeliveryMode() == ApsDeliveryMode::APS_UCST ||
apsHeader.GetDeliveryMode() == ApsDeliveryMode::APS_BCST)
{
if (!m_apsdeDataIndicationCallback.IsNull())
{
// Note: Extracting the Address directly from the NWK, creates a dependency on this NWK
// implementation. This is not a very good design, but in practice, it is unavoidable
// due to the quasi cross-layer design of the specification
//(tigly coupled design of the APS in respect to the NWK).
indicationParams.m_dstAddr16 = m_nwk->GetNetworkAddress();
indicationParams.m_dstAddrMode = ApsDstAddressMode::DST_ADDR16_DST_ENDPOINT_PRESENT;
indicationParams.m_dstEndPoint = apsHeader.GetDstEndpoint();
indicationParams.m_srcAddrMode = ApsSrcAddressMode::SRC_ADDR16_SRC_ENDPOINT_PRESENT;
m_apsdeDataIndicationCallback(indicationParams, nsdu);
}
return;
}
if (apsHeader.GetFrameType() == ApsFrameType::APS_DATA)
{
if (apsHeader.GetDeliveryMode() == ApsDeliveryMode::APS_UCST ||
apsHeader.GetDeliveryMode() == ApsDeliveryMode::APS_BCST)
{
indicationParams.m_dstAddrMode = ApsDstAddressMode::DST_ADDR16_DST_ENDPOINT_PRESENT;
// Note: Extracting the Address directly from the NWK, creates a dependency on this NWK
// implementation. This is not a very good design, but in practice, it is unavoidable
// due to the descriptions in the specification.
indicationParams.m_dstAddr16 = m_nwk->GetNetworkAddress();
indicationParams.m_dstEndPoint = apsHeader.GetDstEndpoint();
indicationParams.m_srcAddrMode = ApsSrcAddressMode::SRC_ADDR16_SRC_ENDPOINT_PRESENT;
indicationParams.m_srcAddress16 = params.m_srcAddr;
indicationParams.m_srcEndpoint = apsHeader.GetSrcEndpoint();
indicationParams.m_profileId = apsHeader.GetProfileId();
indicationParams.m_clusterId = apsHeader.GetClusterId();
indicationParams.asduLength = nsdu->GetSize();
indicationParams.m_securityStatus = ApsSecurityStatus::UNSECURED;
indicationParams.m_linkQuality = params.m_linkQuality;
indicationParams.m_rxTime = Simulator::Now();
// GROUPCAST delivery
if (!m_apsdeDataIndicationCallback.IsNull())
if (apsHeader.GetDeliveryMode() == ApsDeliveryMode::APS_GROUP_ADDRESSING &&
params.m_dstAddrMode == AddressMode::MCST)
{
std::vector<uint8_t> endPoints;
if (m_apsGroupTable->LookUpEndPoints(apsHeader.GetGroupAddress(), endPoints))
{
// Give a copy of the packet to each endpoint associated with the group ID.
for (const auto& endPoint : endPoints)
{
m_apsdeDataIndicationCallback(indicationParams, nsdu);
if (!m_apsdeDataIndicationCallback.IsNull())
{
indicationParams.m_dstAddr16 = Mac16Address(apsHeader.GetGroupAddress());
indicationParams.m_dstAddrMode =
ApsDstAddressMode::GROUP_ADDR_DST_ENDPOINT_NOT_PRESENT;
indicationParams.m_dstEndPoint = endPoint;
indicationParams.m_srcAddrMode =
ApsSrcAddressMode::SRC_ADDR16_SRC_ENDPOINT_PRESENT;
m_apsdeDataIndicationCallback(indicationParams, nsdu->Copy());
}
}
}
else
{
// TODO: Group deliveryMode == (MCST)
NS_LOG_WARN("Group delivery not supported");
}
return;
}
}
@@ -469,6 +653,24 @@ ZigbeeAps::SetApsmeUnbindConfirmCallback(ApsmeUnbindConfirmCallback c)
m_apsmeUnbindConfirmCallback = c;
}
void
ZigbeeAps::SetApsmeAddGroupConfirmCallback(ApsmeAddGroupConfirmCallback c)
{
m_apsmeAddGroupConfirmCallback = c;
}
void
ZigbeeAps::SetApsmeRemoveGroupConfirmCallback(ApsmeRemoveGroupConfirmCallback c)
{
m_apsmeRemoveGroupConfirmCallback = c;
}
void
ZigbeeAps::SetApsmeRemoveAllGroupsConfirmCallback(ApsmeRemoveAllGroupsConfirmCallback c)
{
m_apsmeRemoveAllGroupsConfirmCallback = c;
}
//////////////////////////
// ZigbeeApsTxOptions //
//////////////////////////

View File

@@ -13,6 +13,7 @@
#include "zigbee-aps-header.h"
#include "zigbee-aps-tables.h"
#include "zigbee-group-table.h"
#include "zigbee-nwk.h"
#include "ns3/event-id.h"
@@ -222,6 +223,44 @@ struct ApsmeBindConfirmParams
uint8_t m_dstEndPoint{0xF0}; //!< The application destination endpoint
};
/**
* @ingroup zigbee
*
* Zigbee Specification r22.1.0, Section 2.2.4.5.1 and 2.2.4.5.3
* APSME-ADD-GROUP.request and APSME-REMOVE-GROUP.request params
*/
struct ApsmeGroupRequestParams
{
Mac16Address m_groupAddress; //!< The group address to add
uint8_t m_endPoint{1}; //!< The endpoint to which the group address is associated
};
/**
* @ingroup zigbee
*
* Zigbee Specification r22.1.0, Section 2.2.4.5.2 and 2.2.4.5.4
* APSME-ADD-GROUP.confirm and APSME-REMOVE-GROUP.confirm params
*/
struct ApsmeGroupConfirmParams
{
ApsStatus m_status{ApsStatus::INVALID_PARAMETER}; //!< The status of the add group request
Mac16Address m_groupAddress; //!< The group address being added
uint8_t m_endPoint{1}; //!< The endpoint to which the given group is being added.
};
/**
* @ingroup zigbee
*
* Zigbee Specification r22.1.0, Section 2.2.4.5.6
* APSME-REMOVE-ALL-GROUPS.request params
*/
struct ApsmeRemoveAllGroupsConfirmParams
{
ApsStatus m_status{
ApsStatus::INVALID_PARAMETER}; //!< The status of the remove all groups request
uint8_t m_endPoint{1}; //!< The endpoint from which all groups are being removed.
};
//////////////////////
// Callbacks //
//////////////////////
@@ -257,6 +296,30 @@ typedef Callback<void, ApsmeBindConfirmParams> ApsmeBindConfirmCallback;
*/
typedef Callback<void, ApsmeBindConfirmParams> ApsmeUnbindConfirmCallback;
/**
* @ingroup zigbee
*
* This callback is called to confirm a successfully addition of a group address
* and or endPoint into the group table.
*/
typedef Callback<void, ApsmeGroupConfirmParams> ApsmeAddGroupConfirmCallback;
/**
* @ingroup zigbee
*
* This callback is called to confirm a successfully removal of a group address
* and or endPoint from the group table.
*/
typedef Callback<void, ApsmeGroupConfirmParams> ApsmeRemoveGroupConfirmCallback;
/**
* @ingroup zigbee
*
* This callback is called to confirm a successfully removal of an endpoint from
* all the the groups.
*/
typedef Callback<void, ApsmeRemoveAllGroupsConfirmParams> ApsmeRemoveAllGroupsConfirmCallback;
/**
* @ingroup zigbee
*
@@ -286,6 +349,13 @@ class ZigbeeAps : public Object
*/
void SetNwk(Ptr<ZigbeeNwk> nwk);
/**
* Get the group table used by this Zigbee APS.
*
* @param groupTable The pointer to the group table to set.
*/
void SetGroupTable(Ptr<ZigbeeGroupTable> groupTable);
/**
* Get the underlying NWK used by the current Zigbee APS.
*
@@ -321,6 +391,36 @@ class ZigbeeAps : public Object
*/
void ApsmeUnbindRequest(ApsmeBindRequestParams params);
/**
* Zigbee Specification r22.1.0, Section 2.2.4.5.1
* APSME-ADD-GROUP.request
* Request that group membership for a particular group be added
* for a particular endpoint.
*
* @param params The APSME add group request params
*/
void ApsmeAddGroupRequest(ApsmeGroupRequestParams params);
/**
* Zigbee Specification r22.1.0, Section 2.2.4.5.3
* APSME-REMOVE-GROUP.request
* Request that group membership for a particular group be removed
* for a particular endpoint.
*
* @param params The APSME remove group request params
*/
void ApsmeRemoveGroupRequest(ApsmeGroupRequestParams params);
/**
* Zigbee Specification r22.1.0, Section 2.2.4.5.5
* APSME-REMOVE-ALL-GROUPS.request
* Remove membership in all groups from an endpoint, so that no group-addressed frames
* will be delivered to that endpoint.
*
* @param endPoint The endpoint from which all groups are being removed.
*/
void ApsmeRemoveAllGroupsRequest(uint8_t endPoint);
/**
* Zigbee Specification r22.1.0, Section 3.2.1.2
* NLDE-DATA.confirm
@@ -340,6 +440,18 @@ class ZigbeeAps : public Object
*/
void NldeDataIndication(NldeDataIndicationParams params, Ptr<Packet> nsdu);
/**
* Zigbee Specification r22.1.0, Section 2.2.8.4.2
* Reception and Rejection of data from the NWK.
*
* @param apsHeader The APS header of the received packet
* @param params The NLDE data indication params
* @param nsdu The packet received
*/
void ReceiveData(const ZigbeeApsHeader& apsHeader,
const NldeDataIndicationParams& params,
Ptr<Packet> nsdu);
/**
* Set the callback as part of the interconnections between the APS and
* the next layer or service (typically the application framework). The callback
@@ -376,6 +488,33 @@ class ZigbeeAps : public Object
*/
void SetApsmeUnbindConfirmCallback(ApsmeUnbindConfirmCallback c);
/**
* Set the callback as part of the interconnections between the APS and
* the next layer or service (typically the application framework). The callback
* implements the callback used in a APSME-ADD-GROUP.confirm
*
* @param c the ApsmeAddGroupConfirm callback
*/
void SetApsmeAddGroupConfirmCallback(ApsmeAddGroupConfirmCallback c);
/**
* Set the callback as part of the interconnections between the APS and
* the next layer or service (typically the application framework). The callback
* implements the callback used in a APSME-REMOVE-GROUP.confirm
*
* @param c the ApsmeRemoveGroupConfirm callback
*/
void SetApsmeRemoveGroupConfirmCallback(ApsmeRemoveGroupConfirmCallback c);
/**
* Set the callback as part of the interconnections between the APS and
* the next layer or service (typically the application framework). The callback
* implements the callback used in a APSME-REMOVE-ALL-GROUPS.confirm
*
* @param c the ApsmeRemoveAllGroupsConfirm callback
*/
void SetApsmeRemoveAllGroupsConfirmCallback(ApsmeRemoveAllGroupsConfirmCallback c);
protected:
void DoInitialize() override;
void DoDispose() override;
@@ -399,9 +538,13 @@ class ZigbeeAps : public Object
*/
void SendDataUcstBcst(ApsdeDataRequestParams params, Ptr<Packet> asdu);
Ptr<ZigbeeNwk> m_nwk; //!< Pointer to the underlying NWK connected to this Zigbee APS
SequenceNumber8 m_apsCounter; //!< The sequence number used in packet Tx with APS headers.
BindingTable m_apsBindingTable; //!< The binding table associated to this APS layer
/**
* Send a Groupcast to a group address destination.
*
* @param params The APSDE data request params
* @param asdu The packet to transmit
*/
void SendDataGroup(ApsdeDataRequestParams params, Ptr<Packet> asdu);
/**
* This callback is used to to notify the results of a data transmission
@@ -430,6 +573,59 @@ class ZigbeeAps : public Object
* See Zigbee specification r22.1.0, Section 2.2.4.3.4
*/
ApsmeUnbindConfirmCallback m_apsmeUnbindConfirmCallback;
/**
* This callback is used to to notify the result of endpoint addition
* request in the APS to the Application framework (AF).
* See Zigbee specification r22.1.0, Section 2.2.4.5.2
*/
ApsmeAddGroupConfirmCallback m_apsmeAddGroupConfirmCallback;
/**
* This callback is used to to notify the result of a endpoint removal
* request in the APS to the Application framework (AF).
* See Zigbee specification r22.1.0, Section 2.2.4.5.4
*/
ApsmeRemoveGroupConfirmCallback m_apsmeRemoveGroupConfirmCallback;
/**
* This callback is used to to notify the result of a endpoint removal
* request in the APS to the Application framework (AF).
* See Zigbee specification r22.1.0, Section 2.2.4.5.5
*/
ApsmeRemoveAllGroupsConfirmCallback m_apsmeRemoveAllGroupsConfirmCallback;
/**
* The underlying Zigbee NWK connected to this Zigbee APS.
*/
Ptr<ZigbeeNwk> m_nwk;
/**
* The group table used by this Zigbee APS.
* The group table is a shared resource with the NWK layer.
* Zigbee Specification r22.1.0, Section 2.2.7.2
*/
Ptr<ZigbeeGroupTable> m_apsGroupTable;
/**
* The sequence number used in packet Tx with APS headers.
* Zigbee Specification r22.1.0, Section 2.2.7.2
*/
SequenceNumber8 m_apsCounter;
/**
* The binding table used by this Zigbee APS.
* Zigbee Specification r22.1.0, Section 2.2.7.2
*/
BindingTable m_apsBindingTable;
/**
* The APS non-member radius, used to limit the number of hops
* for non-member multicast group devices when using NWK layer multicast.
* Valid range 0x00 to 0x07.
* Zigbee Specification r22.1.0, Section 2.2.7.2
*/
uint8_t m_apsNonMemberRadius;
};
/**

View File

@@ -1326,6 +1326,14 @@ BroadcastTransactionTable::LookUpEntry(uint8_t seq, Ptr<BroadcastTransactionReco
return false;
}
void
BroadcastTransactionTable::Delete(uint8_t seq)
{
std::erase_if(m_broadcastTransactionTable, [&seq](Ptr<BroadcastTransactionRecord> entry) {
return entry->GetSeqNum() == seq;
});
}
void
BroadcastTransactionTable::Purge()
{

View File

@@ -924,10 +924,10 @@ class BroadcastTransactionRecord : public SimpleRefCount<BroadcastTransactionRec
void Print(Ptr<OutputStreamWrapper> stream) const;
private:
Mac16Address m_srcAddr; //!< The 16-bit network address of the broadcast initiator.
uint8_t m_sequenceNumber; //!< The RREQ sequence number of the initiator's broadcast.
Time m_expirationTime; //!< An indicator of when the entry expires
uint8_t m_broadcastRetryCount; //!< The number of times this BCST has been retried.
Mac16Address m_srcAddr; //!< The 16-bit network address of the broadcast initiator.
uint8_t m_sequenceNumber{0}; //!< The RREQ sequence number of the initiator's broadcast.
Time m_expirationTime; //!< An indicator of when the entry expires
uint8_t m_broadcastRetryCount{1}; //!< The number of times this BCST has been retried.
};
/**
@@ -1297,6 +1297,13 @@ class BroadcastTransactionTable
*/
bool LookUpEntry(uint8_t seq, Ptr<BroadcastTransactionRecord>& entryFound);
/**
* Delete a broadcast transaction record (BTR) from the broadcast transaction table (BTT).
*
* @param seq The sequence number of the broadcasted frame to delete.
*/
void Delete(uint8_t seq);
/**
* Purge expired entries from the broadcast transaction table (BTT).
*/

View File

@@ -56,7 +56,6 @@ ZigbeeNwk::GetTypeId()
TimeValue(MilliSeconds(0x2710)),
MakeTimeAccessor(&ZigbeeNwk::m_nwkcRouteDiscoveryTime),
MakeTimeChecker())
.AddAttribute("NwkcInitialRREQRetries",
"[Constant] The number of times the first broadcast transmission"
"of a RREQ cmd frame is retried.",
@@ -87,6 +86,23 @@ ZigbeeNwk::GetTypeId()
DoubleValue(128),
MakeDoubleAccessor(&ZigbeeNwk::m_nwkcMaxRREQJitter),
MakeDoubleChecker<double>())
.AddAttribute("NwkcMaxBroadcastJitter",
"[Constant] The duration between retries of a broadcast RREQ (msec)",
DoubleValue(40),
MakeDoubleAccessor(&ZigbeeNwk::m_nwkcMaxBroadcastJitter),
MakeDoubleChecker<double>())
.AddAttribute("nwkMaxBroadcastRetries",
"The maximum number of retries allowed after a broadcast "
"transmission failure.",
UintegerValue(0x03),
MakeUintegerAccessor(&ZigbeeNwk::m_nwkMaxBroadcastRetries),
MakeUintegerChecker<uint8_t>())
.AddAttribute("NwkPassiveAckTimeout",
"The maximum time duration in milliseconds allowed for the parent "
"all the child devices to retransmit a broadcast message.",
TimeValue(MilliSeconds(500)),
MakeTimeAccessor(&ZigbeeNwk::m_nwkPassiveAckTimeout),
MakeTimeChecker())
.AddAttribute("MaxPendingTxQueueSize",
"The maximum size of the table storing pending packets awaiting "
"to be transmitted after discovering a route to the destination.",
@@ -138,7 +154,6 @@ ZigbeeNwk::NotifyConstructionCompleted()
m_nwkReportConstantCost = false;
m_nwkSymLink = false;
m_nwkMaxBroadcastRetries = 0x03;
m_countRREQRetries = 0;
m_nwkIsConcentrator = false;
@@ -157,6 +172,10 @@ ZigbeeNwk::NotifyConstructionCompleted()
m_rreqJitter->SetAttribute("Min", DoubleValue(m_nwkcMinRREQJitter));
m_rreqJitter->SetAttribute("Max", DoubleValue(m_nwkcMaxRREQJitter));
m_bcstJitter = CreateObject<UniformRandomVariable>();
m_bcstJitter->SetAttribute("Min", DoubleValue(0));
m_bcstJitter->SetAttribute("Max", DoubleValue(m_nwkcMaxBroadcastJitter));
m_routeExpiryTime = Seconds(255);
}
@@ -211,6 +230,12 @@ ZigbeeNwk::SetMac(Ptr<LrWpanMacBase> mac)
m_mac = mac;
}
void
ZigbeeNwk::SetGroupTable(Ptr<ZigbeeGroupTable> groupTable)
{
m_nwkGroupIdTable = groupTable;
}
Ptr<LrWpanMacBase>
ZigbeeNwk::GetMac() const
{
@@ -352,11 +377,29 @@ ZigbeeNwk::McpsDataIndication(McpsDataIndicationParams params, Ptr<Packet> msdu)
switch (nwkHeader.GetFrameType())
{
case DATA:
case DATA: {
if (nwkHeader.IsMulticast())
{
// DATA MULTICAST
NS_FATAL_ERROR("Multicast DATA transmission not supported");
if (nwkHeader.GetMulticastMode() == MulticastMode::MEMBER)
{
// Mcst Member Mode,Zigbee specification r22.1.0 Section 3.6.6.3
ReceiveMulticastMemberFrame(nwkHeader, msdu, params);
}
else
{
// Mcst Non-Member Mode,Zigbee specification r22.1.0 Section 3.6.6.4
if (m_nwkGroupIdTable->IsGroupMember(nwkHeader.GetDstAddr().ConvertToInt()))
{
// Treat frame as a multicast member
nwkHeader.SetMulticastMode(MulticastMode::MEMBER);
ReceiveMulticastMemberFrame(nwkHeader, msdu, params);
}
else
{
ReceiveMulticastNonMemberFrame(nwkHeader, msdu, params);
}
}
}
else if (IsBroadcastAddress(nwkHeader.GetDstAddr()))
{
@@ -443,6 +486,7 @@ ZigbeeNwk::McpsDataIndication(McpsDataIndicationParams params, Ptr<Packet> msdu)
}
}
break;
}
case NWK_COMMAND: {
ZigbeePayloadType payloadType;
msdu->RemoveHeader(payloadType);
@@ -530,7 +574,7 @@ ZigbeeNwk::ReceiveRREQ(Mac16Address macSrcAddr,
return;
}
// Mesh Routing
// Mesh Routing (Unicast or Multicast Group)
Mac16Address nextHop;
RouteDiscoveryStatus nextHopStatus =
@@ -699,6 +743,132 @@ ZigbeeNwk::ReceiveRREP(Mac16Address macSrcAddr,
}
}
void
ZigbeeNwk::ReceiveMulticastMemberFrame(ZigbeeNwkHeader nwkHeader,
Ptr<Packet> msdu,
McpsDataIndicationParams params)
{
NS_LOG_FUNCTION(this);
// As described in Zigbee specification r22.1.0 Section 3.6.6.3
// Drop if we've already seen this multicast frame
Ptr<BroadcastTransactionRecord> btr;
if (m_btt.LookUpEntry(nwkHeader.GetSeqNum(), btr))
{
return;
}
// Add new record to BTT
Ptr<BroadcastTransactionRecord> newBtr =
Create<BroadcastTransactionRecord>(nwkHeader.GetSrcAddr(),
nwkHeader.GetSeqNum(),
Simulator::Now() + m_nwkNetworkBroadcastDeliveryTime);
if (!m_btt.AddEntry(newBtr))
{
return;
}
// Verify if the device is capable of relaying multicast frames
// (i.e., not an end device)
CapabilityInformation capability(m_nwkCapabilityInformation);
bool canRelay = (capability.GetDeviceType() != MacDeviceType::ENDDEVICE);
// Case 1: Group Member — process and optionally retransmit
if (m_nwkGroupIdTable->IsGroupMember(nwkHeader.GetDstAddr().ConvertToInt()))
{
// Push the multicast frame to the APS layer
if (!m_nldeDataIndicationCallback.IsNull())
{
NldeDataIndicationParams dataParams;
dataParams.m_srcAddr = nwkHeader.GetSrcAddr();
dataParams.m_dstAddr = nwkHeader.GetDstAddr();
dataParams.m_dstAddrMode = AddressMode::MCST;
dataParams.m_linkQuality = params.m_mpduLinkQuality;
dataParams.m_nsduLength = msdu->GetSize();
dataParams.m_rxTime = Simulator::Now();
dataParams.m_securityUse = false;
m_nldeDataIndicationCallback(dataParams, msdu->Copy());
}
// TODO: Add Rx Trace here
if (canRelay)
{
nwkHeader.SetMulticastMode(MulticastMode::MEMBER);
nwkHeader.SetNonMemberRadius(nwkHeader.GetMaxNonMemberRadius());
msdu->AddHeader(nwkHeader);
Simulator::Schedule(MilliSeconds(m_bcstJitter->GetValue()),
&ZigbeeNwk::SendDataBcst,
this,
msdu,
0);
}
return;
}
// Case 2: Non Group Member — forward if non-zero radius
uint8_t radius = nwkHeader.GetNonMemberRadius();
if (radius == 0)
{
m_btt.Delete(nwkHeader.GetSeqNum());
return;
}
// Decrement radius and retransmit if allowed
nwkHeader.SetNonMemberRadius(radius - 1);
if (radius != 0 && canRelay)
{
msdu->AddHeader(nwkHeader);
Simulator::Schedule(MilliSeconds(m_bcstJitter->GetValue()),
&ZigbeeNwk::SendDataBcst,
this,
msdu,
0);
}
}
void
ZigbeeNwk::ReceiveMulticastNonMemberFrame(ZigbeeNwkHeader nwkHeader,
Ptr<Packet> msdu,
McpsDataIndicationParams params)
{
NS_LOG_FUNCTION(this);
NS_ASSERT_MSG(!nwkHeader.GetDstAddr().IsBroadcast(),
"Error: Non-member multicast frame should have a Group ID address");
// As described in Zigbee specification r22.1.0 Section 3.6.6.4
// If the GROUP ID (destination address) is in our routing table,
// our non member multicast frame is transmitted as a unicast frame
// to the next hop in the routing table, otherwise it is discarded.
Ptr<RoutingTableEntry> entry;
if (m_nwkRoutingTable.LookUpEntry(nwkHeader.GetDstAddr(), entry))
{
if (entry->GetStatus() == RouteStatus::ROUTE_VALIDATION_UNDERWAY)
{
entry->SetStatus(RouteStatus::ROUTE_ACTIVE);
}
if ((entry->GetStatus() == ROUTE_ACTIVE))
{
msdu->AddHeader(nwkHeader);
McpsDataRequestParams mcpsDataparams;
mcpsDataparams.m_dstPanId = m_nwkPanId;
mcpsDataparams.m_msduHandle = m_macHandle.GetValue();
mcpsDataparams.m_txOptions = 0x01; // Acknowledment on for Non-Member Multicast
mcpsDataparams.m_srcAddrMode = SHORT_ADDR;
mcpsDataparams.m_dstAddrMode = SHORT_ADDR;
mcpsDataparams.m_dstAddr = entry->GetNextHopAddr();
m_macHandle++;
Simulator::ScheduleNow(&LrWpanMacBase::McpsDataRequest, m_mac, mcpsDataparams, msdu);
}
}
}
bool
ZigbeeNwk::IsBroadcastAddress(Mac16Address address)
{
@@ -714,8 +884,25 @@ ZigbeeNwk::FindNextHop(Mac16Address macSrcAddr,
{
NS_LOG_FUNCTION(this);
if (payload.GetMulticastField() &&
m_nwkGroupIdTable->IsGroupMember(payload.GetDstAddr().ConvertToInt()))
{
// If the destination is a group member, we can directly return the next hop
// as the destination address.
nextHop = payload.GetDstAddr();
return ROUTE_FOUND;
}
// Mesh routing
// Check if I am the destination
if (payload.GetDstAddr() == m_nwkNetworkAddress)
{
// I am the destination, return myself as next hop
nextHop = m_nwkNetworkAddress;
return ROUTE_FOUND;
}
// Check if the destination is our neighbor
Ptr<NeighborTableEntry> neighborEntry;
if (m_nwkNeighborTable.LookUpEntry(payload.GetDstAddr(), neighborEntry))
@@ -762,14 +949,14 @@ ZigbeeNwk::FindNextHop(Mac16Address macSrcAddr,
}
}
// Entry not found
// Entry not found, create a new routing entry
Ptr<RoutingTableEntry> newRoutingEntry =
Create<RoutingTableEntry>(payload.GetDstAddr(),
ROUTE_DISCOVERY_UNDERWAY,
true, // TODO no route cache
false, // TODO: Many to one
false, // TODO: Route record
false, // TODO: Group id
true, // TODO no route cache
false, // Many to one
false, // TODO: Route record
payload.GetMulticastField(), // Group id
Mac16Address("FF:FF"));
newRoutingEntry->SetLifeTime(Simulator::Now() + m_routeExpiryTime);
@@ -922,7 +1109,7 @@ ZigbeeNwk::ProcessManyToOneRoute(Mac16Address macSrcAddr,
Create<RoutingTableEntry>(nwkHeader.GetSrcAddr(),
ROUTE_ACTIVE,
true, // TODO no route cache
true, // TODO: Many to one
true, // Many to one
routeRecord, // TODO: Route record
false, // TODO: Group id
macSrcAddr);
@@ -957,6 +1144,7 @@ ZigbeeNwk::SendDataUcst(Ptr<Packet> packet, uint8_t nwkHandle)
nwkHeaderRreq.SetDstAddr(Mac16Address("FF:FC"));
nwkHeaderRreq.SetSrcAddr(m_nwkNetworkAddress);
nwkHeaderRreq.SetSeqNum(m_nwkSequenceNumber.GetValue());
// see Zigbee specification 3.2.2.33.3
if (nwkHeaderData.GetRadius() == 0)
{
@@ -972,6 +1160,15 @@ ZigbeeNwk::SendDataUcst(Ptr<Packet> packet, uint8_t nwkHandle)
payloadRreq.SetDstAddr(nwkHeaderData.GetDstAddr());
payloadRreq.SetPathCost(0);
// If the original Data packet is marked as multicast,
// then set the multicast field in the RREQ payload
// In essence, this will initiate a multicast route discovery
// if necessary
if (nwkHeaderData.IsMulticast())
{
payloadRreq.SetMulticastField(true);
}
Mac16Address nextHop;
RouteDiscoveryStatus nextHopStatus =
FindNextHop(m_nwkNetworkAddress, 0, nwkHeaderRreq, payloadRreq, nextHop);
@@ -1021,6 +1218,7 @@ ZigbeeNwk::SendDataBcst(Ptr<Packet> packet, uint8_t nwkHandle)
BufferTxPkt(packet->Copy(), m_macHandle.GetValue(), nwkHandle);
// Parameters as described in Section 3.6.5
// TxOptions = 0 by default, i.e. no acknowledgment
McpsDataRequestParams mcpsDataparams;
mcpsDataparams.m_dstPanId = m_nwkPanId;
mcpsDataparams.m_msduHandle = m_macHandle.GetValue();
@@ -1040,28 +1238,58 @@ ZigbeeNwk::McpsDataConfirm(McpsDataConfirmParams params)
ZigbeeNwkHeader nwkHeader;
bufferedElement->txPkt->PeekHeader(nwkHeader);
if (nwkHeader.GetFrameType() == DATA)
if (nwkHeader.GetFrameType() != NwkType::DATA)
{
if (IsBroadcastAddress(nwkHeader.GetDstAddr()))
{
}
else if (nwkHeader.GetSrcAddr() == m_nwkNetworkAddress)
{
// Send the confirmation to next layer after the packet transmission,
// only if packet transmitted was in the initiator of the NLDE-DATA.request
NS_LOG_ERROR("Received DATA.confirm for a non-DATA packet");
return;
}
if (!m_nldeDataConfirmCallback.IsNull())
if (IsBroadcastAddress(nwkHeader.GetDstAddr()) || nwkHeader.IsMulticast())
{
if (params.m_status != MacStatus::SUCCESS)
{
// Broadcast or Multicast failed, retry sending the packet.
// Zigbee specification r22.1.0 Section 3.6.6.3
Ptr<BroadcastTransactionRecord> btr;
if (m_btt.LookUpEntry(nwkHeader.GetSeqNum(), btr))
{
// Zigbee Specification r22.1.0, End of Section 3.2.1.1.3
// Report the the results of a request to a transmission of a packet
NldeDataConfirmParams nldeDataConfirmParams;
// nldeDataConfirmParams.m_status =
// static_cast<ZigbeeNwkStatus>(params.m_status);
nldeDataConfirmParams.m_nsduHandle = bufferedElement->nwkHandle;
m_nldeDataConfirmCallback(nldeDataConfirmParams);
btr->SetBcstRetryCount(btr->GetBcstRetryCount() + 1);
if (btr->GetBcstRetryCount() <= m_nwkMaxBroadcastRetries)
{
// Retry sending the Broadcast or Multicast packet
Simulator::Schedule(MilliSeconds(m_nwkPassiveAckTimeout.GetMilliSeconds()),
&ZigbeeNwk::SendDataBcst,
this,
bufferedElement->txPkt,
bufferedElement->nwkHandle);
}
else
{
// Broadcast retries exhausted, silently discard the packet
NS_LOG_WARN("Broadcast or Multicast packet retries exhausted for packet"
" with sequence number "
<< nwkHeader.GetSeqNum());
}
}
}
}
else if (nwkHeader.GetSrcAddr() == m_nwkNetworkAddress)
{
// Send the confirmation to next layer after the packet transmission,
// only if packet transmitted was in the initiator of the NLDE-DATA.request
if (!m_nldeDataConfirmCallback.IsNull())
{
// Zigbee Specification r22.1.0, End of Section 3.2.1.1.3
// Report the the results of a request to a transmission of a packet
NldeDataConfirmParams nldeDataConfirmParams;
// nldeDataConfirmParams.m_status =
// static_cast<ZigbeeNwkStatus>(params.m_status);
nldeDataConfirmParams.m_nsduHandle = bufferedElement->nwkHandle;
m_nldeDataConfirmCallback(nldeDataConfirmParams);
}
}
}
}
@@ -1970,7 +2198,7 @@ ZigbeeNwk::NldeDataRequest(NldeDataRequestParams params, Ptr<Packet> packet)
if (params.m_dstAddr == m_nwkNetworkAddress)
{
NS_LOG_DEBUG("The source and the destination of the route request are the same!");
NS_LOG_WARN("The source and the destination of the route request are the same!");
return;
}
@@ -1978,7 +2206,7 @@ ZigbeeNwk::NldeDataRequest(NldeDataRequestParams params, Ptr<Packet> packet)
// check that we are associated
if (m_nwkNetworkAddress == "FF:FF")
{
NS_LOG_DEBUG("Cannot send data, the device is not currently associated");
NS_LOG_WARN("Cannot send data, the device is not currently associated");
if (!m_nldeDataConfirmCallback.IsNull())
{
@@ -1998,7 +2226,7 @@ ZigbeeNwk::NldeDataRequest(NldeDataRequestParams params, Ptr<Packet> packet)
nwkHeader.SetDiscoverRoute(static_cast<DiscoverRouteType>(params.m_discoverRoute));
nwkHeader.SetDstAddr(params.m_dstAddr);
if (params.m_useAlias)
if (params.m_useAlias && params.m_dstAddrMode != AddressMode::MCST)
{
nwkHeader.SetSrcAddr(params.m_aliasSrcAddr);
nwkHeader.SetSeqNum(params.m_aliasSeqNumber.GetValue());
@@ -2028,32 +2256,93 @@ ZigbeeNwk::NldeDataRequest(NldeDataRequestParams params, Ptr<Packet> packet)
CapabilityInformation capability;
capability.SetCapability(m_nwkCapabilityInformation);
if (capability.GetDeviceType() == ENDDEVICE)
if (capability.GetDeviceType() == MacDeviceType::ENDDEVICE)
{
nwkHeader.SetEndDeviceInitiator();
}
if (params.m_dstAddrMode == MCST)
// CASE 1: The destination is a multicast address (Group address)
// See Sections 3.6.6.2 and 3.2.1.1.3
if (params.m_dstAddrMode == AddressMode::MCST)
{
if (nwkHeader.GetEndDeviceInitiator())
{
NS_LOG_WARN("EndDevices cannot send multicast packets, dropping the packet");
if (!m_nldeDataConfirmCallback.IsNull())
{
NldeDataConfirmParams confirmParams;
confirmParams.m_status = NwkStatus::INVALID_REQUEST;
confirmParams.m_txTime = Simulator::Now();
confirmParams.m_nsduHandle = params.m_nsduHandle;
m_nldeDataConfirmCallback(confirmParams);
}
return;
// TODO: Add trace here.
}
nwkHeader.SetMulticast();
// TODO:
// set the nwkHeader multicast control according to
// the values of the non-member radios parameter
// See 3.2.1.1.3
nwkHeader.SetNonMemberRadius(params.m_nonMemberRadius);
nwkHeader.SetMaxNonMemberRadius(params.m_nonMemberRadius);
// Check if the current device is member of the multicast Group (dstAddr)
bool groupMember = m_nwkGroupIdTable->IsGroupMember(params.m_dstAddr.ConvertToInt());
if (groupMember)
{
nwkHeader.SetMulticastMode(MulticastMode::MEMBER);
// Add an entry to the Broadcast Transaction Table (BTT)
Ptr<BroadcastTransactionRecord> btr = Create<BroadcastTransactionRecord>(
nwkHeader.GetSrcAddr(),
nwkHeader.GetSeqNum(),
Simulator::Now() + m_nwkNetworkBroadcastDeliveryTime);
if (!m_btt.AddEntry(btr))
{
NS_LOG_DEBUG("Broadcast Transaction Table is full, dropping the packet");
// TODO: Add multicast packet trace here
if (!m_nldeDataConfirmCallback.IsNull())
{
NldeDataConfirmParams confirmParams;
confirmParams.m_status = NwkStatus::BT_TABLE_FULL;
confirmParams.m_txTime = Simulator::Now();
confirmParams.m_nsduHandle = params.m_nsduHandle;
m_nldeDataConfirmCallback(confirmParams);
}
return;
}
}
else
{
nwkHeader.SetMulticastMode(MulticastMode::NONMEMBER);
}
packet->AddHeader(nwkHeader);
if (groupMember)
{
// See 3.6.6.2.1: Group Members initiate the transmission
// using a broadcast (MAC level)
SendDataBcst(packet, params.m_nsduHandle);
}
else
{
// See 3.6.6.2.2: Non-Group member initiate the transmission
// using a unicast (MAC level) and search for the next hop
// in its routing table if necessary.
SendDataUcst(packet, params.m_nsduHandle);
}
return;
}
// CASE 2: The destination is a unicast address, a broadcast address
// or has no address (Many to one routing)
packet->AddHeader(nwkHeader);
if (capability.GetDeviceType() == ROUTER)
if (capability.GetDeviceType() == MacDeviceType::ROUTER)
{
if (params.m_dstAddrMode == MCST)
{
// The destination is MULTICAST (See 3.6.2)
NS_ABORT_MSG("Multicast is currently not supported");
// TODO
return;
}
else if (IsBroadcastAddress(params.m_dstAddr))
if (IsBroadcastAddress(params.m_dstAddr))
{
// The destination is BROADCAST (See 3.6.5)
SendDataBcst(packet, params.m_nsduHandle);
@@ -2223,6 +2512,10 @@ ZigbeeNwk::NlmeRouteDiscoveryRequest(NlmeRouteDiscoveryRequestParams params)
confirmParams.m_status = NwkStatus::INVALID_REQUEST;
m_nlmeRouteDiscoveryConfirmCallback(confirmParams);
}
NS_LOG_WARN("The destination address is a broadcast address, or the destination "
"address mode is NO_ADDRESS, cannot send route discovery request");
return;
}
@@ -2234,8 +2527,12 @@ ZigbeeNwk::NlmeRouteDiscoveryRequest(NlmeRouteDiscoveryRequestParams params)
{
NlmeRouteDiscoveryConfirmParams confirmParams;
confirmParams.m_status = NwkStatus::ROUTE_ERROR;
confirmParams.m_networkStatusCode = NetworkStatusCode::NO_ROUTING_CAPACITY;
m_nlmeRouteDiscoveryConfirmCallback(confirmParams);
}
NS_LOG_WARN("Device does not have routing capacity, cannot send route discovery request");
return;
}
@@ -2255,10 +2552,11 @@ ZigbeeNwk::NlmeRouteDiscoveryRequest(NlmeRouteDiscoveryRequestParams params)
payload.SetRouteReqId(m_routeRequestId.GetValue());
payload.SetPathCost(0);
if (params.m_dstAddrMode == UCST_BCST)
if (params.m_dstAddrMode == AddressMode::UCST_BCST || params.m_dstAddrMode == AddressMode::MCST)
{
// Set the rest of the nwkHeader and command payload parameters
// as described in Zigbee specification, Section 3.2.2.33.3
// Set the rest of the nwkHeader and command payload (RREQ) parameters
// as described in Zigbee specification r22.1.0, Section 3.2.2.33.3
if (params.m_radius == 0)
{
nwkHeader.SetRadius(m_nwkMaxDepth * 2);
@@ -2270,6 +2568,13 @@ ZigbeeNwk::NlmeRouteDiscoveryRequest(NlmeRouteDiscoveryRequestParams params)
payload.SetDstAddr(params.m_dstAddr);
if (params.m_dstAddrMode == AddressMode::MCST)
{
// Set the Multicast flag and proceed with the
// multicast destination route discovery
payload.SetMulticastField(true);
}
Mac16Address nextHop;
RouteDiscoveryStatus routeStatus =
FindNextHop(m_nwkNetworkAddress, 0, nwkHeader, payload, nextHop);
@@ -2298,10 +2603,6 @@ ZigbeeNwk::NlmeRouteDiscoveryRequest(NlmeRouteDiscoveryRequestParams params)
m_routeRequestId++;
}
}
else if (params.m_dstAddrMode == MCST)
{
NS_ABORT_MSG("Multicast Route discovery not supported");
}
else if (params.m_dstAddrMode == NO_ADDRESS)
{
// Many-to-one route discovery.

View File

@@ -12,6 +12,7 @@
#ifndef ZIGBEE_NWK_H
#define ZIGBEE_NWK_H
#include "zigbee-group-table.h"
#include "zigbee-nwk-fields.h"
#include "zigbee-nwk-header.h"
#include "zigbee-nwk-payload-header.h"
@@ -49,7 +50,7 @@ static constexpr uint32_t ALL_CHANNELS = 0x07FFF800; //!< Bitmap representing al
//!< Page 0 in Zigbee (250kbps O-QPSK)
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* Indicates a pending NWK primitive
*/
@@ -67,7 +68,7 @@ enum PendingPrimitiveNwk : std::uint8_t
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* Table 3.2 (Address Mode) NLDE-DATA-Request parameters
*/
@@ -137,7 +138,7 @@ enum RouteDiscoveryStatus : std::uint8_t
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* Network layer status values
* Combines Zigbee Specification r22.1.0 Table 3-73 and
@@ -235,7 +236,7 @@ std::ostream& operator<<(std::ostream& os, const std::vector<uint8_t>& vec);
std::ostream& operator<<(std::ostream& os, const uint8_t& num);
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* Status codes for network status command frame and route discovery failures.
*
@@ -265,7 +266,7 @@ enum NetworkStatusCode : std::uint8_t
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* Channel List Structure. See Zigbee Specification 3.2.2.2.1
*/
@@ -283,7 +284,7 @@ struct ChannelList
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLDE-DATA.confirm params. See Zigbee Specification 3.2.1.2
*/
@@ -297,7 +298,7 @@ struct NldeDataConfirmParams
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLDE-DATA.indication params. See Zigbee Specification 3.2.1.3.1
*/
@@ -315,7 +316,7 @@ struct NldeDataIndicationParams
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLDE-DATA.request params. See Zigbee Specification 3.2.1.1
*/
@@ -340,7 +341,7 @@ struct NldeDataRequestParams
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLME-NETWORK-FORMATION.request params. See Zigbee Specification 3.2.2.5.1
*/
@@ -372,7 +373,7 @@ struct NlmeNetworkFormationRequestParams
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* A group of pending parameters arranged into a structure during the execution of
* a NLME-NETWORK-FORMATION.request primitive.
@@ -385,7 +386,7 @@ struct NetFormPendingParamsGen : public SimpleRefCount<NetFormPendingParamsGen>
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLME-NETWORK-FORMATION.confirm params. See Zigbee Specification 3.2.2.6.1
*/
@@ -396,14 +397,15 @@ struct NlmeNetworkFormationConfirmParams
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLME-ROUTE-DISCOVERY.request params. See Zigbee Specification 3.2.2.33
*/
struct NlmeRouteDiscoveryRequestParams
{
AddressMode m_dstAddrMode{UCST_BCST}; //!< Specifies the kind of destination address.
Mac16Address m_dstAddr; //!< The destination of the route discovery.
Mac16Address m_dstAddr; //!< The 16-bit destination address or Group ID (MCST destination)
//!< of the route discovery.
uint16_t m_radius{0}; //!< Optional parameter that describes the number of hops that the
//!< route request will travel through the network.
bool m_noRouteCache{true}; //!< This flag determines whether the NWK should establish a
@@ -411,7 +413,7 @@ struct NlmeRouteDiscoveryRequestParams
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLME-ROUTE-DISCOVERY.confirm params. See Zigbee Specification r22.1.0, 3.2.2.34
*/
@@ -425,7 +427,7 @@ struct NlmeRouteDiscoveryConfirmParams
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLME-DIRECT-JOIN.request params.
* See Zigbee Specification r22.1.0, 3.2.2.16
@@ -438,7 +440,7 @@ struct NlmeDirectJoinRequestParams
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLME-DIRECT-JOIN.confirm params.
* See Zigbee Specification r22.1.0, 3.2.2.17
@@ -452,7 +454,7 @@ struct NlmeDirectJoinConfirmParams
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLME-NETWORK-DISCOVERY.request params.
* See Zigbee Specification r22.1.0, 3.2.2.3
@@ -492,7 +494,7 @@ struct NetworkDescriptor
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLME-NETWORK-DISCOVERY.confirm params. See Zigbee Specification r22.1.0, 3.2.2.4
*/
@@ -506,7 +508,7 @@ struct NlmeNetworkDiscoveryConfirmParams
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLME-JOIN.request params.
* See Zigbee Specification r22.1.0, 3.2.2.13
@@ -528,7 +530,7 @@ struct NlmeJoinRequestParams
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLME-JOIN.confirm params.
* See Zigbee Specification r22.1.0, 3.2.2.15
@@ -560,7 +562,7 @@ struct NlmeJoinConfirmParams
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLME-JOIN.indication params.
* See Zigbee Specification r22.1.0, 3.2.2.14
@@ -579,7 +581,7 @@ struct NlmeJoinIndicationParams
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLME-START-ROUTER.request params.
* See Zigbee Specification r22.1.0, 3.2.2.13
@@ -592,7 +594,7 @@ struct NlmeStartRouterRequestParams
};
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* NLME-START-ROUTER.confirm params.
* See Zigbee Specification r22.1.0, 3.2.2.10
@@ -608,7 +610,7 @@ struct NlmeStartRouterConfirmParams
//////////////////////
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* This callback is called after a NSDU has successfully received and
* NWK push it to deliver it to the next higher layer.
@@ -617,7 +619,7 @@ struct NlmeStartRouterConfirmParams
typedef Callback<void, NldeDataIndicationParams, Ptr<Packet>> NldeDataIndicationCallback;
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* This callback is used to notify the next higher layer with a confirmation in response to
* a previously issued NLDE-DATA.request.
@@ -626,7 +628,7 @@ typedef Callback<void, NldeDataIndicationParams, Ptr<Packet>> NldeDataIndication
typedef Callback<void, NldeDataConfirmParams> NldeDataConfirmCallback;
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* This callback is used to notify the next higher layer with a confirmation in response to
* a previously issued NLME-NETWORK-FORMATION.request.
@@ -634,7 +636,7 @@ typedef Callback<void, NldeDataConfirmParams> NldeDataConfirmCallback;
typedef Callback<void, NlmeNetworkFormationConfirmParams> NlmeNetworkFormationConfirmCallback;
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* This callback is used to notify the next higher layer with a confirmation in response to
* a previously issued NLME-NETWORK-DISCOVERY.request.
@@ -642,7 +644,7 @@ typedef Callback<void, NlmeNetworkFormationConfirmParams> NlmeNetworkFormationCo
typedef Callback<void, NlmeNetworkDiscoveryConfirmParams> NlmeNetworkDiscoveryConfirmCallback;
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* This callback is used to notify the next higher layer with a confirmation in response to
* a previously issued NLME-ROUTE-DISCOVERY.request.
@@ -650,7 +652,7 @@ typedef Callback<void, NlmeNetworkDiscoveryConfirmParams> NlmeNetworkDiscoveryCo
typedef Callback<void, NlmeRouteDiscoveryConfirmParams> NlmeRouteDiscoveryConfirmCallback;
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* This callback is used to notify the next higher layer with a confirmation in response to
* a previously issued NLME-DIRECT-JOIN.request.
@@ -658,7 +660,7 @@ typedef Callback<void, NlmeRouteDiscoveryConfirmParams> NlmeRouteDiscoveryConfir
typedef Callback<void, NlmeDirectJoinConfirmParams> NlmeDirectJoinConfirmCallback;
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* This callback is used to notify the next higher layer with a confirmation in response to
* a previously issued NLME-JOIN.request.
@@ -666,7 +668,7 @@ typedef Callback<void, NlmeDirectJoinConfirmParams> NlmeDirectJoinConfirmCallbac
typedef Callback<void, NlmeJoinConfirmParams> NlmeJoinConfirmCallback;
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* This callback is used to notify the next higher layer with an indication that a new
* device has successfully joined its network by association or rejoining.
@@ -674,7 +676,7 @@ typedef Callback<void, NlmeJoinConfirmParams> NlmeJoinConfirmCallback;
typedef Callback<void, NlmeJoinIndicationParams> NlmeJoinIndicationCallback;
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* This callback is used to notify the next higher layer with a confirmation in response to
* a previously issued NLME-START-ROUTER.request.
@@ -682,7 +684,7 @@ typedef Callback<void, NlmeJoinIndicationParams> NlmeJoinIndicationCallback;
typedef Callback<void, NlmeStartRouterConfirmParams> NlmeStartRouterConfirmCallback;
/**
* @ingroup zigbee
* @ingroup Zigbee
*
* Class that implements the Zigbee Specification Network Layer
*/
@@ -709,6 +711,13 @@ class ZigbeeNwk : public Object
*/
void SetMac(Ptr<lrwpan::LrWpanMacBase> mac);
/**
* Get the group table used by this Zigbee NWK.
*
* @param groupTable The pointer to the group table to set.
*/
void SetGroupTable(Ptr<ZigbeeGroupTable> groupTable);
/**
* Get the underlying MAC used by the current Zigbee NWK.
*
@@ -1283,6 +1292,12 @@ class ZigbeeNwk : public Object
*/
BroadcastTransactionTable m_btt;
/**
* The Group Table used by this Zigbee NWK.
* See Zigbee specification r22.1.0, 3.6.3.2
*/
Ptr<ZigbeeGroupTable> m_nwkGroupIdTable;
/**
* Enqueue a packet in the pending transmission queue until
* a route is discovered for its destination.
@@ -1445,6 +1460,30 @@ class ZigbeeNwk : public Object
ZigbeeNwkHeader nwkHeader,
ZigbeePayloadRouteReplyCommand payload);
/**
* Process a Multicast Frame received as a member of a multicast group.
* See Zigbee specification r22.1.0 Section 3.6.6.3
*
* @param nwkHeader The network header of the received multicast frame.
* @param msdu The MSDU (MSDU = MAC Service Data Unit) received
* @param params The MCPS-DATA.indication parameters associated to the received frame.
*/
void ReceiveMulticastMemberFrame(ZigbeeNwkHeader nwkHeader,
Ptr<Packet> msdu,
lrwpan::McpsDataIndicationParams params);
/**
* Process a Multicast Frame received as a non member of a multicast group.
* See Zigbee specification r22.1.0 Section 3.6.6.4
*
* @param nwkHeader The network header of the received multicast frame.
* @param msdu The MSDU (MSDU = MAC Service Data Unit) received
* @param params The MCPS-DATA.indication parameters associated to the received frame.
*/
void ReceiveMulticastNonMemberFrame(ZigbeeNwkHeader nwkHeader,
Ptr<Packet> msdu,
lrwpan::McpsDataIndicationParams params);
/**
* Returns true if the address is a broadcast address according to
* Zigbee specification r22.1.0, Section 3.6.5, Table 3-69
@@ -1480,6 +1519,18 @@ class ZigbeeNwk : public Object
*/
void SendDataBcst(Ptr<Packet> packet, uint8_t nwkHandle);
/**
* Send a data multicast packet to all the members of a multicast group.
*
* @param packet The NPDU (nwkHeader + data payload) to transmit.
* @param nwkHandle The NWK handle associated to this packet (nsdu handle).
* A handle of 0 implies that the unicast transmission is a
* retransmission and do not requires a handle which is
* used to identify a packet in confirmations to
* requests (NLDE-DATA.confirm).
*/
void SendDataMcst(Ptr<Packet> packet, uint8_t nwkHandle);
/**
* Find the next hop in route to a destination.
*
@@ -1526,6 +1577,11 @@ class ZigbeeNwk : public Object
*/
Ptr<UniformRandomVariable> m_rreqJitter;
/**
* Provides uniform random values for the broadcast jitter
*/
Ptr<UniformRandomVariable> m_bcstJitter;
/**
* Temporarily store beacons information from POS routers and PAN coordinators
* during a network-discovery process.
@@ -1613,6 +1669,14 @@ class ZigbeeNwk : public Object
*/
double m_nwkcMaxRREQJitter;
/**
* Minimum Broadcast jitter time (msec).
* Zigbee Specification r22.1.0, Table 3-57. Defined as a constant
* in the specification but here is defined as variable to allow the selection of values
* per device.
*/
double m_nwkcMaxBroadcastJitter;
//////////////////////////////
// Network layer attributes //
//////////////////////////////
@@ -1763,6 +1827,7 @@ class ZigbeeNwk : public Object
* The maximum time duration in milliseconds allowed for the parent all the child devices to
* retransmit a broadcast message.
* See Zigbe Specification r22.1.0, Table 3-58 (NIB attributes)
* See Zigbee-2007 Layer PICS and Stack Profiles
*/
Time m_nwkPassiveAckTimeout;

View File

@@ -41,6 +41,7 @@ ZigbeeStack::ZigbeeStack()
m_nwk = CreateObject<zigbee::ZigbeeNwk>();
m_aps = CreateObject<zigbee::ZigbeeAps>();
m_groupTable = Create<zigbee::ZigbeeGroupTable>();
m_nwkOnly = false;
}
@@ -59,6 +60,7 @@ ZigbeeStack::DoDispose()
m_node = nullptr;
m_aps = nullptr;
m_nwk = nullptr;
m_groupTable = nullptr;
m_mac = nullptr;
Object::DoDispose();
}
@@ -68,8 +70,6 @@ ZigbeeStack::DoInitialize()
{
NS_LOG_FUNCTION(this);
// AggregateObject(m_aps);
NS_ABORT_MSG_UNLESS(m_netDevice,
"Invalid NetDevice found when attempting to install ZigbeeStack");
@@ -108,10 +108,17 @@ ZigbeeStack::DoInitialize()
m_nwk->SetNldeDataConfirmCallback(MakeCallback(&ZigbeeAps::NldeDataConfirm, m_aps));
m_nwk->SetNldeDataIndicationCallback(MakeCallback(&ZigbeeAps::NldeDataIndication, m_aps));
m_nwk->SetGroupTable(m_groupTable);
m_aps->SetGroupTable(m_groupTable);
m_aps->Initialize();
m_aps->SetNwk(m_nwk);
AggregateObject(m_aps);
}
else
{
m_nwk->SetGroupTable(m_groupTable);
}
// Obtain Extended address as soon as NWK is set to begin operations
m_mac->MlmeGetRequest(MacPibAttributeIdentifier::macExtendedAddress);

View File

@@ -11,6 +11,7 @@
#define ZIGBEE_STACK_H
#include "zigbee-aps.h"
#include "zigbee-group-table.h"
#include "zigbee-nwk.h"
#include "ns3/lr-wpan-mac-base.h"
@@ -18,7 +19,6 @@
#include "ns3/traced-callback.h"
#include <stdint.h>
#include <string>
namespace ns3
{
@@ -136,8 +136,9 @@ class ZigbeeStack : public Object
Ptr<lrwpan::LrWpanMacBase> m_mac; //!< The underlying LrWpan MAC connected to this Zigbee Stack.
Ptr<ZigbeeNwk> m_nwk; //!< The Zigbee Network layer.
Ptr<ZigbeeAps> m_aps; //!< The Zigbee Application Support Sub-layer
Ptr<Node> m_node; //!< The node associated with this NetDevice.
Ptr<NetDevice> m_netDevice; //!< Smart pointer to the underlying NetDevice.
Ptr<ZigbeeGroupTable> m_groupTable; //!< The Zigbee Group Table used by both NWK and APS layers.
Ptr<Node> m_node; //!< The node associated with this NetDevice.
Ptr<NetDevice> m_netDevice; //!< Smart pointer to the underlying NetDevice.
bool m_nwkOnly; //!< Indicates that only the NWK layer is present in the Zigbee stack
};