static void My_NPDU_Handler( BACNET_ADDRESS * src, /* source address */ uint8_t * pdu, /* PDU data */ uint16_t pdu_len) { /* length PDU */ int apdu_offset = 0; BACNET_ADDRESS dest = { 0 }; BACNET_NPDU_DATA npdu_data = { 0 }; apdu_offset = npdu_decode(&pdu[0], &dest, src, &npdu_data); if (npdu_data.network_layer_message) { if (apdu_offset <= pdu_len) { My_Router_Handler(src, &npdu_data, &pdu[apdu_offset], (uint16_t) (pdu_len - apdu_offset)); } } else if ((apdu_offset > 0) && (apdu_offset <= pdu_len)) { if ((npdu_data.protocol_version == BACNET_PROTOCOL_VERSION) && ((dest.net == 0) || (dest.net == BACNET_BROADCAST_NETWORK))) { /* only handle the version that we know how to handle */ /* and we are not a router, so ignore messages with routing information cause they are not for us */ apdu_handler(src, &pdu[apdu_offset], (uint16_t) (pdu_len - apdu_offset)); } else { if (dest.net) { debug_printf("NPDU: DNET=%d. Discarded!\n", dest.net); } else { debug_printf("NPDU: BACnet Protocol Version=%d. Discarded!\n", npdu_data.protocol_version); } } } return; }
void testNPDU1( Test * pTest) { uint8_t pdu[480] = { 0 }; BACNET_ADDRESS dest = { 0 }; BACNET_ADDRESS src = { 0 }; BACNET_ADDRESS npdu_dest = { 0 }; BACNET_ADDRESS npdu_src = { 0 }; int len = 0; bool data_expecting_reply = false; BACNET_MESSAGE_PRIORITY priority = MESSAGE_PRIORITY_NORMAL; BACNET_NPDU_DATA npdu_data = { 0 }; int i = 0; /* counter */ int npdu_len = 0; bool network_layer_message = false; /* false if APDU */ BACNET_NETWORK_MESSAGE_TYPE network_message_type = 0; /* optional */ uint16_t vendor_id = 0; /* optional, if net message type is > 0x80 */ /* mac_len = 0 if global address */ dest.mac_len = 0; for (i = 0; i < MAX_MAC_LEN; i++) { dest.mac[i] = 0; } /* DNET,DLEN,DADR */ dest.net = 0; dest.len = 0; for (i = 0; i < MAX_MAC_LEN; i++) { dest.adr[i] = 0; } src.mac_len = 0; for (i = 0; i < MAX_MAC_LEN; i++) { src.mac[i] = 0; } /* SNET,SLEN,SADR */ src.net = 0; src.len = 0; for (i = 0; i < MAX_MAC_LEN; i++) { src.adr[i] = 0; } npdu_encode_npdu_data(&npdu_data, false, priority); len = npdu_encode_pdu(&pdu[0], &dest, &src, &npdu_data); ct_test(pTest, len != 0); /* can we get the info back? */ npdu_len = npdu_decode(&pdu[0], &npdu_dest, &npdu_src, &npdu_data); ct_test(pTest, npdu_len != 0); ct_test(pTest, npdu_data.data_expecting_reply == data_expecting_reply); ct_test(pTest, npdu_data.network_layer_message == network_layer_message); if (npdu_data.network_layer_message) { ct_test(pTest, npdu_data.network_message_type == network_message_type); } ct_test(pTest, npdu_data.vendor_id == vendor_id); ct_test(pTest, npdu_data.priority == priority); ct_test(pTest, npdu_dest.mac_len == src.mac_len); ct_test(pTest, npdu_src.mac_len == dest.mac_len); }
/** Handler for the NPDU portion of a received packet. * Aside from error-checking, if the NPDU doesn't contain routing info, * this handler doesn't do much besides stepping over the NPDU header * and passing the remaining bytes to the apdu_handler. * @note The routing (except src) and NCPI information, including * npdu_data->data_expecting_reply, are discarded. * @see routing_npdu_handler * * @ingroup MISCHNDLR * * @param src [out] Returned with routing source information if the NPDU * has any and if this points to non-null storage for it. * If src->net and src->len are 0 on return, there is no * routing source information. * This src describes the original source of the message when * it had to be routed to reach this BACnet Device, and this * is passed down into the apdu_handler; however, I don't * think this project's code has any use for the src info * on return from this handler, since the response has * already been sent via the apdu_handler. * @param pdu [in] Buffer containing the NPDU and APDU of the received packet. * @param pdu_len [in] The size of the received message in the pdu[] buffer. */ void npdu_handler( PORT_SUPPORT *portParams, BACNET_ADDRESS * src, /* source address */ uint8_t * pdu, /* PDU data */ uint16_t pdu_len) { /* length PDU */ int apdu_offset = 0; BACNET_ADDRESS dest = { 0 }; BACNET_NPDU_DATA npdu_data = { 0 }; /* only handle the version that we know how to handle */ if (pdu[0] == BACNET_PROTOCOL_VERSION) { apdu_offset = npdu_decode(&pdu[0], &dest, src, &npdu_data); if (npdu_data.network_layer_message) { /*FIXME: network layer message received! Handle it! */ #if PRINT_ENABLED fprintf(stderr, "NPDU: Network Layer Message discarded!\n"); #endif } else if ((apdu_offset > 0) && (apdu_offset <= pdu_len)) { if ((dest.net == 0) || (dest.net == BACNET_BROADCAST_NETWORK)) { /* only handle the version that we know how to handle */ /* and we are not a router, so ignore messages with routing information cause they are not for us */ if ((dest.net == BACNET_BROADCAST_NETWORK) && ((pdu[apdu_offset] & 0xF0) == PDU_TYPE_CONFIRMED_SERVICE_REQUEST)) { /* hack for 5.4.5.1 - IDLE */ /* ConfirmedBroadcastReceived */ /* then enter IDLE - ignore the PDU */ } else { apdu_handler(portParams, src, &pdu[apdu_offset], (uint16_t) (pdu_len - apdu_offset)); } } else { #if PRINT_ENABLED printf("NPDU: DNET=%u. Discarded!\n", (unsigned) dest.net); #endif } } } else { #if PRINT_ENABLED printf("NPDU: BACnet Protocol Version=%u. Discarded!\n", (unsigned) pdu[0]); #endif } return; }
static void mstp_monitor_i_am( uint8_t mac, uint8_t *pdu, uint16_t pdu_len) { BACNET_ADDRESS src = { 0 }; BACNET_ADDRESS dest = { 0 }; BACNET_NPDU_DATA npdu_data = { 0 }; int apdu_offset = 0; uint16_t apdu_len = 0; uint8_t *apdu = NULL; uint8_t pdu_type = 0; uint8_t service_choice = 0; uint8_t *service_request = NULL; uint32_t device_id = 0; int len = 0; if (pdu[0] == BACNET_PROTOCOL_VERSION) { MSTP_Fill_BACnet_Address(&src, mac); apdu_offset = npdu_decode(&pdu[0], &dest, &src, &npdu_data); if ((!npdu_data.network_layer_message) && (apdu_offset > 0) && (apdu_offset < pdu_len) && ((dest.net == 0) || (dest.net == BACNET_BROADCAST_NETWORK)) && (src.net == 0)) { apdu_len = pdu_len - apdu_offset; apdu = &pdu[apdu_offset]; pdu_type = apdu[0] & 0xF0; if ((pdu_type == PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST) && (apdu_len >= 2)) { service_choice = apdu[1]; service_request = &apdu[2]; if (service_choice == SERVICE_UNCONFIRMED_I_AM) { len = iam_decode_service_request(service_request, &device_id, NULL, NULL, NULL); if (len != -1) { MSTP_Statistics[mac].device_id = device_id; } } } } } }
/** Handler for the NPDU portion of a received packet, which may have routing. * This is a fuller handler than the regular npdu_handler, as it manages * - Decoding of the NCPI byte * - Further processing by network_control_handler() if this is a network * layer message. * - Further processing by routed_apdu_handler() if it contains an APDU * - Normally (no routing) by apdu_handler() * - With Routing (a further destination was indicated) by the decoded * destination. * - Errors in decoding. * @note The npdu_data->data_expecting_reply status is discarded. * @see npdu_handler * @ingroup NMRC * * @param src [out] Returned with routing source information if the NPDU * has any and if this points to non-null storage for it. * If src->net and src->len are 0 on return, there is no * routing source information. * This src describes the original source of the message when * it had to be routed to reach this BACnet Device, and this * is passed down into the apdu_handler; however, I don't * think this project's code has any use for the src info * on return from this handler, since the response has * already been sent via the apdu_handler. * @param DNET_list [in] List of our reachable downstream BACnet Network numbers. * Normally just one valid entry; terminated with a -1 value. * @param pdu [in] Buffer containing the NPDU and APDU of the received packet. * @param pdu_len [in] The size of the received message in the pdu[] buffer. */ void routing_npdu_handler( BACNET_ADDRESS * src, int *DNET_list, uint8_t * pdu, uint16_t pdu_len) { int apdu_offset = 0; BACNET_ADDRESS dest = { 0 }; BACNET_NPDU_DATA npdu_data = { 0 }; /* only handle the version that we know how to handle */ if (pdu[0] == BACNET_PROTOCOL_VERSION) { apdu_offset = npdu_decode(&pdu[0], &dest, src, &npdu_data); if (apdu_offset <= 0) { debug_printf("NPDU: Decoding failed; Discarded!\n"); } else if (npdu_data.network_layer_message) { if ((dest.net == 0) || (dest.net == BACNET_BROADCAST_NETWORK)) { network_control_handler(src, DNET_list, &npdu_data, &pdu[apdu_offset], (uint16_t) (pdu_len - apdu_offset)); } else { /* The DNET is set, but we don't support downstream routers, * so we just silently drop this network layer message, * since only routers can handle it (even if for our DNET) */ } } else if (apdu_offset <= pdu_len) { if ((dest.net == 0) || (npdu_data.hop_count > 1)) routed_apdu_handler(src, &dest, DNET_list, &pdu[apdu_offset], (uint16_t) (pdu_len - apdu_offset)); /* Else, hop_count bottomed out and we discard this one. */ } } else { /* Should we send NETWORK_MESSAGE_REJECT_MESSAGE_TO_NETWORK? */ debug_printf ("NPDU: Unsupported BACnet Protocol Version=%u. Discarded!\n", (unsigned) pdu[0]); } return; }
/** Handler for the NPDU portion of a received packet. * Aside from error-checking, if the NPDU doesn't contain routing info, * this handler doesn't do much besides stepping over the NPDU header * and passing the remaining bytes to the apdu_handler. * @note The routing (except src) and NCPI information, including * npdu_data->data_expecting_reply, are discarded. * @see routing_npdu_handler * * @ingroup MISCHNDLR * * @param src [out] Returned with routing source information if the NPDU * has any and if this points to non-null storage for it. * If src->net and src->len are 0 on return, there is no * routing source information. * This src describes the original source of the message when * it had to be routed to reach this BACnet Device, and this * is passed down into the apdu_handler; however, I don't * think this project's code has any use for the src info * on return from this handler, since the response has * already been sent via the apdu_handler. * @param pdu [in] Buffer containing the NPDU and APDU of the received packet. * @param pdu_len [in] The size of the received message in the pdu[] buffer. */ void npdu_handler( BACNET_ADDRESS * src, /* source address */ uint8_t * pdu, /* PDU data */ uint16_t pdu_len) { /* length PDU */ int apdu_offset = 0; BACNET_ADDRESS dest = { 0 }; BACNET_NPDU_DATA npdu_data = { 0 }; /* only handle the version that we know how to handle */ if (pdu[0] == BACNET_PROTOCOL_VERSION) { apdu_offset = npdu_decode(&pdu[0], &dest, src, &npdu_data); if (npdu_data.network_layer_message) { /*FIXME: network layer message received! Handle it! */ #ifdef PRINT_ENABLE fprintf(stderr, "NPDU: Network Layer Message discarded!\n"); #endif } else if ((apdu_offset > 0) && (apdu_offset <= pdu_len)) { if ((dest.net == 0) || (dest.net == BACNET_BROADCAST_NETWORK)) { /* only handle the version that we know how to handle */ /* and we are not a router, so ignore messages with routing information cause they are not for us */ apdu_handler(src, &pdu[apdu_offset], (uint16_t) (pdu_len - apdu_offset)); } else { #ifdef PRINT_ENABLE fprintf(stderr, "NPDU: DNET=%u. Discarded!\n", (unsigned) dest.net); #endif } } } else { #ifdef PRINT_ENABLE fprintf(stderr, "NPDU: BACnet Protocol Version=%u. Discarded!\n", (unsigned) pdu[0]); #endif } return; }
bool dlmstp_compare_data_expecting_reply( uint8_t * request_pdu, uint16_t request_pdu_len, uint8_t src_address, uint8_t * reply_pdu, uint16_t reply_pdu_len, BACNET_ADDRESS * dest_address) { uint16_t offset; /* One way to check the message is to compare NPDU src, dest, along with the APDU type, invoke id. Seems a bit overkill */ struct DER_compare_t { BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS address; uint8_t pdu_type; uint8_t invoke_id; uint8_t service_choice; }; struct DER_compare_t request; struct DER_compare_t reply; /* unused parameters */ request_pdu_len = request_pdu_len; reply_pdu_len = reply_pdu_len; /* decode the request data */ request.address.mac[0] = src_address; request.address.mac_len = 1; offset = npdu_decode(&request_pdu[0], NULL, &request.address, &request.npdu_data); if (request.npdu_data.network_layer_message) { return false; } request.pdu_type = request_pdu[offset] & 0xF0; if (request.pdu_type != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) { return false; } request.invoke_id = request_pdu[offset + 2]; /* segmented message? */ if (request_pdu[offset] & BIT3) request.service_choice = request_pdu[offset + 5]; else request.service_choice = request_pdu[offset + 3]; /* decode the reply data */ bacnet_address_copy(&reply.address, dest_address); offset = npdu_decode(&reply_pdu[0], &reply.address, NULL, &reply.npdu_data); if (reply.npdu_data.network_layer_message) { return false; } /* reply could be a lot of things: confirmed, simple ack, abort, reject, error */ reply.pdu_type = reply_pdu[offset] & 0xF0; switch (reply.pdu_type) { case PDU_TYPE_CONFIRMED_SERVICE_REQUEST: reply.invoke_id = reply_pdu[offset + 2]; /* segmented message? */ if (reply_pdu[offset] & BIT3) reply.service_choice = reply_pdu[offset + 5]; else reply.service_choice = reply_pdu[offset + 3]; break; case PDU_TYPE_SIMPLE_ACK: reply.invoke_id = reply_pdu[offset + 1]; reply.service_choice = reply_pdu[offset + 2]; break; case PDU_TYPE_COMPLEX_ACK: reply.invoke_id = reply_pdu[offset + 1]; /* segmented message? */ if (reply_pdu[offset] & BIT3) reply.service_choice = reply_pdu[offset + 4]; else reply.service_choice = reply_pdu[offset + 2]; break; case PDU_TYPE_ERROR: reply.invoke_id = reply_pdu[offset + 1]; reply.service_choice = reply_pdu[offset + 2]; break; case PDU_TYPE_REJECT: case PDU_TYPE_ABORT: reply.invoke_id = reply_pdu[offset + 1]; break; default: return false; } /* these don't have service choice included */ if ((reply.pdu_type == PDU_TYPE_REJECT) || (reply.pdu_type == PDU_TYPE_ABORT)) { if (request.invoke_id != reply.invoke_id) { return false; } } else { if (request.invoke_id != reply.invoke_id) { return false; } if (request.service_choice != reply.service_choice) { return false; } } if (request.npdu_data.protocol_version != reply.npdu_data.protocol_version) { return false; } if (request.npdu_data.priority != reply.npdu_data.priority) { return false; } if (!bacnet_address_same(&request.address, &reply.address)) { return false; } return true; }