/******************************************************************************
* @fn dispatchFrame
*
* @brief Received frame looks OK so far. Dispatch to either NWK app by
* invoking the handler or the user's app by simply leaving the
* frame in the queue and letting the app poll the port.
*
* input parameters
* @param fiPtr - frameInfo_t pointer to received frame
*
* output parameters
*
* @return void
*/
static void dispatchFrame(frameInfo_t *fiPtr)
{
uint8_t port = GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_PORT_OS);
uint8_t nwkAppSize = sizeof(func)/sizeof(func[0]);
fhStatus_t rc;
linkID_t lid;
#if defined(ACCESS_POINT)
uint8_t loc;
#endif
#if !defined(END_DEVICE)
uint8_t isForMe;
#endif
/* be sure it's not an echo... */
if (!memcmp(MRFI_P_SRC_ADDR(&fiPtr->mrfiPkt), sMyAddr, NET_ADDR_SIZE))
{
fiPtr->fi_usage = FI_AVAILABLE;
return;
}
/* Make sure encyrption bit conforms to our security support context. */
#if defined(SMPL_SECURE)
if (!(GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_ENCRYPT_OS)))
{
/* Encyrption bit is not on when when it should be */
fiPtr->fi_usage = FI_AVAILABLE;
return;
}
#else
if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_ENCRYPT_OS))
{
/* Encyrption bit is on when when it should not be */
fiPtr->fi_usage = FI_AVAILABLE;
return;
}
#endif /* SMPL_SECURE */
/* If it's a network application port dispatch to service routine. Dispose
* of frame depending on return code.
*/
if (port && (port <= nwkAppSize))
{
#if defined(SMPL_SECURE)
/* Non-connection-based frame. We can decode here if it was encrypted */
if (!nwk_getSecureFrame(&fiPtr->mrfiPkt, MRFI_GET_PAYLOAD_LEN(&fiPtr->mrfiPkt) - F_SEC_CTR_OS, 0))
{
fiPtr->fi_usage = FI_AVAILABLE;
return;
}
#endif
rc = func[port-1](&fiPtr->mrfiPkt);
if (FHS_KEEP == rc)
{
fiPtr->fi_usage = FI_INUSE_UNTIL_DEL;
}
#if !defined(END_DEVICE)
else if (FHS_REPLAY == rc)
{
/* an AP or an RE could be relaying a NWK application frame... */
nwk_replayFrame(fiPtr);
}
#endif
else /* rc == FHS_RELEASE (default...) */
{
fiPtr->fi_usage = FI_AVAILABLE;
}
return;
}
/* sanity check */
else if ((port != SMPL_PORT_USER_BCAST) && ((port < PORT_BASE_NUMBER) || (port > SMPL_PORT_STATIC_MAX)))
{
/* bogus port. drop frame */
fiPtr->fi_usage = FI_AVAILABLE;
return;
}
/* At this point we know the target is a user app. If this is an end device
* and we got this far save the frame and we're done. If we're an AP there
* are 3 cases: it's for us, it's for s store-and-forward client, or we need
* to replay the frame. If we're and RE and the frame didn't come from an RE
* and it's not for us, replay the frame.
*/
#if defined(END_DEVICE)
/* If we're s polling end device we only accept application frames from
* the AP. This prevents duplicate reception if we happen to be on when
* a linked peer sends.
*/
#if defined(RX_POLLS)
if (F_TX_DEVICE_ED != GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_TX_DEVICE))
{
if (nwk_isConnectionValid(&fiPtr->mrfiPkt, &lid))
{
fiPtr->fi_usage = FI_INUSE_UNTIL_DEL;
}
else
{
fiPtr->fi_usage = FI_AVAILABLE;
}
}
else
{
fiPtr->fi_usage = FI_AVAILABLE;
}
#else
/* it's destined for a user app. */
if (nwk_isConnectionValid(&fiPtr->mrfiPkt, &lid))
{
fiPtr->fi_usage = FI_INUSE_UNTIL_DEL;
if (spCallback && spCallback(lid))
{
fiPtr->fi_usage = FI_AVAILABLE;
return;
}
}
else
{
fiPtr->fi_usage = FI_AVAILABLE;
}
#endif /* RX_POLLS */
#else /* END_DEVICE */
/* We have an issue if the frame is broadcast to the UUD port. The AP (or RE) must
* handle this frame as if it were the target in case there is an application
* running that is listening on that port. But if it's a broadcast it must also be
* replayed. It isn't enough just to test for the UUD port because it could be a
* directed frame to another device. We must check explicitly for broadcast
* destination address.
*/
isForMe = !memcmp(sMyAddr, MRFI_P_DST_ADDR(&fiPtr->mrfiPkt), NET_ADDR_SIZE);
if (isForMe || ((port == SMPL_PORT_USER_BCAST) && !memcmp(nwk_getBCastAddress(), MRFI_P_DST_ADDR(&fiPtr->mrfiPkt), NET_ADDR_SIZE)))
{
/* The folllowing test will succeed for the UUD port regardless of the
* source address.
*/
if (nwk_isConnectionValid(&fiPtr->mrfiPkt, &lid))
{
/* If this is for the UUD port and we are here then the device is either
* an AP or an RE. In either case it must replay the UUD port frame if the
* frame is not "for me". But it also must handle it since it could have a
* UUD-listening application. Do the reply first and let the subsequent code
* correctly set the frame usage state. Note that the routine return can be
* from this code block. If not it will drop through to the bottom without
* doing a replay.
*/
/* Do I need to replay it? */
if (!isForMe)
{
/* must be a broadcast for the UUD port */
nwk_replayFrame(fiPtr);
}
/* OK. Now I handle it... */
fiPtr->fi_usage = FI_INUSE_UNTIL_DEL;
if (spCallback && spCallback(lid))
{
fiPtr->fi_usage = FI_AVAILABLE;
return;
}
}
else
{
fiPtr->fi_usage = FI_AVAILABLE;
}
}
#if defined( ACCESS_POINT )
/* Check to see if we need to save this for a S and F client. Otherwise,
* if it's not for us, get rid of it.
*/
else if (nwk_isSandFClient(MRFI_P_DST_ADDR(&fiPtr->mrfiPkt), &loc))
{
/* Don't bother if it is a duplicate frame or if it's a forwarded frame
* echoed back from an RE.
*/
if (!isDupSandFFrame(&fiPtr->mrfiPkt) &&
!(GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_FWD_FRAME))
)
{
#if defined(APP_AUTO_ACK)
/* Make sure ack request bit is off. Sender will have gone away. */
PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_ACK_REQ, 0);
#endif
fiPtr->fi_usage = FI_INUSE_UNTIL_FWD;
}
else
{
fiPtr->fi_usage = FI_AVAILABLE;
}
}
else if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_TX_DEVICE) == F_TX_DEVICE_AP)
{
/* I'm an AP and this frame came from an AP. Don't replay. */
fiPtr->fi_usage = FI_AVAILABLE;
}
#elif defined( RANGE_EXTENDER )
else if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_TX_DEVICE) == F_TX_DEVICE_RE)
{
/* I'm an RE and this frame came from an RE. Don't replay. */
fiPtr->fi_usage = FI_AVAILABLE;
}
#endif
else
{
/* It's not for me and I'm either an AP or I'm an RE and the frame
* didn't come from an RE. Replay the frame.
*/
nwk_replayFrame(fiPtr);
}
#endif /* !END_DEVICE */
return;
}
红色部分代码,迷惑...... ctrl+shift+f 找了好久,都不知道func怎么来的。看过的指导下......
|