From 278af89fa23d2af63c1db98ac786303ab970d23d Mon Sep 17 00:00:00 2001 From: skarg Date: Fri, 12 Aug 2016 21:57:57 +0000 Subject: [PATCH] Added enhancement to address cache: Top Protected Entry: entries from 0 to Top_Protected_Entry are not removed by address_remove_oldest()function. When I-am attack occurs only entries between Top_Protected_Entry and MAX_ADDRESS_CACHE can be removed. --- bacnet-stack/include/address.h | 16 +++++++ bacnet-stack/src/address.c | 80 ++++++++++++++++++++++++++++++---- 2 files changed, 88 insertions(+), 8 deletions(-) diff --git a/bacnet-stack/include/address.h b/bacnet-stack/include/address.h index af97fe3b..50b5aa4d 100644 --- a/bacnet-stack/include/address.h +++ b/bacnet-stack/include/address.h @@ -59,6 +59,13 @@ extern "C" { unsigned *max_apdu, BACNET_ADDRESS * src); + bool address_device_get_by_index( + unsigned index, + uint32_t * device_id, + uint32_t * device_ttl, + unsigned *max_apdu, + BACNET_ADDRESS * src); + bool address_get_device_id( BACNET_ADDRESS * src, uint32_t * device_id); @@ -75,6 +82,12 @@ extern "C" { unsigned *max_apdu, BACNET_ADDRESS * src); + bool address_device_bind_request( + uint32_t device_id, + uint32_t * device_ttl, + unsigned *max_apdu, + BACNET_ADDRESS * src); + void address_add_binding( uint32_t device_id, unsigned max_apdu, @@ -105,6 +118,9 @@ extern "C" { BACNET_MAC_ADDRESS *mac, char *arg); + void address_protected_entry_index_set(uint32_t top_protected_entry_index); + void address_own_device_id_set(uint32_t own_id); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bacnet-stack/src/address.c b/bacnet-stack/src/address.c index aa8321cb..3b364272 100644 --- a/bacnet-stack/src/address.c +++ b/bacnet-stack/src/address.c @@ -49,6 +49,9 @@ /* occurs in BACnet. A device id is bound to a MAC address. */ /* The normal method is using Who-Is, and using the data from I-Am */ +static uint32_t Top_Protected_Entry; +static uint32_t Own_Device_ID = 0xFFFFFFFF; + static struct Address_Cache_Entry { uint8_t Flags; uint32_t device_id; @@ -72,6 +75,17 @@ static struct Address_Cache_Entry { #define BAC_ADDR_SHORT_TIME BAC_ADDR_SECS_1HOUR #define BAC_ADDR_FOREVER 0xFFFFFFFF /* Permenant entry */ + +void address_protected_entry_index_set(uint32_t top_protected_entry_index) +{ + Top_Protected_Entry = top_protected_entry_index; +} + +void address_own_device_id_set(uint32_t own_id) +{ + Own_Device_ID = own_id; +} + bool address_match( BACNET_ADDRESS * dest, BACNET_ADDRESS * src) @@ -112,15 +126,20 @@ void address_remove_device( uint32_t device_id) { struct Address_Cache_Entry *pMatch; + int index = 0; pMatch = Address_Cache; while (pMatch <= &Address_Cache[MAX_ADDRESS_CACHE - 1]) { if (((pMatch->Flags & BAC_ADDR_IN_USE) != 0) && (pMatch->device_id == device_id)) { pMatch->Flags = 0; + if (index < Top_Protected_Entry) { + Top_Protected_Entry--; + } break; } pMatch++; + index++; } return; @@ -143,11 +162,14 @@ static struct Address_Cache_Entry *address_remove_oldest( uint32_t ulTime; pCandidate = NULL; + if (Top_Protected_Entry > (MAX_ADDRESS_CACHE - 1)) { + return pCandidate; + } ulTime = BAC_ADDR_FOREVER - 1; /* Longest possible non static time to live */ /* First pass - try only in use and bound entries */ - pMatch = Address_Cache; + pMatch = &Address_Cache[Top_Protected_Entry]; while (pMatch <= &Address_Cache[MAX_ADDRESS_CACHE - 1]) { if ((pMatch-> Flags & (BAC_ADDR_IN_USE | BAC_ADDR_BIND_REQ | @@ -341,6 +363,8 @@ void address_init( { struct Address_Cache_Entry *pMatch; + Top_Protected_Entry = 0; + pMatch = Address_Cache; while (pMatch <= &Address_Cache[MAX_ADDRESS_CACHE - 1]) { pMatch->Flags = 0; @@ -479,6 +503,10 @@ void address_add( bool found = false; /* return value */ struct Address_Cache_Entry *pMatch; + if (Own_Device_ID == device_id) { + return; + } + /* Note: Previously this function would ignore bind request marked entries and in fact would probably overwrite the first bind request entry blindly with the device info which may @@ -544,8 +572,9 @@ void address_add( /* returns true if device is already bound */ /* also returns the address and max apdu if already bound */ -bool address_bind_request( +bool address_device_bind_request( uint32_t device_id, + uint32_t * device_ttl, unsigned *max_apdu, BACNET_ADDRESS * src) { @@ -559,8 +588,15 @@ bool address_bind_request( (pMatch->device_id == device_id)) { if ((pMatch->Flags & BAC_ADDR_BIND_REQ) == 0) { /* Already bound */ found = true; - *src = pMatch->address; - *max_apdu = pMatch->max_apdu; + if (src) { + *src = pMatch->address; + } + if (max_apdu) { + *max_apdu = pMatch->max_apdu; + } + if (device_ttl) { + *device_ttl = pMatch->TimeToLive; + } if ((pMatch->Flags & BAC_ADDR_SHORT_TTL) != 0) { /* Was picked up opportunistacilly */ pMatch->Flags &= ~BAC_ADDR_SHORT_TTL; /* Convert to normal entry */ pMatch->TimeToLive = BAC_ADDR_LONG_TIME; /* And give it a decent time to live */ @@ -597,6 +633,15 @@ bool address_bind_request( return (false); } +/* returns true if device is already bound */ +/* also returns the address and max apdu if already bound */ +bool address_bind_request( + uint32_t device_id, + unsigned *max_apdu, + BACNET_ADDRESS * src) +{ + return address_device_bind_request(device_id, NULL, max_apdu, src); +} void address_add_binding( uint32_t device_id, @@ -626,9 +671,10 @@ void address_add_binding( return; } -bool address_get_by_index( +bool address_device_get_by_index( unsigned index, uint32_t * device_id, + uint32_t * device_ttl, unsigned *max_apdu, BACNET_ADDRESS * src) { @@ -639,9 +685,18 @@ bool address_get_by_index( pMatch = &Address_Cache[index]; if ((pMatch->Flags & (BAC_ADDR_IN_USE | BAC_ADDR_BIND_REQ)) == BAC_ADDR_IN_USE) { - *src = pMatch->address; - *device_id = pMatch->device_id; - *max_apdu = pMatch->max_apdu; + if (src) { + *src = pMatch->address; + } + if (device_id) { + *device_id = pMatch->device_id; + } + if (max_apdu) { + *max_apdu = pMatch->max_apdu; + } + if (device_ttl) { + *device_ttl = pMatch->TimeToLive; + } found = true; } } @@ -649,6 +704,15 @@ bool address_get_by_index( return found; } +bool address_get_by_index( + unsigned index, + uint32_t * device_id, + unsigned *max_apdu, + BACNET_ADDRESS * src) +{ + return address_device_get_by_index(index, device_id, NULL, max_apdu, src); +} + unsigned address_count( void) {