void testAddress( Test * pTest) { unsigned i, count; BACNET_ADDRESS src; uint32_t device_id = 0; unsigned max_apdu = 480; BACNET_ADDRESS test_address; uint32_t test_device_id = 0; unsigned test_max_apdu = 0; /* create a fake address database */ for (i = 0; i < MAX_ADDRESS_CACHE; i++) { set_address(i, &src); device_id = i * 255; address_add(device_id, max_apdu, &src); count = address_count(); ct_test(pTest, count == (i + 1)); } for (i = 0; i < MAX_ADDRESS_CACHE; i++) { device_id = i * 255; set_address(i, &src); /* test the lookup by device id */ ct_test(pTest, address_get_by_device(device_id, &test_max_apdu, &test_address)); ct_test(pTest, test_max_apdu == max_apdu); ct_test(pTest, bacnet_address_same(&test_address, &src)); ct_test(pTest, address_get_by_index(i, &test_device_id, &test_max_apdu, &test_address)); ct_test(pTest, test_device_id == device_id); ct_test(pTest, test_max_apdu == max_apdu); ct_test(pTest, bacnet_address_same(&test_address, &src)); ct_test(pTest, address_count() == MAX_ADDRESS_CACHE); /* test the lookup by MAC */ ct_test(pTest, address_get_device_id(&src, &test_device_id)); ct_test(pTest, test_device_id == device_id); } for (i = 0; i < MAX_ADDRESS_CACHE; i++) { device_id = i * 255; address_remove_device(device_id); ct_test(pTest, !address_get_by_device(device_id, &test_max_apdu, &test_address)); count = address_count(); ct_test(pTest, count == (MAX_ADDRESS_CACHE - i - 1)); } }
void testAddressFile( Test * pTest) { BACNET_ADDRESS src = { 0 }; uint32_t device_id = 0; unsigned max_apdu = 480; BACNET_ADDRESS test_address = { 0 }; unsigned test_max_apdu = 0; /* create a fake address */ device_id = 55555; src.mac_len = 1; src.mac[0] = 25; src.net = 0; src.adr[0] = 0; max_apdu = 50; set_file_address(Address_Cache_Filename, device_id, &src, max_apdu); /* retrieve it from the file, and see if we can find it */ address_file_init(Address_Cache_Filename); ct_test(pTest, address_get_by_device(device_id, &test_max_apdu, &test_address)); ct_test(pTest, test_max_apdu == max_apdu); ct_test(pTest, bacnet_address_same(&test_address, &src)); /* create a fake address */ device_id = 55555; src.mac_len = 6; src.mac[0] = 0xC0; src.mac[1] = 0xA8; src.mac[2] = 0x00; src.mac[3] = 0x18; src.mac[4] = 0xBA; src.mac[5] = 0xC0; src.net = 26001; src.len = 1; src.adr[0] = 25; max_apdu = 50; set_file_address(Address_Cache_Filename, device_id, &src, max_apdu); /* retrieve it from the file, and see if we can find it */ address_file_init(Address_Cache_Filename); ct_test(pTest, address_get_by_device(device_id, &test_max_apdu, &test_address)); ct_test(pTest, test_max_apdu == max_apdu); ct_test(pTest, bacnet_address_same(&test_address, &src)); }
/** * Adds the address to the list of COV addresses * * @param dest - address to be added if there is room in the list * * @return index number 0..N, or -1 if unable to add */ static int cov_address_add( BACNET_ADDRESS * dest) { int index = -1; unsigned i = 0; bool found = false; bool valid = false; BACNET_ADDRESS *cov_dest = NULL; if (dest) { for (i = 0; i < MAX_COV_ADDRESSES; i++) { valid = COV_Addresses[i].valid; if (valid) { cov_dest = &COV_Addresses[i].dest; found = bacnet_address_same(dest, cov_dest); if (found) { index = i; break; } } } if (!found) { /* find a free place to add a new address */ for (i = 0; i < MAX_COV_ADDRESSES; i++) { valid = COV_Addresses[i].valid; if (!valid) { index = i; cov_dest = &COV_Addresses[i].dest; bacnet_address_copy(cov_dest, dest); COV_Addresses[i].valid = true; break; } } } } return index; }
bool address_get_device_id( BACNET_ADDRESS * src, uint32_t * device_id) { struct Address_Cache_Entry *pMatch; bool found = false; /* return value */ pMatch = Address_Cache; while (pMatch <= &Address_Cache[MAX_ADDRESS_CACHE - 1]) { if ((pMatch->Flags & (BAC_ADDR_IN_USE | BAC_ADDR_BIND_REQ)) == BAC_ADDR_IN_USE) { /* If bound */ if (bacnet_address_same(&pMatch->address, src)) { if (device_id) { *device_id = pMatch->device_id; } found = true; break; } } pMatch++; } return found; }
static bool cov_list_subscribe( BACNET_ADDRESS * src, BACNET_SUBSCRIBE_COV_DATA * cov_data, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) { bool existing_entry = false; int index; int first_invalid_index = -1; bool found = true; /* unable to subscribe - resources? */ /* unable to cancel subscription - other? */ /* existing? - match Object ID and Process ID */ for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) { if (COV_Subscriptions[index].flag.valid) { if ((COV_Subscriptions[index].monitoredObjectIdentifier.type == cov_data->monitoredObjectIdentifier.type) && (COV_Subscriptions[index].monitoredObjectIdentifier.instance == cov_data->monitoredObjectIdentifier.instance) && (COV_Subscriptions[index].subscriberProcessIdentifier == cov_data->subscriberProcessIdentifier) && bacnet_address_same(src, &COV_Subscriptions[index].dest)) { existing_entry = true; if (cov_data->cancellationRequest) { COV_Subscriptions[index].flag.valid = false; } else { bacnet_address_copy(&COV_Subscriptions[index].dest, src); COV_Subscriptions[index].flag.issueConfirmedNotifications = cov_data->issueConfirmedNotifications; COV_Subscriptions[index].lifetime = cov_data->lifetime; COV_Subscriptions[index].flag.send_requested = true; } if (COV_Subscriptions[index].invokeID) { tsm_free_invoke_id(COV_Subscriptions[index].invokeID); COV_Subscriptions[index].invokeID = 0; } break; } } else { if (first_invalid_index < 0) { first_invalid_index = index; } } } if (!existing_entry && (first_invalid_index >= 0) && (!cov_data->cancellationRequest)) { index = first_invalid_index; found = true; COV_Subscriptions[index].flag.valid = true; bacnet_address_copy(&COV_Subscriptions[index].dest, src); COV_Subscriptions[index].monitoredObjectIdentifier.type = cov_data->monitoredObjectIdentifier.type; COV_Subscriptions[index].monitoredObjectIdentifier.instance = cov_data->monitoredObjectIdentifier.instance; COV_Subscriptions[index].subscriberProcessIdentifier = cov_data->subscriberProcessIdentifier; COV_Subscriptions[index].flag.issueConfirmedNotifications = cov_data->issueConfirmedNotifications; COV_Subscriptions[index].invokeID = 0; COV_Subscriptions[index].lifetime = cov_data->lifetime; COV_Subscriptions[index].flag.send_requested = true; } else if (!existing_entry) { if (first_invalid_index < 0) { /* Out of resources */ *error_class = ERROR_CLASS_RESOURCES; *error_code = ERROR_CODE_NO_SPACE_TO_ADD_LIST_ELEMENT; found = false; } else { /* cancellationRequest - valid object not subscribed */ /* From BACnet Standard 135-2010-13.14.2 ...Cancellations that are issued for which no matching COV context can be found shall succeed as if a context had existed, returning 'Result(+)'. */ found = true; } } return found; }
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; }