Issue 2 move folders and use deep path include file names to prevent collisions (#4)

* moving folders and files and adjust server demo build

* Fix Makefile for apps/server on Linux

* fix unit test source file folders

* fix datetime convert UTC functions. Add Code::Blocks project for datetime testing

* added some ignore extensions

* disable parallel make option

* fix build for abort, dcc, and epics apps

* fix build for dcc, epics, error, and getevent apps.

* Fixed building of all apps

* fix the ipv4 to ipv6 router app build

* Change indent style from Google to Webkit

* make pretty to re-format style

* removed common Makefile since we already had one and two was too many

* remove scripts from root folder that are no longer maintained or used

* remove mercurial EOL and ignore files for git repo

* remove .vscodeconfig files from repo

* tweak clang-format style

* clang-format src and apps with tweaked style

* added clang-tidy to fix readability if braces in src

* result of make tidy for src and apps

* fix clang-tidy mangling

* Added code::blocks project for BACnet server simulation

* added code::blocks linux project for WhoIs app

* update text files for EOL

* fix EOL in some files

* fixed make win32 apps for older gcc

* Removed Borland C++ Makefile in apps. Unable to maintain support for Borland C++ compiler.

* created codeblocks project for apps/epics for Windows

* fixing ports/xplained to work with new data structure.

* fix ports/xplained example for Atmel Studio compile

* fix ports/stm32f10x example for gcc Makefile compile

* fix ports/stm32f10x example for IAR EWARM compile

* fix ports/xplained timer callback

* fix ports/bdk_atxx_mspt build with subdirs

* fix ports/bdk_atxx_mspt build with subdirs

* updated git ignore for IAR build artifacts

* updated gitignore for non-tracked files and folders

* fixed bdk-atxx4-mstp port for Rowley Crossworks project file

* fixed bdk-atxx4-mstp port for GCC AVR Makefile

* fixed atmega168 port for IAR AVR and GCC AVR Makefile

* fixed at91sam7s port for IAR ARM and GCC ARM Makefile

* removed unmaintainable DOS, RTOS32, and atmega8 ports.  Updated rx62n (untested).

* changed arm7 to uip port
This commit is contained in:
Steve Karg
2019-12-13 15:19:10 -06:00
committed by GitHub
parent 8a38dbe2cf
commit d50c190957
912 changed files with 36206 additions and 52502 deletions
+72
View File
@@ -0,0 +1,72 @@
/**************************************************************************
*
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*********************************************************************/
#ifndef ARCNET_H
#define ARCNET_H
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include "bacnet/bacdef.h"
#include "bacnet/npdu.h"
/* specific defines for ARCNET */
#define MAX_HEADER (1+1+2+2+1+1+1+1)
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
bool arcnet_valid(
void);
void arcnet_cleanup(
void);
bool arcnet_init(
char *interface_name);
/* function to send a packet out the 802.2 socket */
/* returns zero on success, non-zero on failure */
int arcnet_send_pdu(
BACNET_ADDRESS * dest, /* destination address */
BACNET_NPDU_DATA * npdu_data, /* network information */
uint8_t * pdu, /* any data to be sent - may be null */
unsigned pdu_len); /* number of bytes of data */
/* receives an framed packet */
/* returns the number of octets in the PDU, or zero on failure */
uint16_t arcnet_receive(
BACNET_ADDRESS * src, /* source address */
uint8_t * pdu, /* PDU data */
uint16_t max_pdu, /* amount of space available in the PDU */
unsigned timeout); /* milliseconds to wait for a packet */
void arcnet_get_my_address(
BACNET_ADDRESS * my_address);
void arcnet_get_broadcast_address(
BACNET_ADDRESS * dest); /* destination address */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+800
View File
@@ -0,0 +1,800 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "bacnet/bacdcode.h"
#include "bacnet/bacsec.h"
BACNET_KEY_IDENTIFIER_ALGORITHM key_algorithm(uint16_t id)
{
return (BACNET_KEY_IDENTIFIER_ALGORITHM)((id >> 8) & 0xFF);
}
BACNET_KEY_IDENTIFIER_KEY_NUMBER key_number(uint16_t id)
{
return (BACNET_KEY_IDENTIFIER_KEY_NUMBER)(id & 0xFF);
}
int encode_security_wrapper(
int bytes_before, uint8_t *apdu, BACNET_SECURITY_WRAPPER *wrapper)
{
int curr = 0;
int enc_begin = 0;
BACNET_KEY_ENTRY key;
BACNET_SECURITY_RESPONSE_CODE res = SEC_RESP_SUCCESS;
apdu[curr] = 0;
/* control byte */
if (wrapper->payload_net_or_bvll_flag) {
apdu[curr] |= 1 << 7;
}
/* encryption flag will be set after signature calculation */
/* bit 5 is reserved and shall be 0 */
if (wrapper->authentication_flag) {
apdu[curr] |= 1 << 4;
}
if (wrapper->do_not_unwrap_flag) {
apdu[curr] |= 1 << 3;
}
if (wrapper->do_not_decrypt_flag) {
apdu[curr] |= 1 << 2;
}
if (wrapper->non_trusted_source_flag) {
apdu[curr] |= 1 << 1;
}
if (wrapper->secured_by_router_flag) {
apdu[curr] |= 1;
}
curr++;
/* basic integrity checks */
if (wrapper->do_not_decrypt_flag && !wrapper->do_not_unwrap_flag) {
return -SEC_RESP_MALFORMED_MESSAGE;
}
if (!wrapper->encrypted_flag && wrapper->do_not_decrypt_flag) {
return -SEC_RESP_MALFORMED_MESSAGE;
}
/* key */
apdu[curr++] = wrapper->key_revision;
curr += encode_unsigned16(&apdu[curr], wrapper->key_identifier);
/* find appropriate key */
key.key_identifier = wrapper->key_identifier;
res = bacnet_find_key(wrapper->key_revision, &key);
if (res != SEC_RESP_SUCCESS) {
return -res;
}
/* source device instance */
curr += encode_unsigned24(&apdu[curr], wrapper->source_device_instance);
/* message id */
curr += encode_unsigned32(&apdu[curr], wrapper->message_id);
/* timestamp */
curr += encode_unsigned32(&apdu[curr], wrapper->timestamp);
/* begin encryption starting from destination device instance */
enc_begin = curr;
/* destination device instance */
curr +=
encode_unsigned24(&apdu[curr], wrapper->destination_device_instance);
/* dst address */
curr += encode_unsigned16(&apdu[curr], wrapper->dnet);
apdu[curr++] = wrapper->dlen;
memcpy(&apdu[curr], wrapper->dadr, wrapper->dlen);
curr += wrapper->dlen;
/* src address */
curr += encode_unsigned16(&apdu[curr], wrapper->snet);
apdu[curr++] = wrapper->slen;
memcpy(&apdu[curr], wrapper->sadr, wrapper->slen);
curr += wrapper->slen;
/* authentication */
if (wrapper->authentication_flag) {
apdu[curr++] = wrapper->authentication_mechanism;
/* authentication data */
curr += encode_unsigned16(&apdu[curr], wrapper->user_id);
apdu[curr++] = wrapper->user_role;
if ((wrapper->authentication_mechanism >= 1) &&
(wrapper->authentication_mechanism <= 199)) {
curr += encode_unsigned16(
&apdu[curr], wrapper->authentication_data_length + 5);
memcpy(&apdu[curr], wrapper->authentication_data,
wrapper->authentication_data_length);
curr += wrapper->authentication_data_length;
} else if (wrapper->authentication_mechanism >= 200) {
curr += encode_unsigned16(
&apdu[curr], wrapper->authentication_data_length + 7);
curr += encode_unsigned16(&apdu[curr], wrapper->vendor_id);
memcpy(&apdu[curr], wrapper->authentication_data,
wrapper->authentication_data_length);
curr += wrapper->authentication_data_length;
}
}
memcpy(&apdu[curr], wrapper->service_data, wrapper->service_data_len);
curr += wrapper->service_data_len;
/* signature calculation */
key_sign_msg(&key, &apdu[-bytes_before], (uint32_t)(bytes_before + curr),
wrapper->signature);
/* padding and encryption */
if (wrapper->encrypted_flag) {
/* set encryption flag, signing is done */
apdu[0] |= 1 << 6;
/* handle padding */
key_set_padding(
&key, curr - enc_begin, &wrapper->padding_len, wrapper->padding);
if (wrapper->padding_len > 2) {
memcpy(&apdu[curr], wrapper->padding, wrapper->padding_len - 2);
curr += wrapper->padding_len - 2;
}
curr += encode_unsigned16(&apdu[curr], wrapper->padding_len);
/* encryption */
key_encrypt_msg(&key, &apdu[enc_begin], (uint32_t)(curr - enc_begin),
wrapper->signature);
}
memcpy(&apdu[curr], wrapper->signature, SIGNATURE_LEN);
curr += SIGNATURE_LEN;
return curr;
}
int encode_challenge_request(uint8_t *apdu, BACNET_CHALLENGE_REQUEST *bc_req)
{
int curr = 0;
apdu[curr++] = bc_req->message_challenge;
curr += encode_unsigned32(&apdu[curr], bc_req->orig_message_id);
curr += encode_unsigned32(&apdu[curr], bc_req->orig_timestamp);
return curr;
}
int encode_security_payload(uint8_t *apdu, BACNET_SECURITY_PAYLOAD *payload)
{
encode_unsigned16(&apdu[0], payload->payload_length);
memcpy(&apdu[2], payload->payload, payload->payload_length);
return (int)(2 + payload->payload_length);
}
int encode_security_response(uint8_t *apdu, BACNET_SECURITY_RESPONSE *resp)
{
int curr = 0;
int i;
apdu[curr++] = resp->response_code;
curr += encode_unsigned32(&apdu[curr], resp->orig_message_id);
curr += encode_unsigned32(&apdu[curr], resp->orig_timestamp);
switch ((BACNET_SECURITY_RESPONSE_CODE)resp->response_code) {
case SEC_RESP_BAD_TIMESTAMP:
curr += encode_unsigned32(
&apdu[curr], resp->response.bad_timestamp.expected_timestamp);
break;
case SEC_RESP_CANNOT_USE_KEY:
curr += encode_unsigned16(
&apdu[curr], resp->response.cannot_use_key.key);
break;
case SEC_RESP_INCORRECT_KEY:
apdu[curr++] = resp->response.incorrect_key.number_of_keys;
for (i = 0; i < (int)resp->response.incorrect_key.number_of_keys;
i++) {
curr += encode_unsigned16(
&apdu[curr], resp->response.incorrect_key.keys[i]);
}
break;
case SEC_RESP_UNKNOWN_AUTHENTICATION_TYPE:
apdu[curr++] = resp->response.unknown_authentication_type
.original_authentication_type;
curr += encode_unsigned16(&apdu[curr],
resp->response.unknown_authentication_type.vendor_id);
break;
case SEC_RESP_UNKNOWN_KEY:
curr += encode_unsigned16(
&apdu[curr], resp->response.unknown_key.original_key);
break;
case SEC_RESP_UNKNOWN_KEY_REVISION:
apdu[curr++] =
resp->response.unknown_key_revision.original_key_revision;
break;
case SEC_RESP_TOO_MANY_KEYS:
apdu[curr++] = resp->response.too_many_keys.max_num_of_keys;
break;
case SEC_RESP_INVALID_KEY_DATA:
curr += encode_unsigned16(
&apdu[curr], resp->response.invalid_key_data.key);
break;
case SEC_RESP_SUCCESS:
case SEC_RESP_ACCESS_DENIED:
case SEC_RESP_BAD_DESTINATION_ADDRESS:
case SEC_RESP_BAD_DESTINATION_DEVICE_ID:
case SEC_RESP_BAD_SIGNATURE:
case SEC_RESP_BAD_SOURCE_ADDRESS:
case SEC_RESP_CANNOT_VERIFY_MESSAGE_ID:
case SEC_RESP_CORRECT_KEY_REVISION:
case SEC_RESP_DESTINATION_DEVICE_ID_REQUIRED:
case SEC_RESP_DUPLICATE_MESSAGE:
case SEC_RESP_ENCRYPTION_NOT_CONFIGURED:
case SEC_RESP_ENCRYPTION_REQUIRED:
case SEC_RESP_KEY_UPDATE_IN_PROGRESS:
case SEC_RESP_MALFORMED_MESSAGE:
case SEC_RESP_NOT_KEY_SERVER:
case SEC_RESP_SECURITY_NOT_CONFIGURED:
case SEC_RESP_SOURCE_SECURITY_REQUIRED:
case SEC_RESP_UNKNOWN_SOURCE_MESSAGE:
break;
default:
return -1; /* unknown message type */
}
return curr;
}
int encode_request_key_update(uint8_t *apdu, BACNET_REQUEST_KEY_UPDATE *req)
{
int curr = 0;
apdu[curr++] = req->set_1_key_revision;
curr += encode_unsigned32(&apdu[curr], req->set_1_activation_time);
curr += encode_unsigned32(&apdu[curr], req->set_1_expiration_time);
apdu[curr++] = req->set_2_key_revision;
curr += encode_unsigned32(&apdu[curr], req->set_2_activation_time);
curr += encode_unsigned32(&apdu[curr], req->set_2_expiration_time);
apdu[curr++] = req->distribution_key_revision;
return curr;
}
int encode_key_entry(uint8_t *apdu, BACNET_KEY_ENTRY *entry)
{
int curr = 0;
curr += encode_unsigned16(&apdu[curr], entry->key_identifier);
apdu[curr++] = entry->key_len;
memcpy(&apdu[curr], entry->key, entry->key_len);
curr += entry->key_len;
return curr;
}
int encode_update_key_set(uint8_t *apdu, BACNET_UPDATE_KEY_SET *key_set)
{
int curr = 0;
int i, res;
apdu[curr] = 0;
if (key_set->remove) {
apdu[curr] |= 1;
}
if (key_set->more) {
apdu[curr] |= 1 << 1;
}
if (key_set->set_clr[1]) {
apdu[curr] |= 1 << 2;
}
if (key_set->set_ck[1]) {
apdu[curr] |= 1 << 3;
}
if (key_set->set_rae[1]) {
apdu[curr] |= 1 << 4;
}
if (key_set->set_clr[0]) {
apdu[curr] |= 1 << 5;
}
if (key_set->set_ck[0]) {
apdu[curr] |= 1 << 6;
}
if (key_set->set_rae[0]) {
apdu[curr] |= 1 << 7;
}
curr++;
if (key_set->set_rae[0]) {
apdu[curr++] = key_set->set_key_revision[0];
curr += encode_unsigned32(&apdu[curr], key_set->set_activation_time[0]);
curr += encode_unsigned32(&apdu[curr], key_set->set_expiration_time[0]);
}
if (key_set->set_ck[0]) {
apdu[curr++] = key_set->set_key_count[0];
if (key_set->set_key_count[0] > MAX_UPDATE_KEY_COUNT) {
return -1;
}
for (i = 0; i < (int)key_set->set_key_count[0]; i++) {
res = encode_key_entry(&apdu[curr], &key_set->set_keys[0][i]);
if (res < 0) {
return -1;
}
curr += res;
}
}
if (key_set->set_rae[1]) {
apdu[curr++] = key_set->set_key_revision[1];
curr += encode_unsigned32(&apdu[curr], key_set->set_activation_time[1]);
curr += encode_unsigned32(&apdu[curr], key_set->set_expiration_time[1]);
}
if (key_set->set_ck[1]) {
apdu[curr++] = key_set->set_key_count[1];
if (key_set->set_key_count[1] > MAX_UPDATE_KEY_COUNT) {
return -1;
}
for (i = 0; i < (int)key_set->set_key_count[1]; i++) {
res = encode_key_entry(&apdu[curr], &key_set->set_keys[1][i]);
if (res < 0) {
return -1;
}
curr += res;
}
}
return curr;
}
int encode_update_distribution_key(
uint8_t *apdu, BACNET_UPDATE_DISTRIBUTION_KEY *dist_key)
{
int curr = 0;
int res;
apdu[curr++] = dist_key->key_revision;
res = encode_key_entry(&apdu[curr], &dist_key->key);
if (res < 0) {
return -1;
}
return curr + res;
}
int encode_request_master_key(
uint8_t *apdu, BACNET_REQUEST_MASTER_KEY *req_master_key)
{
int curr = 0;
apdu[curr++] = req_master_key->no_supported_algorithms;
memcpy(&apdu[curr], req_master_key->es_algorithms,
req_master_key->no_supported_algorithms);
return (int)(curr + req_master_key->no_supported_algorithms);
}
int encode_set_master_key(uint8_t *apdu, BACNET_SET_MASTER_KEY *set_master_key)
{
return encode_key_entry(apdu, &set_master_key->key);
}
int decode_security_wrapper_safe(int bytes_before,
uint8_t *apdu,
uint32_t apdu_len_remaining,
BACNET_SECURITY_WRAPPER *wrapper)
{
int curr = 0;
int enc_begin = 0;
int real_len = (int)(apdu_len_remaining - SIGNATURE_LEN);
BACNET_KEY_ENTRY key;
BACNET_SECURITY_RESPONSE_CODE res = SEC_RESP_SUCCESS;
if (apdu_len_remaining < 40) {
return -SEC_RESP_MALFORMED_MESSAGE;
}
wrapper->payload_net_or_bvll_flag = ((apdu[curr] & (1 << 7)) != 0);
wrapper->encrypted_flag = ((apdu[curr] & (1 << 6)) != 0);
wrapper->authentication_flag = ((apdu[curr] & (1 << 4)) != 0);
wrapper->do_not_unwrap_flag = ((apdu[curr] & (1 << 3)) != 0);
wrapper->do_not_decrypt_flag = ((apdu[curr] & (1 << 2)) != 0);
wrapper->non_trusted_source_flag = ((apdu[curr] & (1 << 1)) != 0);
wrapper->secured_by_router_flag = ((apdu[curr] & 1) != 0);
/* basic integrity checks */
if (wrapper->do_not_decrypt_flag && !wrapper->do_not_unwrap_flag) {
return -SEC_RESP_MALFORMED_MESSAGE;
}
if (!wrapper->encrypted_flag && wrapper->do_not_decrypt_flag) {
return -SEC_RESP_MALFORMED_MESSAGE;
}
/* remove encryption flag for signature validation */
apdu[curr] &= ~((uint8_t)(1 << 6));
curr++;
/* key */
wrapper->key_revision = apdu[curr++];
curr += decode_unsigned16(&apdu[curr], &wrapper->key_identifier);
/* find appropriate key */
key.key_identifier = wrapper->key_identifier;
res = bacnet_find_key(wrapper->key_revision, &key);
if (res != SEC_RESP_SUCCESS) {
return -res;
}
/* source device instance */
curr += decode_unsigned24(&apdu[curr], &wrapper->source_device_instance);
/* message id */
curr += decode_unsigned32(&apdu[curr], &wrapper->message_id);
/* timestamp */
curr += decode_unsigned32(&apdu[curr], &wrapper->timestamp);
/* begin decryption starting from destination device instance */
enc_begin = curr;
/* read signature */
memcpy(wrapper->signature, &apdu[real_len], SIGNATURE_LEN);
if (wrapper->encrypted_flag) {
if (!key_decrypt_msg(&key, &apdu[enc_begin],
(uint32_t)(real_len - enc_begin), wrapper->signature)) {
return -SEC_RESP_MALFORMED_MESSAGE;
}
curr += decode_unsigned16(&apdu[real_len - 2], &wrapper->padding_len);
real_len -= wrapper->padding_len;
memcpy(wrapper->padding, &apdu[wrapper->padding_len],
wrapper->padding_len - 2);
}
/* destination device instance */
curr +=
decode_unsigned24(&apdu[curr], &wrapper->destination_device_instance);
/* dst address */
curr += decode_unsigned16(&apdu[curr], &wrapper->dnet);
wrapper->dlen = apdu[curr++];
memcpy(wrapper->dadr, &apdu[curr], wrapper->dlen);
curr += wrapper->dlen;
/* src address */
curr += decode_unsigned16(&apdu[curr], &wrapper->snet);
wrapper->slen = apdu[curr++];
memcpy(wrapper->sadr, &apdu[curr], wrapper->slen);
curr += wrapper->slen;
/* authentication */
if (wrapper->authentication_flag) {
wrapper->authentication_mechanism = apdu[curr++];
/* authentication data */
curr += decode_unsigned16(&apdu[curr], &wrapper->user_id);
wrapper->user_role = apdu[curr++];
if ((wrapper->authentication_mechanism >= 1) &&
(wrapper->authentication_mechanism <= 199)) {
curr += decode_unsigned16(
&apdu[curr], &wrapper->authentication_data_length);
wrapper->authentication_data_length -= 5;
memcpy(wrapper->authentication_data, &apdu[curr],
wrapper->authentication_data_length);
curr += wrapper->authentication_data_length;
} else if (wrapper->authentication_mechanism >= 200) {
curr += decode_unsigned16(
&apdu[curr], &wrapper->authentication_data_length);
wrapper->authentication_data_length -= 7;
curr += decode_unsigned16(&apdu[curr], &wrapper->vendor_id);
memcpy(wrapper->authentication_data, &apdu[curr],
wrapper->authentication_data_length);
curr += wrapper->authentication_data_length;
}
}
wrapper->service_data_len = (uint16_t)(real_len - curr);
memcpy(wrapper->service_data, &apdu[curr], wrapper->service_data_len);
curr += wrapper->service_data_len;
if (!key_verify_sign_msg(&key, &apdu[-bytes_before],
(uint32_t)(bytes_before + real_len), wrapper->signature)) {
return -SEC_RESP_BAD_SIGNATURE;
}
return curr;
}
int decode_challenge_request_safe(uint8_t *apdu,
uint32_t apdu_len_remaining,
BACNET_CHALLENGE_REQUEST *bc_req)
{
int curr = 0;
if (apdu_len_remaining < 9) {
return -1;
}
bc_req->message_challenge = apdu[curr++];
curr += decode_unsigned32(&apdu[curr], &bc_req->orig_message_id);
curr += decode_unsigned32(&apdu[curr], &bc_req->orig_timestamp);
return curr; /* always 9! */
}
int decode_security_payload_safe(uint8_t *apdu,
uint32_t apdu_len_remaining,
BACNET_SECURITY_PAYLOAD *payload)
{
if (apdu_len_remaining < 2) {
return -1;
}
decode_unsigned16(&apdu[0], &payload->payload_length);
if (apdu_len_remaining - 2 < payload->payload_length) {
return -1;
}
memcpy(payload->payload, &apdu[2], payload->payload_length);
return (int)(2 + payload->payload_length);
}
int decode_security_response_safe(
uint8_t *apdu, uint32_t apdu_len_remaining, BACNET_SECURITY_RESPONSE *resp)
{
int curr = 0;
int i;
if (apdu_len_remaining < 9) {
return -1;
}
resp->response_code = apdu[curr++];
curr += decode_unsigned32(&apdu[curr], &resp->orig_message_id);
curr += decode_unsigned32(&apdu[curr], &resp->orig_timestamp);
switch ((BACNET_SECURITY_RESPONSE_CODE)resp->response_code) {
case SEC_RESP_BAD_TIMESTAMP:
if (apdu_len_remaining < 13) {
return -1;
}
curr += decode_unsigned32(
&apdu[curr], &resp->response.bad_timestamp.expected_timestamp);
break;
case SEC_RESP_CANNOT_USE_KEY:
if (apdu_len_remaining < 11) {
return -1;
}
curr += decode_unsigned16(
&apdu[curr], &resp->response.cannot_use_key.key);
break;
case SEC_RESP_INCORRECT_KEY:
if (apdu_len_remaining < 10) {
return -1;
}
resp->response.incorrect_key.number_of_keys = apdu[curr++];
if (apdu_len_remaining - 10 <
resp->response.incorrect_key.number_of_keys * 2) {
return -1;
}
for (i = 0; i < (int)resp->response.incorrect_key.number_of_keys;
i++) {
curr += decode_unsigned16(
&apdu[curr], &resp->response.incorrect_key.keys[i]);
}
break;
case SEC_RESP_UNKNOWN_AUTHENTICATION_TYPE:
if (apdu_len_remaining < 12) {
return -1;
}
resp->response.unknown_authentication_type
.original_authentication_type = apdu[curr++];
curr += decode_unsigned16(&apdu[curr],
&resp->response.unknown_authentication_type.vendor_id);
if (resp->response.unknown_authentication_type
.original_authentication_type < 200 &&
resp->response.unknown_authentication_type.vendor_id != 0) {
return -1;
}
break;
case SEC_RESP_UNKNOWN_KEY:
if (apdu_len_remaining < 11) {
return -1;
}
curr += decode_unsigned16(
&apdu[curr], &resp->response.unknown_key.original_key);
break;
case SEC_RESP_UNKNOWN_KEY_REVISION:
if (apdu_len_remaining < 10) {
return -1;
}
resp->response.unknown_key_revision.original_key_revision =
apdu[curr++];
break;
case SEC_RESP_TOO_MANY_KEYS:
if (apdu_len_remaining < 10) {
return -1;
}
resp->response.too_many_keys.max_num_of_keys = apdu[curr++];
break;
case SEC_RESP_INVALID_KEY_DATA:
if (apdu_len_remaining < 11) {
return -1;
}
curr += decode_unsigned16(
&apdu[curr], &resp->response.invalid_key_data.key);
break;
case SEC_RESP_SUCCESS:
case SEC_RESP_ACCESS_DENIED:
case SEC_RESP_BAD_DESTINATION_ADDRESS:
case SEC_RESP_BAD_DESTINATION_DEVICE_ID:
case SEC_RESP_BAD_SIGNATURE:
case SEC_RESP_BAD_SOURCE_ADDRESS:
case SEC_RESP_CANNOT_VERIFY_MESSAGE_ID:
case SEC_RESP_CORRECT_KEY_REVISION:
case SEC_RESP_DESTINATION_DEVICE_ID_REQUIRED:
case SEC_RESP_DUPLICATE_MESSAGE:
case SEC_RESP_ENCRYPTION_NOT_CONFIGURED:
case SEC_RESP_ENCRYPTION_REQUIRED:
case SEC_RESP_KEY_UPDATE_IN_PROGRESS:
case SEC_RESP_MALFORMED_MESSAGE:
case SEC_RESP_NOT_KEY_SERVER:
case SEC_RESP_SECURITY_NOT_CONFIGURED:
case SEC_RESP_SOURCE_SECURITY_REQUIRED:
case SEC_RESP_UNKNOWN_SOURCE_MESSAGE:
break;
default:
return -1; /* unknown message type */
}
return curr;
}
int decode_request_key_update_safe(
uint8_t *apdu, uint32_t apdu_len_remaining, BACNET_REQUEST_KEY_UPDATE *req)
{
int curr = 0;
if (apdu_len_remaining < 19) {
return -1;
}
req->set_1_key_revision = apdu[curr++];
curr += decode_unsigned32(&apdu[curr], &req->set_1_activation_time);
curr += decode_unsigned32(&apdu[curr], &req->set_1_expiration_time);
req->set_2_key_revision = apdu[curr++];
curr += decode_unsigned32(&apdu[curr], &req->set_2_activation_time);
curr += decode_unsigned32(&apdu[curr], &req->set_2_expiration_time);
req->distribution_key_revision = apdu[curr++];
return curr;
}
int decode_key_entry_safe(
uint8_t *apdu, uint32_t apdu_len_remaining, BACNET_KEY_ENTRY *entry)
{
int curr = 0;
if (apdu_len_remaining < 3) {
return -1;
}
curr += decode_unsigned16(&apdu[curr], &entry->key_identifier);
entry->key_len = apdu[curr++];
if (apdu_len_remaining - 3 < entry->key_len ||
entry->key_len > MAX_KEY_LEN) {
return -1;
}
memcpy(entry->key, &apdu[curr], entry->key_len);
curr += entry->key_len;
return curr;
}
int decode_update_key_set_safe(
uint8_t *apdu, uint32_t apdu_len_remaining, BACNET_UPDATE_KEY_SET *key_set)
{
int curr = 0;
int i, res;
if (apdu_len_remaining < 1) {
return -1;
}
if (apdu[curr] & 1) {
key_set->remove = true;
}
if ((apdu[curr] >> 1) & 1) {
key_set->more = true;
}
if ((apdu[curr] >> 2) & 1) {
key_set->set_clr[1] = true;
}
if ((apdu[curr] >> 3) & 1) {
key_set->set_ck[1] = true;
}
if ((apdu[curr] >> 4) & 1) {
key_set->set_rae[1] = true;
}
if ((apdu[curr] >> 5) & 1) {
key_set->set_clr[0] = true;
}
if ((apdu[curr] >> 6) & 1) {
key_set->set_ck[0] = true;
}
if ((apdu[curr] >> 7) & 1) {
key_set->set_rae[0] = true;
}
curr++;
if (key_set->set_rae[0]) {
if (apdu_len_remaining - curr < 9) {
return -1;
}
key_set->set_key_revision[0] = apdu[curr++];
curr +=
decode_unsigned32(&apdu[curr], &key_set->set_activation_time[0]);
curr +=
decode_unsigned32(&apdu[curr], &key_set->set_expiration_time[0]);
}
if (key_set->set_ck[0]) {
if (apdu_len_remaining - curr < 1) {
return -1;
}
key_set->set_key_count[0] = apdu[curr++];
if (key_set->set_key_count[0] > MAX_UPDATE_KEY_COUNT) {
return -1;
}
for (i = 0; i < (int)key_set->set_key_count[0]; i++) {
res = decode_key_entry_safe(apdu + curr, apdu_len_remaining - curr,
&key_set->set_keys[0][i]);
if (res < 0) {
return -1;
}
curr += res;
}
}
if (key_set->set_rae[1]) {
if (apdu_len_remaining - curr < 9) {
return -1;
}
key_set->set_key_revision[1] = apdu[curr++];
curr +=
decode_unsigned32(&apdu[curr], &key_set->set_activation_time[1]);
curr +=
decode_unsigned32(&apdu[curr], &key_set->set_expiration_time[1]);
}
if (key_set->set_ck[1]) {
if (apdu_len_remaining - curr < 1) {
return -1;
}
key_set->set_key_count[1] = apdu[curr++];
if (key_set->set_key_count[1] > MAX_UPDATE_KEY_COUNT) {
return -1;
}
for (i = 0; i < (int)key_set->set_key_count[1]; i++) {
res = decode_key_entry_safe(apdu + curr, apdu_len_remaining - curr,
&key_set->set_keys[1][i]);
if (res < 0) {
return -1;
}
curr += res;
}
}
return curr;
}
int decode_update_distribution_key_safe(uint8_t *apdu,
uint32_t apdu_len_remaining,
BACNET_UPDATE_DISTRIBUTION_KEY *dist_key)
{
int curr = 0;
int res;
if (apdu_len_remaining < 1) {
return -1;
}
dist_key->key_revision = apdu[curr++];
res = decode_key_entry_safe(
&apdu[curr], apdu_len_remaining - curr, &dist_key->key);
if (res < 0) {
return -1;
}
return curr + res;
}
int decode_request_master_key_safe(uint8_t *apdu,
uint32_t apdu_len_remaining,
BACNET_REQUEST_MASTER_KEY *req_master_key)
{
uint32_t curr = 0;
if (apdu_len_remaining < 1) {
return -1;
}
req_master_key->no_supported_algorithms = apdu[curr++];
if (apdu_len_remaining < curr + req_master_key->no_supported_algorithms) {
return -1;
}
memcpy(req_master_key->es_algorithms, &apdu[curr],
req_master_key->no_supported_algorithms);
return (int)(curr + req_master_key->no_supported_algorithms);
}
int decode_set_master_key_safe(uint8_t *apdu,
uint32_t apdu_len_remaining,
BACNET_SET_MASTER_KEY *set_master_key)
{
return decode_key_entry_safe(
apdu, apdu_len_remaining, &set_master_key->key);
}
+290
View File
@@ -0,0 +1,290 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
#ifndef BACNET_SECURITY_H
#define BACNET_SECURITY_H
#define MAX_AUTH_DATA_LEN 16
#define MD5_KEY_SIZE 16
#define AES_KEY_SIZE 16
#define SHA256_KEY_SIZE 32
#define MAX_KEY_LEN 48
#define MAX_UPDATE_KEY_COUNT 32
#define MAX_INCORRECT_KEYS 255
#define MAX_SUPPORTED_ALGORITHMS 255
#define MAX_PAD_LEN 16
#define SIGNATURE_LEN 16
#include <stdbool.h>
#include <stdint.h>
#include "bacnet/bacdef.h"
#include "bacnet/bacenum.h"
typedef struct BACnet_Security_Wrapper {
bool payload_net_or_bvll_flag; /* true if NPDU or BVLL */
bool encrypted_flag;
bool authentication_flag; /* always false for responses */
bool do_not_unwrap_flag; /* always true if do-not-encrypt is true */
bool do_not_decrypt_flag; /* when encrypted flag is false, it also false */
bool non_trusted_source_flag;
bool secured_by_router_flag;
uint8_t key_revision; /* 0 for Device-Master key */
uint16_t key_identifier;
uint32_t source_device_instance;
uint32_t message_id; /* monotonically increased value */
uint32_t timestamp; /* seconds from UTC 1970-1-1 00:00:00 */
uint32_t destination_device_instance;
uint16_t dnet;
uint8_t dlen;
uint8_t dadr[MAX_MAC_LEN];
uint16_t snet;
uint8_t slen;
uint8_t sadr[MAX_MAC_LEN];
uint8_t authentication_mechanism; /* present when User-Authenticated or
* Application-Specific keys are used with: */
/* APDU: Confrmed-Request, Unconfirmed-Request */
/* NPDU: Initialize-Routing-Table, Establish-Connection-To-Network,
* Disconnect-Connection-To-Network */
/* BVLL: Write-Broadcast-Distribution-Table, Read-Broadcast-Distribution-Table,
* Register-Foreign-Device, Read-Foreign-Device-Table,
* Delete-Foreign-Device-Table-Entry */
/* 0 is only legitimate value for now. 200-255 are vendor-specific */
uint16_t user_id; /* 0 for unknown */
uint8_t user_role; /* 0 and 1 are "system users": 0 for device-to-device non-human,
* 1 for device-to-device by unknown human */
uint16_t authentication_data_length; /* authentication mechanism 1-255 */
uint16_t vendor_id; /* authentication mechanism 200-255 */
uint8_t authentication_data[MAX_AUTH_DATA_LEN]; /* other than id, role, length and
* vendor-id */
uint16_t service_data_len; /* case-to-case */
uint8_t *service_data;
uint8_t service_type; /* first octet of service_data */
uint16_t padding_len; /* included in padding */
uint8_t padding[MAX_PAD_LEN];
uint8_t signature[SIGNATURE_LEN]; /* hmac-md5 or hmac-sha256, first 16 bytes */
} BACNET_SECURITY_WRAPPER;
typedef struct Challenge_Request {
uint8_t message_challenge; /* 1 as a response, everything else for other */
uint32_t orig_message_id;
uint32_t orig_timestamp;
} BACNET_CHALLENGE_REQUEST;
typedef struct Security_Payload {
uint16_t payload_length;
uint8_t *payload;
} BACNET_SECURITY_PAYLOAD;
struct Bad_Timestamp {
uint32_t expected_timestamp;
};
struct Cannot_Use_Key {
uint16_t key;
};
struct Incorrect_Key {
uint8_t number_of_keys;
uint16_t keys[MAX_INCORRECT_KEYS];
};
struct Unknown_Authentication_Type {
uint8_t original_authentication_type;
uint16_t vendor_id;
};
struct Unknown_Key {
uint16_t original_key;
};
struct Unknown_Key_Revision {
uint8_t original_key_revision;
};
struct Too_Many_Keys {
uint8_t max_num_of_keys;
};
struct Invalid_Key_Data {
uint16_t key;
};
typedef struct Security_Response {
uint16_t response_code;
uint32_t orig_message_id;
uint32_t orig_timestamp;
union {
struct Bad_Timestamp bad_timestamp;
struct Cannot_Use_Key cannot_use_key;
struct Incorrect_Key incorrect_key;
struct Unknown_Authentication_Type unknown_authentication_type;
struct Unknown_Key unknown_key;
struct Unknown_Key_Revision unknown_key_revision;
struct Too_Many_Keys too_many_keys;
struct Invalid_Key_Data invalid_key_data;
} response;
} BACNET_SECURITY_RESPONSE;
typedef struct Request_Key_Update {
uint8_t set_1_key_revision;
uint32_t set_1_activation_time;
uint32_t set_1_expiration_time;
uint8_t set_2_key_revision;
uint32_t set_2_activation_time;
uint32_t set_2_expiration_time;
uint8_t distribution_key_revision;
} BACNET_REQUEST_KEY_UPDATE;
typedef struct Key_Entry {
uint16_t key_identifier;
uint8_t key_len;
uint8_t key[MAX_KEY_LEN];
} BACNET_KEY_ENTRY;
typedef struct Update_Key_Set {
bool set_rae[2], set_ck[2], set_clr[2];
bool more;
bool remove; /* false for add, true for remove */
uint8_t set_key_revision[2];
uint32_t set_activation_time[2];
uint32_t set_expiration_time[2];
uint8_t set_key_count[2];
BACNET_KEY_ENTRY set_keys[2][MAX_UPDATE_KEY_COUNT];
} BACNET_UPDATE_KEY_SET;
typedef struct Update_Distribution_Key {
uint8_t key_revision;
BACNET_KEY_ENTRY key;
} BACNET_UPDATE_DISTRIBUTION_KEY;
typedef struct Request_Master_Key {
uint8_t no_supported_algorithms;
uint8_t es_algorithms[MAX_SUPPORTED_ALGORITHMS];
} BACNET_REQUEST_MASTER_KEY;
typedef struct Set_Master_Key {
BACNET_KEY_ENTRY key;
} BACNET_SET_MASTER_KEY;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* helper functions */
BACNET_KEY_IDENTIFIER_ALGORITHM key_algorithm(uint16_t id);
BACNET_KEY_IDENTIFIER_KEY_NUMBER key_number(uint16_t id);
/* key manipulation functions - port specific! */
BACNET_SECURITY_RESPONSE_CODE bacnet_master_key_set(BACNET_SET_MASTER_KEY *
key);
BACNET_SECURITY_RESPONSE_CODE
bacnet_distribution_key_update(BACNET_UPDATE_DISTRIBUTION_KEY * key);
BACNET_SECURITY_RESPONSE_CODE bacnet_key_set_update(BACNET_UPDATE_KEY_SET *
update_key_sets);
BACNET_SECURITY_RESPONSE_CODE bacnet_find_key(uint8_t revision,
BACNET_KEY_ENTRY * key);
/* signing/verification and encryption/decryption - port specific */
int key_sign_msg(BACNET_KEY_ENTRY * key,
uint8_t * msg,
uint32_t msg_len,
uint8_t * signature);
bool key_verify_sign_msg(BACNET_KEY_ENTRY * key,
uint8_t * msg,
uint32_t msg_len,
uint8_t * signature);
int key_encrypt_msg(BACNET_KEY_ENTRY * key,
uint8_t * msg,
uint32_t msg_len,
uint8_t * signature);
bool key_decrypt_msg(BACNET_KEY_ENTRY * key,
uint8_t * msg,
uint32_t msg_len,
uint8_t * signature);
void key_set_padding(BACNET_KEY_ENTRY * key,
int enc_len,
uint16_t * padding_len,
uint8_t * padding);
/* encoders */
int encode_security_wrapper(int bytes_before,
uint8_t * apdu,
BACNET_SECURITY_WRAPPER * wrapper);
int encode_challenge_request(uint8_t * apdu,
BACNET_CHALLENGE_REQUEST * bc_req);
int encode_security_payload(uint8_t * apdu,
BACNET_SECURITY_PAYLOAD * payload);
int encode_security_response(uint8_t * apdu,
BACNET_SECURITY_RESPONSE * resp);
int encode_request_key_update(uint8_t * apdu,
BACNET_REQUEST_KEY_UPDATE * req);
int encode_key_entry(uint8_t * apdu,
BACNET_KEY_ENTRY * entry);
int encode_update_key_set(uint8_t * apdu,
BACNET_UPDATE_KEY_SET * key_set);
int encode_update_distribution_key(uint8_t * apdu,
BACNET_UPDATE_DISTRIBUTION_KEY * dist_key);
int encode_request_master_key(uint8_t * apdu,
BACNET_REQUEST_MASTER_KEY * req_master_key);
int encode_set_master_key(uint8_t * apdu,
BACNET_SET_MASTER_KEY * set_master_key);
/* safe decoders */
int decode_security_wrapper_safe(int bytes_before,
uint8_t * apdu,
uint32_t apdu_len_remaining,
BACNET_SECURITY_WRAPPER * wrapper);
int decode_challenge_request_safe(uint8_t * apdu,
uint32_t apdu_len_remaining,
BACNET_CHALLENGE_REQUEST * bc_req);
int decode_security_payload_safe(uint8_t * apdu,
uint32_t apdu_len_remaining,
BACNET_SECURITY_PAYLOAD * payload);
int decode_security_response_safe(uint8_t * apdu,
uint32_t apdu_len_remaining,
BACNET_SECURITY_RESPONSE * resp);
int decode_request_key_update_safe(uint8_t * apdu,
uint32_t apdu_len_remaining,
BACNET_REQUEST_KEY_UPDATE * req);
int decode_key_entry_safe(uint8_t * apdu,
uint32_t apdu_len_remaining,
BACNET_KEY_ENTRY * entry);
int decode_update_key_set_safe(uint8_t * apdu,
uint32_t apdu_len_remaining,
BACNET_UPDATE_KEY_SET * key_set);
int decode_update_distribution_key_safe(uint8_t * apdu,
uint32_t apdu_len_remaining,
BACNET_UPDATE_DISTRIBUTION_KEY * dist_key);
int decode_request_master_key_safe(uint8_t * apdu,
uint32_t apdu_len_remaining,
BACNET_REQUEST_MASTER_KEY * req_master_key);
int decode_set_master_key_safe(uint8_t * apdu,
uint32_t apdu_len_remaining,
BACNET_SET_MASTER_KEY * set_master_key);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+386
View File
@@ -0,0 +1,386 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2005 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
#include <stdint.h> /* for standard integer types uint8_t etc. */
#include <stdbool.h> /* for the standard bool type. */
#include "bacnet/bacdcode.h"
#include "bacnet/bacint.h"
#include "bacnet/datalink/bip.h"
#include "bacnet/datalink/bvlc.h"
#include "bacport.h" /* custom per port */
#if PRINT_ENABLED
#include <stdio.h> /* for standard i/o, like printing */
#endif
/** @file bip.c Configuration and Operations for BACnet/IP */
static int BIP_Socket = -1;
/* port to use - stored in network byte order */
static uint16_t BIP_Port = 0; /* this will force initialization in demos */
/* IP Address - stored in network byte order */
static struct in_addr BIP_Address;
/* Broadcast Address - stored in network byte order */
static struct in_addr BIP_Broadcast_Address;
/** Setter for the BACnet/IP socket handle.
*
* @param sock_fd [in] Handle for the BACnet/IP socket.
*/
void bip_set_socket(int sock_fd)
{
BIP_Socket = sock_fd;
}
/** Getter for the BACnet/IP socket handle.
*
* @return The handle to the BACnet/IP socket.
*/
int bip_socket(void)
{
return BIP_Socket;
}
bool bip_valid(void)
{
return (BIP_Socket != -1);
}
void bip_set_addr(uint32_t net_address)
{ /* in network byte order */
BIP_Address.s_addr = net_address;
}
/* returns network byte order */
uint32_t bip_get_addr(void)
{
return BIP_Address.s_addr;
}
void bip_set_broadcast_addr(uint32_t net_address)
{ /* in network byte order */
BIP_Broadcast_Address.s_addr = net_address;
}
/* returns network byte order */
uint32_t bip_get_broadcast_addr(void)
{
return BIP_Broadcast_Address.s_addr;
}
void bip_set_port(uint16_t port)
{ /* in network byte order */
BIP_Port = port;
}
/* returns network byte order */
uint16_t bip_get_port(void)
{
return BIP_Port;
}
static int bip_decode_bip_address(BACNET_ADDRESS *bac_addr,
struct in_addr *address, /* in network format */
uint16_t *port)
{ /* in network format */
int len = 0;
if (bac_addr) {
memcpy(&address->s_addr, &bac_addr->mac[0], 4);
memcpy(port, &bac_addr->mac[4], 2);
len = 6;
}
return len;
}
/** Function to send a packet out the BACnet/IP socket (Annex J).
* @ingroup DLBIP
*
* @param dest [in] Destination address (may encode an IP address and port #).
* @param npdu_data [in] The NPDU header (Network) information (not used).
* @param pdu [in] Buffer of data to be sent - may be null (why?).
* @param pdu_len [in] Number of bytes in the pdu buffer.
* @return Number of bytes sent on success, negative number on failure.
*/
int bip_send_pdu(BACNET_ADDRESS *dest, /* destination address */
BACNET_NPDU_DATA *npdu_data, /* network information */
uint8_t *pdu, /* any data to be sent - may be null */
unsigned pdu_len)
{ /* number of bytes of data */
struct sockaddr_in bip_dest;
uint8_t mtu[MAX_MPDU] = { 0 };
int mtu_len = 0;
int bytes_sent = 0;
/* addr and port in host format */
struct in_addr address;
uint16_t port = 0;
(void)npdu_data;
/* assumes that the driver has already been initialized */
if (BIP_Socket < 0) {
return BIP_Socket;
}
mtu[0] = BVLL_TYPE_BACNET_IP;
bip_dest.sin_family = AF_INET;
if ((dest->net == BACNET_BROADCAST_NETWORK) || (dest->mac_len == 0)) {
/* broadcast */
address.s_addr = BIP_Broadcast_Address.s_addr;
port = BIP_Port;
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
} else if ((dest->net > 0) && (dest->len == 0)) {
/* network specific broadcast */
if (dest->mac_len == 6) {
bip_decode_bip_address(dest, &address, &port);
} else {
address.s_addr = BIP_Broadcast_Address.s_addr;
port = BIP_Port;
}
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
} else if (dest->mac_len == 6) {
bip_decode_bip_address(dest, &address, &port);
mtu[1] = BVLC_ORIGINAL_UNICAST_NPDU;
} else {
/* invalid address */
return -1;
}
bip_dest.sin_addr.s_addr = address.s_addr;
bip_dest.sin_port = port;
memset(&(bip_dest.sin_zero), '\0', 8);
mtu_len = 2;
mtu_len += encode_unsigned16(
&mtu[mtu_len], (uint16_t)(pdu_len + 4 /*inclusive */));
memcpy(&mtu[mtu_len], pdu, pdu_len);
mtu_len += pdu_len;
/* Send the packet */
bytes_sent = sendto(BIP_Socket, (char *)mtu, mtu_len, 0,
(struct sockaddr *)&bip_dest, sizeof(struct sockaddr));
return bytes_sent;
}
/** Implementation of the receive() function for BACnet/IP; receives one
* packet, verifies its BVLC header, and removes the BVLC header from
* the PDU data before returning.
*
* @param src [out] Source of the packet - who should receive any response.
* @param pdu [out] A buffer to hold the PDU portion of the received packet,
* after the BVLC portion has been stripped
* off.
* @param max_pdu [in] Size of the pdu[] buffer.
* @param timeout [in] The number of milliseconds to wait for a packet.
* @return The number of octets (remaining) in the PDU, or zero on failure.
*/
uint16_t bip_receive(BACNET_ADDRESS *src, /* source address */
uint8_t *pdu, /* PDU data */
uint16_t max_pdu, /* amount of space available in the PDU */
unsigned timeout)
{
int received_bytes = 0;
uint16_t pdu_len = 0; /* return value */
fd_set read_fds;
int max = 0;
struct timeval select_timeout;
struct sockaddr_in sin = { 0 };
socklen_t sin_len = sizeof(sin);
uint16_t i = 0;
int function = 0;
/* Make sure the socket is open */
if (BIP_Socket < 0) {
return 0;
}
/* we could just use a non-blocking socket, but that consumes all
the CPU time. We can use a timeout; it is only supported as
a select. */
if (timeout >= 1000) {
select_timeout.tv_sec = timeout / 1000;
select_timeout.tv_usec =
1000 * (timeout - select_timeout.tv_sec * 1000);
} else {
select_timeout.tv_sec = 0;
select_timeout.tv_usec = 1000 * timeout;
}
FD_ZERO(&read_fds);
FD_SET(BIP_Socket, &read_fds);
max = BIP_Socket;
/* see if there is a packet for us */
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
received_bytes = recvfrom(BIP_Socket, (char *)&pdu[0], max_pdu, 0,
(struct sockaddr *)&sin, &sin_len);
} else {
return 0;
}
/* See if there is a problem */
if (received_bytes < 0) {
return 0;
}
/* no problem, just no bytes */
if (received_bytes == 0) {
return 0;
}
/* the signature of a BACnet/IP packet */
if (pdu[0] != BVLL_TYPE_BACNET_IP) {
return 0;
}
if (bvlc_for_non_bbmd(&sin, pdu, received_bytes) > 0) {
/* Handled, usually with a NACK. */
#if PRINT_ENABLED
fprintf(stderr, "BIP: BVLC discarded!\n");
#endif
return 0;
}
function = bvlc_get_function_code(); /* aka, pdu[1] */
if ((function == BVLC_ORIGINAL_UNICAST_NPDU) ||
(function == BVLC_ORIGINAL_BROADCAST_NPDU)) {
/* ignore messages from me */
if ((sin.sin_addr.s_addr == BIP_Address.s_addr) &&
(sin.sin_port == BIP_Port)) {
pdu_len = 0;
#if 0
fprintf(stderr, "BIP: src is me. Discarded!\n");
#endif
} else {
/* data in src->mac[] is in network format */
src->mac_len = 6;
memcpy(&src->mac[0], &sin.sin_addr.s_addr, 4);
memcpy(&src->mac[4], &sin.sin_port, 2);
/* FIXME: check destination address */
/* see if it is broadcast or for us */
/* decode the length of the PDU - length is inclusive of BVLC */
(void)decode_unsigned16(&pdu[2], &pdu_len);
/* subtract off the BVLC header */
pdu_len -= 4;
if (pdu_len < max_pdu) {
#if 0
fprintf(stderr, "BIP: NPDU[%hu]:", pdu_len);
#endif
/* shift the buffer to return a valid PDU */
for (i = 0; i < pdu_len; i++) {
pdu[i] = pdu[4 + i];
#if 0
fprintf(stderr, "%02X ", pdu[i]);
#endif
}
#if 0
fprintf(stderr, "\n");
#endif
}
/* ignore packets that are too large */
/* clients should check my max-apdu first */
else {
pdu_len = 0;
#if PRINT_ENABLED
fprintf(stderr, "BIP: PDU too large. Discarded!.\n");
#endif
}
}
} else if (function == BVLC_FORWARDED_NPDU) {
memcpy(&sin.sin_addr.s_addr, &pdu[4], 4);
memcpy(&sin.sin_port, &pdu[8], 2);
if ((sin.sin_addr.s_addr == BIP_Address.s_addr) &&
(sin.sin_port == BIP_Port)) {
/* ignore messages from me */
pdu_len = 0;
} else {
/* data in src->mac[] is in network format */
src->mac_len = 6;
memcpy(&src->mac[0], &sin.sin_addr.s_addr, 4);
memcpy(&src->mac[4], &sin.sin_port, 2);
/* FIXME: check destination address */
/* see if it is broadcast or for us */
/* decode the length of the PDU - length is inclusive of BVLC */
(void)decode_unsigned16(&pdu[2], &pdu_len);
/* subtract off the BVLC header */
pdu_len -= 10;
if (pdu_len < max_pdu) {
/* shift the buffer to return a valid PDU */
for (i = 0; i < pdu_len; i++) {
pdu[i] = pdu[4 + 6 + i];
}
} else {
/* ignore packets that are too large */
/* clients should check my max-apdu first */
pdu_len = 0;
}
}
}
return pdu_len;
}
void bip_get_my_address(BACNET_ADDRESS *my_address)
{
int i = 0;
if (my_address) {
my_address->mac_len = 6;
memcpy(&my_address->mac[0], &BIP_Address.s_addr, 4);
memcpy(&my_address->mac[4], &BIP_Port, 2);
my_address->net = 0; /* local only, no routing */
my_address->len = 0; /* no SLEN */
for (i = 0; i < MAX_MAC_LEN; i++) {
/* no SADR */
my_address->adr[i] = 0;
}
}
return;
}
void bip_get_broadcast_address(BACNET_ADDRESS *dest)
{ /* destination address */
int i = 0; /* counter */
if (dest) {
dest->mac_len = 6;
memcpy(&dest->mac[0], &BIP_Broadcast_Address.s_addr, 4);
memcpy(&dest->mac[4], &BIP_Port, 2);
dest->net = BACNET_BROADCAST_NETWORK;
dest->len = 0; /* no SLEN */
for (i = 0; i < MAX_MAC_LEN; i++) {
/* no SADR */
dest->adr[i] = 0;
}
}
return;
}
+126
View File
@@ -0,0 +1,126 @@
/**************************************************************************
*
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*********************************************************************/
#ifndef BIP_H
#define BIP_H
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include "bacnet/bacdef.h"
#include "bacnet/npdu.h"
#include "bacport.h"
/* specific defines for BACnet/IP over Ethernet */
#define MAX_HEADER (1 + 1 + 2)
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
#define BVLL_TYPE_BACNET_IP (0x81)
extern bool BIP_Debug;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* note: define init, set_interface, and cleanup in your port */
/* on Linux, ifname is eth0, ath0, arc0, and others.
on Windows, ifname is the dotted ip address of the interface */
bool bip_init(
char *ifname);
void bip_set_interface(
char *ifname);
void bip_cleanup(
void);
/* common BACnet/IP functions */
void bip_set_socket(
int sock_fd);
int bip_socket(
void);
bool bip_valid(
void);
void bip_get_broadcast_address(
BACNET_ADDRESS * dest); /* destination address */
void bip_get_my_address(
BACNET_ADDRESS * my_address);
/* function to send a packet out the BACnet/IP socket */
/* returns zero on success, non-zero on failure */
int bip_send_pdu(
BACNET_ADDRESS * dest, /* destination address */
BACNET_NPDU_DATA * npdu_data, /* network information */
uint8_t * pdu, /* any data to be sent - may be null */
unsigned pdu_len); /* number of bytes of data */
/* receives a BACnet/IP packet */
/* returns the number of octets in the PDU, or zero on failure */
uint16_t bip_receive(
BACNET_ADDRESS * src, /* source address */
uint8_t * pdu, /* PDU data */
uint16_t max_pdu, /* amount of space available in the PDU */
unsigned timeout); /* milliseconds to wait for a packet */
/* use network byte order for setting */
void bip_set_port(
uint16_t port);
bool bip_port_changed(void);
/* returns network byte order */
uint16_t bip_get_port(
void);
/* use network byte order for setting */
void bip_set_addr(
uint32_t net_address);
/* returns network byte order */
uint32_t bip_get_addr(
void);
/* use network byte order for setting */
void bip_set_broadcast_addr(
uint32_t net_address);
/* returns network byte order */
uint32_t bip_get_broadcast_addr(
void);
/* gets an IP address by name, where name can be a
string that is an IP address in dotted form, or
a name that is a domain name
returns 0 if not found, or
an IP address in network byte order */
long bip_getaddrbyname(
const char *host_name);
#ifdef __cplusplus
}
#endif /* __cplusplus */
/** @defgroup DLBIP BACnet/IP DataLink Network Layer
* @ingroup DataLink
* Implementation of the Network Layer using BACnet/IP as the transport, as
* described in Annex J.
* The functions described here fulfill the roles defined generically at the
* DataLink level by serving as the implementation of the function templates.
*
*/
#endif
+87
View File
@@ -0,0 +1,87 @@
/**
* @file
* @author Steve Karg
* @date 2015
* @defgroup DLBIP6 BACnet/IPv6 DataLink Network Layer
* @ingroup DataLink
*
* Implementation of the Network Layer using BACnet/IPv6 as the transport, as
* described in Annex J.
* The functions described here fulfill the roles defined generically at the
* DataLink level by serving as the implementation of the function templates.
*/
#ifndef BIP6_H
#define BIP6_H
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include "bacnet/bacdef.h"
#include "bacnet/npdu.h"
#include "bacnet/datalink/bvlc6.h"
/* specific defines for BACnet/IP over Ethernet */
#define BIP6_HEADER_MAX (1 + 1 + 2)
#define BIP6_MPDU_MAX (BIP6_HEADER_MAX+MAX_PDU)
/* for legacy demo applications */
#define MAX_MPDU BIP6_MPDU_MAX
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* 6 datalink functions used by demo handlers and applications:
init, send, receive, cleanup, unicast/broadcast address.
Note: the addresses used here are VMAC addresses. */
bool bip6_init(
char *ifname);
void bip6_cleanup(
void);
void bip6_get_broadcast_address(
BACNET_ADDRESS * my_address);
void bip6_get_my_address(
BACNET_ADDRESS * my_address);
int bip6_send_pdu(
BACNET_ADDRESS * dest,
BACNET_NPDU_DATA * npdu_data,
uint8_t * pdu,
unsigned pdu_len);
uint16_t bip6_receive(
BACNET_ADDRESS * src,
uint8_t * pdu,
uint16_t max_pdu,
unsigned timeout);
/* functions that are custom per port */
void bip6_set_interface(
char *ifname);
bool bip6_address_match_self(
BACNET_IP6_ADDRESS *addr);
bool bip6_set_addr(
BACNET_IP6_ADDRESS *addr);
bool bip6_get_addr(
BACNET_IP6_ADDRESS *addr);
void bip6_set_port(
uint16_t port);
uint16_t bip6_get_port(
void);
bool bip6_set_broadcast_addr(
BACNET_IP6_ADDRESS *addr);
/* returns network byte order */
bool bip6_get_broadcast_addr(
BACNET_IP6_ADDRESS *addr);
int bip6_send_mpdu(
BACNET_IP6_ADDRESS *addr,
uint8_t * mtu,
uint16_t mtu_len);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
File diff suppressed because it is too large Load Diff
+182
View File
@@ -0,0 +1,182 @@
/**************************************************************************
*
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*********************************************************************/
#ifndef BVLC_H
#define BVLC_H
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <time.h>
#include "bacnet/bacdef.h"
#include "bacnet/npdu.h"
#include "bacnet/datalink/bip.h"
struct sockaddr_in; /* Defined elsewhere, needed here. */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#if defined(BBMD_ENABLED) && BBMD_ENABLED
void bvlc_maintenance_timer(
time_t seconds);
#else
#define bvlc_maintenance_timer(x)
#endif
typedef struct {
/* true if valid entry - false if not */
bool valid;
/* BACnet/IP address */
struct in_addr dest_address; /* in network format */
/* BACnet/IP port number - not always 47808=BAC0h */
uint16_t dest_port; /* in network format */
/* Broadcast Distribution Mask */
struct in_addr broadcast_mask; /* in tework format */
} BBMD_TABLE_ENTRY;
uint16_t bvlc_receive(
BACNET_ADDRESS * src, /* returns the source address */
uint8_t * npdu, /* returns the NPDU */
uint16_t max_npdu, /* amount of space available in the NPDU */
unsigned timeout); /* number of milliseconds to wait for a packet */
int bvlc_send_pdu(
BACNET_ADDRESS * dest, /* destination address */
BACNET_NPDU_DATA * npdu_data, /* network information */
uint8_t * pdu, /* any data to be sent - may be null */
unsigned pdu_len);
int bvlc_send_mpdu(
struct sockaddr_in *dest,
uint8_t * mtu,
uint16_t mtu_len);
#if defined(BBMD_CLIENT_ENABLED) && BBMD_CLIENT_ENABLED
int bvlc_encode_write_bdt_init(
uint8_t * pdu,
unsigned entries);
int bvlc_encode_read_fdt(
uint8_t * pdu);
int bvlc_encode_delete_fdt_entry(
uint8_t * pdu,
uint32_t address, /* in network byte order */
uint16_t port); /* in network byte order */
int bvlc_encode_original_unicast_npdu(
uint8_t * pdu,
uint8_t * npdu,
unsigned npdu_length);
int bvlc_encode_original_broadcast_npdu(
uint8_t * pdu,
uint8_t * npdu,
unsigned npdu_length);
#endif
int bvlc_encode_read_bdt(
uint8_t * pdu);
int bvlc_bbmd_read_bdt(
uint32_t bbmd_address,
uint16_t bbmd_port);
/* registers with a bbmd as a foreign device */
int bvlc_register_with_bbmd(
uint32_t bbmd_address, /* in network byte order */
uint16_t bbmd_port, /* in network byte order */
uint16_t time_to_live_seconds);
/* Note any BVLC_RESULT code, or NAK the BVLL message in the unsupported cases. */
int bvlc_for_non_bbmd(
struct sockaddr_in *sout,
uint8_t * npdu,
uint16_t received_bytes);
/* Returns the last BVLL Result we received, either as the result of a BBMD
* request we sent, or (if not a BBMD or Client), from trying to register
* as a foreign device. */
BACNET_BVLC_RESULT bvlc_get_last_result(
void);
/* Returns the current BVLL Function Code we are processing.
* We have to store this higher layer code for when the lower layers
* need to know what it is, especially to differentiate between
* BVLC_ORIGINAL_UNICAST_NPDU and BVLC_ORIGINAL_BROADCAST_NPDU. */
BACNET_BVLC_FUNCTION bvlc_get_function_code(
void);
/* Local interface to manage BBMD.
* The interface user needs to handle mutual exclusion if needed i.e.
* BACnet packet is not being handled when the BBMD table is modified.
*/
/* Get handle to broadcast distribution table. Returns the number of
* valid entries in the table. */
int bvlc_get_bdt_local(
const BBMD_TABLE_ENTRY** table);
/* Invalidate all entries in the broadcast distribution table */
void bvlc_clear_bdt_local(void);
/* Add new entry to broadcast distribution table. Returns true if the new
* entry was added successfully */
bool bvlc_add_bdt_entry_local(
BBMD_TABLE_ENTRY* entry);
/* Backup broadcast distribution table to a file.
* Filename is the BBMD_BACKUP_FILE constant
*/
void bvlc_bdt_backup_local(
void);
/* Restore broadcast distribution from a file.
* Filename is the BBMD_BACKUP_FILE constant
*/
void bvlc_bdt_restore_local(
void);
/* NAT handling
* If the communication between BBMDs goes through a NAT enabled internet
* router, special considerations are needed as stated in Annex J.7.8.
*
* In short, the local IP address of the BBMD is different than the global
* address which is visible to the other BBMDs or foreign devices. This is
* why the source address in forwarded messages needs to be changed to the
* global IP address.
*
* For other considerations/limitations see Annex J.7.8.
*/
/* Set global IP address of a NAT enabled router which is used in forwarded
* messages. Enables NAT handling.
*/
void bvlc_set_global_address_for_nat(const struct in_addr* addr);
/* Disable NAT handling of BBMD.
*/
void bvlc_disable_nat(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* */
File diff suppressed because it is too large Load Diff
+387
View File
@@ -0,0 +1,387 @@
/**
* @file
* @author Steve Karg
* @date 2015
*
* Implementation of the BACnet Virtual Link Layer using IPv6,
* as described in Annex J.
*/
#ifndef BVLC6_H
#define BVLC6_H
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <time.h>
#include "bacnet/bacdef.h"
#include "bacnet/npdu.h"
/**
* BVLL for BACnet/IPv6
* @{
*/
#define BVLL_TYPE_BACNET_IP6 (0x82)
/** @} */
/**
* B/IPv6 BVLL Messages
* @{
*/
#define BVLC6_RESULT 0x00
#define BVLC6_ORIGINAL_UNICAST_NPDU 0x01
#define BVLC6_ORIGINAL_BROADCAST_NPDU 0x02
#define BVLC6_ADDRESS_RESOLUTION 0x03
#define BVLC6_FORWARDED_ADDRESS_RESOLUTION 0x04
#define BVLC6_ADDRESS_RESOLUTION_ACK 0x05
#define BVLC6_VIRTUAL_ADDRESS_RESOLUTION 0x06
#define BVLC6_VIRTUAL_ADDRESS_RESOLUTION_ACK 0x07
#define BVLC6_FORWARDED_NPDU 0x08
#define BVLC6_REGISTER_FOREIGN_DEVICE 0x09
#define BVLC6_DELETE_FOREIGN_DEVICE 0x0A
#define BVLC6_SECURE_BVLL 0x0B
#define BVLC6_DISTRIBUTE_BROADCAST_TO_NETWORK 0x0C
/** @} */
/**
* BVLC Result Code
* @{
*/
#define BVLC6_RESULT_SUCCESSFUL_COMPLETION 0x0000
#define BVLC6_RESULT_ADDRESS_RESOLUTION_NAK 0x0030
#define BVLC6_RESULT_VIRTUAL_ADDRESS_RESOLUTION_NAK 0x0060
#define BVLC6_RESULT_REGISTER_FOREIGN_DEVICE_NAK 0x0090
#define BVLC6_RESULT_DELETE_FOREIGN_DEVICE_NAK 0x00A0
#define BVLC6_RESULT_DISTRIBUTE_BROADCAST_TO_NETWORK_NAK 0x00C0
/** @} */
/**
* BACnet IPv6 Multicast Group ID
* BACnet broadcast messages shall be delivered by IPv6 multicasts
* as opposed to using IP broadcasting. Broadcasting in
* IPv6 is subsumed by multicasting to the all-nodes link
* group FF02::1; however, the use of the all-nodes group is not
* recommended, and BACnet/IPv6 uses an IANA permanently assigned
* multicast group identifier to avoid disturbing
* every interface in the network.
*
* The IANA assigned BACnet/IPv6 variable scope multicast address
* is FF0X:0:0:0:0:0:0:BAC0 (FF0X::BAC0) which indicates the multicast
* group identifier X'BAC0'. The following multicast scopes are
* defined for B/IPv6.
* @{
*/
#define BIP6_MULTICAST_GROUP_ID 0xBAC0
/** @} */
/**
* IANA prefixes
* @{
*/
#define BIP6_MULTICAST_reserved_0 0xFF00
#define BIP6_MULTICAST_NODE_LOCAL 0xFF01
#define BIP6_MULTICAST_LINK_LOCAL 0xFF02
#define BIP6_MULTICAST_reserved_3 0xFF03
#define BIP6_MULTICAST_ADMIN_LOCAL 0xFF04
#define BIP6_MULTICAST_SITE_LOCAL 0xFF05
#define BIP6_MULTICAST_ORG_LOCAL 0xFF08
#define BIP6_MULTICAST_GLOBAL 0xFF0E
/** @} */
/* number of bytes in the IPv6 address */
#define IP6_ADDRESS_MAX 16
/* number of bytes in the B/IPv6 address */
#define BIP6_ADDRESS_MAX 18
/**
* BACnet IPv6 Address
*
* Data link layer addressing between B/IPv6 nodes consists of a 128-bit
* IPv6 address followed by a two-octet UDP port number (both of which
* shall be transmitted with the most significant octet first).
* This address shall be referred to as a B/IPv6 address.
* @{
*/
typedef struct BACnet_IP6_Address {
uint8_t address[IP6_ADDRESS_MAX];
uint16_t port;
} BACNET_IP6_ADDRESS;
/** @} */
/**
* BACnet /IPv6 Broadcast Distribution Table Format
*
* The BDT shall consist of either the eighteen-octet B/IPv6 address
* of the peer BBMD or the combination of the fully qualified
* domain name service (DNS) entry and UDP port that resolves to
* the B/IPv6 address of the peer BBMD. The Broadcast
* Distribution Table shall not contain an entry for the BBMD in
* which the BDT resides.
* @{
*/
struct BACnet_IP6_Broadcast_Distribution_Table_Entry;
typedef struct BACnet_IP6_Broadcast_Distribution_Table_Entry {
/* true if valid entry - false if not */
bool valid;
/* BACnet/IPv6 address */
BACNET_IP6_ADDRESS bip6_address;
struct BACnet_IP6_Broadcast_Distribution_Table_Entry *next;
} BACNET_IP6_BROADCAST_DISTRIBUTION_TABLE_ENTRY;
/** @} */
/**
* Foreign Device Table (FDT)
*
* Each entry shall contain the B/IPv6 address and the TTL of the
* registered foreign device.
*
* Each entry shall consist of the eighteen-octet B/IPv6 address of the
* registrant; the 2-octet Time-to-Live value supplied at the time of
* registration; and a 2-octet value representing the number of seconds
* remaining before the BBMD will purge the registrant's FDT entry if no
* re-registration occurs. The number of seconds remaining shall be
* initialized to the 2-octet Time-to-Live value supplied at the time
* of registration plus 30 seconds (see U.4.5.2), with a maximum of 65535.
* @{
*/
struct BACnet_IP6_Foreign_Device_Table_Entry;
typedef struct BACnet_IP6_Foreign_Device_Table_Entry {
/* true if valid entry - false if not */
bool valid;
/* BACnet/IPv6 address */
BACNET_IP6_ADDRESS bip6_address;
/* requested time-to-live value */
uint16_t ttl_seconds;
/* number of seconds remaining */
uint16_t ttl_seconds_remaining;
struct BACnet_IP6_Foreign_Device_Table_Entry *next;
} BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY;
/** @} */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int bvlc6_encode_address(
uint8_t * pdu,
uint16_t pdu_size,
BACNET_IP6_ADDRESS * ip6_address);
int bvlc6_decode_address(
uint8_t * pdu,
uint16_t pdu_len,
BACNET_IP6_ADDRESS * ip6_address);
bool bvlc6_address_copy(
BACNET_IP6_ADDRESS * dst,
BACNET_IP6_ADDRESS * src);
bool bvlc6_address_different(
BACNET_IP6_ADDRESS * dst,
BACNET_IP6_ADDRESS * src);
bool bvlc6_address_set(
BACNET_IP6_ADDRESS * addr,
uint16_t addr0,
uint16_t addr1,
uint16_t addr2,
uint16_t addr3,
uint16_t addr4,
uint16_t addr5,
uint16_t addr6,
uint16_t addr7);
bool bvlc6_address_get(
BACNET_IP6_ADDRESS * addr,
uint16_t *addr0,
uint16_t *addr1,
uint16_t *addr2,
uint16_t *addr3,
uint16_t *addr4,
uint16_t *addr5,
uint16_t *addr6,
uint16_t *addr7);
bool bvlc6_vmac_address_set(
BACNET_ADDRESS * addr,
uint32_t device_id);
bool bvlc6_vmac_address_get(
BACNET_ADDRESS * addr,
uint32_t *device_id);
int bvlc6_encode_header(
uint8_t * pdu,
uint16_t pdu_size,
uint8_t message_type,
uint16_t length);
int bvlc6_decode_header(
uint8_t * pdu,
uint16_t pdu_len,
uint8_t * message_type,
uint16_t * length);
int bvlc6_encode_result(
uint8_t * pdu,
uint16_t pdu_size,
uint32_t vmac,
uint16_t result_code);
int bvlc6_decode_result(
uint8_t * pdu,
uint16_t pdu_len,
uint32_t * vmac,
uint16_t * result_code);
int bvlc6_encode_original_unicast(
uint8_t * pdu,
uint16_t pdu_size,
uint32_t vmac_src,
uint32_t vmac_dst,
uint8_t * npdu,
uint16_t npdu_len);
int bvlc6_decode_original_unicast(
uint8_t * pdu,
uint16_t pdu_len,
uint32_t * vmac_src,
uint32_t * vmac_dst,
uint8_t * npdu,
uint16_t npdu_size,
uint16_t * npdu_len);
int bvlc6_encode_original_broadcast(
uint8_t * pdu,
uint16_t pdu_size,
uint32_t vmac,
uint8_t * npdu,
uint16_t npdu_len);
int bvlc6_decode_original_broadcast(
uint8_t * pdu,
uint16_t pdu_len,
uint32_t * vmac,
uint8_t * npdu,
uint16_t npdu_size,
uint16_t * npdu_len);
int bvlc6_encode_address_resolution(
uint8_t * pdu,
uint16_t pdu_size,
uint32_t vmac_src,
uint32_t vmac_target);
int bvlc6_decode_address_resolution(
uint8_t * pdu,
uint16_t pdu_len,
uint32_t * vmac_src,
uint32_t * vmac_target);
int bvlc6_encode_forwarded_address_resolution(
uint8_t * pdu,
uint16_t pdu_size,
uint32_t vmac_src,
uint32_t vmac_target,
BACNET_IP6_ADDRESS * bip6_address);
int bvlc6_decode_forwarded_address_resolution(
uint8_t * pdu,
uint16_t pdu_len,
uint32_t * vmac_src,
uint32_t * vmac_target,
BACNET_IP6_ADDRESS * bip6_address);
int bvlc6_encode_address_resolution_ack(
uint8_t * pdu,
uint16_t pdu_size,
uint32_t vmac_src,
uint32_t vmac_dst);
int bvlc6_decode_address_resolution_ack(
uint8_t * pdu,
uint16_t pdu_len,
uint32_t * vmac_src,
uint32_t * vmac_dst);
int bvlc6_encode_virtual_address_resolution(
uint8_t * pdu,
uint16_t pdu_size,
uint32_t vmac_src);
int bvlc6_decode_virtual_address_resolution(
uint8_t * pdu,
uint16_t pdu_len,
uint32_t * vmac_src);
int bvlc6_encode_virtual_address_resolution_ack(
uint8_t * pdu,
uint16_t pdu_size,
uint32_t vmac_src,
uint32_t vmac_dst);
int bvlc6_decode_virtual_address_resolution_ack(
uint8_t * pdu,
uint16_t pdu_len,
uint32_t * vmac_src,
uint32_t * vmac_dst);
int bvlc6_encode_forwarded_npdu(
uint8_t * pdu,
uint16_t pdu_size,
uint32_t vmac_src,
BACNET_IP6_ADDRESS * address,
uint8_t * npdu,
uint16_t npdu_len);
int bvlc6_decode_forwarded_npdu(
uint8_t * pdu,
uint16_t pdu_len,
uint32_t * vmac_src,
BACNET_IP6_ADDRESS * address,
uint8_t * npdu,
uint16_t npdu_size,
uint16_t * npdu_len);
int bvlc6_encode_register_foreign_device(
uint8_t * pdu,
uint16_t pdu_size,
uint32_t vmac_src,
uint16_t ttl_seconds);
int bvlc6_decode_register_foreign_device(
uint8_t * pdu,
uint16_t pdu_len,
uint32_t * vmac_src,
uint16_t * ttl_seconds);
int bvlc6_encode_delete_foreign_device(
uint8_t * pdu,
uint16_t pdu_size,
uint32_t vmac_src,
BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY * fdt_entry);
int bvlc6_decode_delete_foreign_device(
uint8_t * pdu,
uint16_t pdu_len,
uint32_t * vmac_src,
BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY * fdt_entry);
int bvlc6_encode_secure_bvll(
uint8_t * pdu,
uint16_t pdu_size,
uint8_t * sbuf,
uint16_t sbuf_len);
int bvlc6_decode_secure_bvll(
uint8_t * pdu,
uint16_t pdu_len,
uint8_t * sbuf,
uint16_t sbuf_size,
uint16_t * sbuf_len);
int bvlc6_encode_distribute_broadcast_to_network(
uint8_t * pdu,
uint16_t pdu_size,
uint32_t vmac,
uint8_t * npdu,
uint16_t npdu_len);
int bvlc6_decode_distribute_broadcast_to_network(
uint8_t * pdu,
uint16_t pdu_len,
uint32_t * vmac,
uint8_t * npdu,
uint16_t npdu_size,
uint16_t * npdu_len);
#ifdef TEST
#include "ctest.h"
void test_BVLC6(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* */
+269
View File
@@ -0,0 +1,269 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307
USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "crc.h"
/** @file crc.c Calculate CRCs */
#if defined(CRC_USE_TABLE)
/* note: table is created using unit test below */
static const uint8_t HeaderCRC[256] = { 0x00, 0xfe, 0xff, 0x01, 0xfd, 0x03,
0x02, 0xfc, 0xf9, 0x07, 0x06, 0xf8, 0x04, 0xfa, 0xfb, 0x05, 0xf1, 0x0f,
0x0e, 0xf0, 0x0c, 0xf2, 0xf3, 0x0d, 0x08, 0xf6, 0xf7, 0x09, 0xf5, 0x0b,
0x0a, 0xf4, 0xe1, 0x1f, 0x1e, 0xe0, 0x1c, 0xe2, 0xe3, 0x1d, 0x18, 0xe6,
0xe7, 0x19, 0xe5, 0x1b, 0x1a, 0xe4, 0x10, 0xee, 0xef, 0x11, 0xed, 0x13,
0x12, 0xec, 0xe9, 0x17, 0x16, 0xe8, 0x14, 0xea, 0xeb, 0x15, 0xc1, 0x3f,
0x3e, 0xc0, 0x3c, 0xc2, 0xc3, 0x3d, 0x38, 0xc6, 0xc7, 0x39, 0xc5, 0x3b,
0x3a, 0xc4, 0x30, 0xce, 0xcf, 0x31, 0xcd, 0x33, 0x32, 0xcc, 0xc9, 0x37,
0x36, 0xc8, 0x34, 0xca, 0xcb, 0x35, 0x20, 0xde, 0xdf, 0x21, 0xdd, 0x23,
0x22, 0xdc, 0xd9, 0x27, 0x26, 0xd8, 0x24, 0xda, 0xdb, 0x25, 0xd1, 0x2f,
0x2e, 0xd0, 0x2c, 0xd2, 0xd3, 0x2d, 0x28, 0xd6, 0xd7, 0x29, 0xd5, 0x2b,
0x2a, 0xd4, 0x81, 0x7f, 0x7e, 0x80, 0x7c, 0x82, 0x83, 0x7d, 0x78, 0x86,
0x87, 0x79, 0x85, 0x7b, 0x7a, 0x84, 0x70, 0x8e, 0x8f, 0x71, 0x8d, 0x73,
0x72, 0x8c, 0x89, 0x77, 0x76, 0x88, 0x74, 0x8a, 0x8b, 0x75, 0x60, 0x9e,
0x9f, 0x61, 0x9d, 0x63, 0x62, 0x9c, 0x99, 0x67, 0x66, 0x98, 0x64, 0x9a,
0x9b, 0x65, 0x91, 0x6f, 0x6e, 0x90, 0x6c, 0x92, 0x93, 0x6d, 0x68, 0x96,
0x97, 0x69, 0x95, 0x6b, 0x6a, 0x94, 0x40, 0xbe, 0xbf, 0x41, 0xbd, 0x43,
0x42, 0xbc, 0xb9, 0x47, 0x46, 0xb8, 0x44, 0xba, 0xbb, 0x45, 0xb1, 0x4f,
0x4e, 0xb0, 0x4c, 0xb2, 0xb3, 0x4d, 0x48, 0xb6, 0xb7, 0x49, 0xb5, 0x4b,
0x4a, 0xb4, 0xa1, 0x5f, 0x5e, 0xa0, 0x5c, 0xa2, 0xa3, 0x5d, 0x58, 0xa6,
0xa7, 0x59, 0xa5, 0x5b, 0x5a, 0xa4, 0x50, 0xae, 0xaf, 0x51, 0xad, 0x53,
0x52, 0xac, 0xa9, 0x57, 0x56, 0xa8, 0x54, 0xaa, 0xab, 0x55 };
uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue)
{
return HeaderCRC[crcValue ^ dataValue];
}
/* note: table is created using unit test below */
static const uint16_t DataCRC[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624,
0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5,
0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7,
0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a,
0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a,
0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb, 0xac42, 0x9ed9,
0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f,
0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868,
0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528,
0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb,
0xaa72, 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0x7387,
0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46,
0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a,
0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb,
0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad,
0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c,
0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c,
0xd1b5, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3,
0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785,
0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956,
0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704, 0xf59f, 0xe416,
0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1,
0x0d68, 0x3ff3, 0x2e7a, 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3,
0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70,
0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 };
uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue)
{
return ((crcValue >> 8) ^ DataCRC[(crcValue & 0x00FF) ^ dataValue]);
}
#else
/* Accumulate "dataValue" into the CRC in crcValue. */
/* Return value is updated CRC */
/* */
/* The ^ operator means exclusive OR. */
/* Note: This function is copied directly from the BACnet standard. */
uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue)
{
uint16_t crc;
crc = crcValue ^ dataValue; /* XOR C7..C0 with D7..D0 */
/* Exclusive OR the terms in the table (top down) */
crc = crc ^ (crc << 1) ^ (crc << 2) ^ (crc << 3) ^ (crc << 4) ^ (crc << 5) ^
(crc << 6) ^ (crc << 7);
/* Combine bits shifted out left hand end */
return (crc & 0xfe) ^ ((crc >> 8) & 1);
}
/* Accumulate "dataValue" into the CRC in crcValue. */
/* Return value is updated CRC */
/* */
/* The ^ operator means exclusive OR. */
/* Note: This function is copied directly from the BACnet standard. */
uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue)
{
uint16_t crcLow;
crcLow = (crcValue & 0xff) ^ dataValue; /* XOR C7..C0 with D7..D0 */
/* Exclusive OR the terms in the table (top down) */
return (crcValue >> 8) ^ (crcLow << 8) ^ (crcLow << 3) ^ (crcLow << 12) ^
(crcLow >> 4) ^ (crcLow & 0x0f) ^ ((crcLow & 0x0f) << 7);
}
#endif
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
#include "bacnet/bytes.h"
/* test from Annex G 1.0 of BACnet Standard */
void testCRC8(Test *pTest)
{
uint8_t crc = 0xff; /* accumulates the crc value */
uint8_t frame_crc; /* appended to the end of the frame */
crc = CRC_Calc_Header(0x00, crc);
ct_test(pTest, crc == 0x55);
crc = CRC_Calc_Header(0x10, crc);
ct_test(pTest, crc == 0xC2);
crc = CRC_Calc_Header(0x05, crc);
ct_test(pTest, crc == 0xBC);
crc = CRC_Calc_Header(0x00, crc);
ct_test(pTest, crc == 0x95);
crc = CRC_Calc_Header(0x00, crc);
ct_test(pTest, crc == 0x73);
/* send the ones complement of the CRC in place of */
/* the CRC, and the resulting CRC will always equal 0x55. */
frame_crc = ~crc;
ct_test(pTest, frame_crc == 0x8C);
/* use the ones complement value and the next to last CRC value */
crc = CRC_Calc_Header(frame_crc, crc);
ct_test(pTest, crc == 0x55);
}
/* test from Annex G 2.0 of BACnet Standard */
void testCRC16(Test *pTest)
{
uint16_t crc = 0xffff;
uint16_t data_crc;
crc = CRC_Calc_Data(0x01, crc);
ct_test(pTest, crc == 0x1E0E);
crc = CRC_Calc_Data(0x22, crc);
ct_test(pTest, crc == 0xEB70);
crc = CRC_Calc_Data(0x30, crc);
ct_test(pTest, crc == 0x42EF);
/* send the ones complement of the CRC in place of */
/* the CRC, and the resulting CRC will always equal 0xF0B8. */
data_crc = ~crc;
ct_test(pTest, data_crc == 0xBD10);
crc = CRC_Calc_Data(LO_BYTE(data_crc), crc);
ct_test(pTest, crc == 0x0F3A);
crc = CRC_Calc_Data(HI_BYTE(data_crc), crc);
ct_test(pTest, crc == 0xF0B8);
}
void testCRC8CreateTable(Test *pTest)
{
uint8_t crc = 0xff; /* accumulates the crc value */
int i;
(void)pTest;
printf("static const uint8_t HeaderCRC[256] =\n");
printf("{\n");
printf(" ");
for (i = 0; i < 256; i++) {
crc = CRC_Calc_Header(i, 0);
printf("0x%02x, ", crc);
if (!((i + 1) % 8)) {
printf("\n");
if (i != 255) {
printf(" ");
}
}
}
printf("};\n");
}
void testCRC16CreateTable(Test *pTest)
{
uint16_t crc;
int i;
(void)pTest;
printf("static const uint16_t DataCRC[256] =\n");
printf("{\n");
printf(" ");
for (i = 0; i < 256; i++) {
crc = CRC_Calc_Data(i, 0);
printf("0x%04x, ", crc);
if (!((i + 1) % 8)) {
printf("\n");
if (i != 255) {
printf(" ");
}
}
}
printf("};\n");
}
#endif
#ifdef TEST_CRC
int main(void)
{
Test *pTest;
bool rc;
pTest = ct_create("crc", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testCRC8);
assert(rc);
rc = ct_addTestFunction(pTest, testCRC16);
assert(rc);
rc = ct_addTestFunction(pTest, testCRC8CreateTable);
assert(rc);
rc = ct_addTestFunction(pTest, testCRC16CreateTable);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void)ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif
+44
View File
@@ -0,0 +1,44 @@
/**************************************************************************
*
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*********************************************************************/
#ifndef CRC_H
#define CRC_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
uint8_t CRC_Calc_Header(
uint8_t dataValue,
uint8_t crcValue);
uint16_t CRC_Calc_Data(
uint8_t dataValue,
uint16_t crcValue);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+176
View File
@@ -0,0 +1,176 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2007 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
/** @file datalink.c Optional run-time assignment of datalink transport */
#include "bacnet/datalink/datalink.h"
#if defined(BACDL_ALL) || defined FOR_DOXYGEN
#include "bacnet/datalink/ethernet.h"
#include "bacnet/datalink/bip.h"
#include "bacnet/datalink/bip6.h"
#include "bacnet/datalink/bvlc.h"
#include "bacnet/datalink/arcnet.h"
#include "bacnet/datalink/dlmstp.h"
#include <string.h>
/* Function pointers - point to your datalink */
/** Function template to Initialize the DataLink services at the given
interface.
* @ingroup DLTemplates
*
* @note For Linux, ifname is eth0, ath0, arc0, ttyS0, and others.
For Windows, ifname is the COM port or dotted ip address of the
interface.
* @param ifname [in] The named interface to use for the network layer.
* @return True if the interface is successfully initialized,
* else False if the initialization fails.
*/
bool (*datalink_init)(char *ifname);
/** Function template to send a packet via the DataLink.
* @ingroup DLTemplates
*
* @param dest [in] Destination address.
* @param npdu_data [in] The NPDU header (Network) information.
* @param pdu [in] Buffer of data to be sent - may be null.
* @param pdu_len [in] Number of bytes in the pdu buffer.
* @return Number of bytes sent on success, negative number on failure.
*/
int (*datalink_send_pdu)(BACNET_ADDRESS *dest,
BACNET_NPDU_DATA *npdu_data,
uint8_t *pdu,
unsigned pdu_len);
uint16_t (*datalink_receive)(
BACNET_ADDRESS *src, uint8_t *pdu, uint16_t max_pdu, unsigned timeout);
/** Function template to close the DataLink services and perform any cleanup.
* @ingroup DLTemplates
*/
void (*datalink_cleanup)(void);
void (*datalink_get_broadcast_address)(BACNET_ADDRESS *dest);
void (*datalink_get_my_address)(BACNET_ADDRESS *my_address);
void datalink_set(char *datalink_string)
{
if (strcasecmp("bip", datalink_string) == 0) {
datalink_init = bip_init;
datalink_send_pdu = bip_send_pdu;
datalink_receive = bip_receive;
datalink_cleanup = bip_cleanup;
datalink_get_broadcast_address = bip_get_broadcast_address;
datalink_get_my_address = bip_get_my_address;
} else if (strcasecmp("bvlc", datalink_string) == 0) {
datalink_init = bip_init;
datalink_send_pdu = bvlc_send_pdu;
datalink_receive = bvlc_receive;
datalink_cleanup = bip_cleanup;
datalink_get_broadcast_address = bip_get_broadcast_address;
datalink_get_my_address = bip_get_my_address;
} else if (strcasecmp("bip6", datalink_string) == 0) {
datalink_init = bip6_init;
datalink_send_pdu = bip6_send_pdu;
datalink_receive = bip6_receive;
datalink_cleanup = bip6_cleanup;
datalink_get_broadcast_address = bip6_get_broadcast_address;
datalink_get_my_address = bip6_get_my_address;
} else if (strcasecmp("bvlc6", datalink_string) == 0) {
datalink_init = bip6_init;
datalink_send_pdu = bvlc6_send_pdu;
datalink_receive = bvlc6_receive;
datalink_cleanup = bip6_cleanup;
datalink_get_broadcast_address = bip6_get_broadcast_address;
datalink_get_my_address = bip6_get_my_address;
} else if (strcasecmp("ethernet", datalink_string) == 0) {
datalink_init = ethernet_init;
datalink_send_pdu = ethernet_send_pdu;
datalink_receive = ethernet_receive;
datalink_cleanup = ethernet_cleanup;
datalink_get_broadcast_address = ethernet_get_broadcast_address;
datalink_get_my_address = ethernet_get_my_address;
} else if (strcasecmp("arcnet", datalink_string) == 0) {
datalink_init = arcnet_init;
datalink_send_pdu = arcnet_send_pdu;
datalink_receive = arcnet_receive;
datalink_cleanup = arcnet_cleanup;
datalink_get_broadcast_address = arcnet_get_broadcast_address;
datalink_get_my_address = arcnet_get_my_address;
} else if (strcasecmp("mstp", datalink_string) == 0) {
datalink_init = dlmstp_init;
datalink_send_pdu = dlmstp_send_pdu;
datalink_receive = dlmstp_receive;
datalink_cleanup = dlmstp_cleanup;
datalink_get_broadcast_address = dlmstp_get_broadcast_address;
datalink_get_my_address = dlmstp_get_my_address;
}
}
#endif
#if defined(BACDL_NONE)
int datalink_send_pdu(BACNET_ADDRESS *dest,
BACNET_NPDU_DATA *npdu_data,
uint8_t *pdu,
unsigned pdu_len)
{
return 0;
}
uint16_t datalink_receive(
BACNET_ADDRESS *src, uint8_t *pdu, uint16_t max_pdu, unsigned timeout)
{
return 0;
}
void datalink_cleanup(void)
{
}
void datalink_get_broadcast_address(BACNET_ADDRESS *dest)
{
}
void datalink_get_my_address(BACNET_ADDRESS *my_address)
{
}
void datalink_set_interface(char *ifname)
{
}
void datalink_set(char *datalink_string)
{
}
#endif
+154
View File
@@ -0,0 +1,154 @@
/**************************************************************************
*
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*********************************************************************/
#ifndef DATALINK_H
#define DATALINK_H
#include "bacnet/config.h"
#include "bacnet/bacdef.h"
#if defined(BACDL_ETHERNET)
#include "bacnet/datalink/ethernet.h"
#define datalink_init ethernet_init
#define datalink_send_pdu ethernet_send_pdu
#define datalink_receive ethernet_receive
#define datalink_cleanup ethernet_cleanup
#define datalink_get_broadcast_address ethernet_get_broadcast_address
#define datalink_get_my_address ethernet_get_my_address
#elif defined(BACDL_ARCNET)
#include "bacnet/datalink/arcnet.h"
#define datalink_init arcnet_init
#define datalink_send_pdu arcnet_send_pdu
#define datalink_receive arcnet_receive
#define datalink_cleanup arcnet_cleanup
#define datalink_get_broadcast_address arcnet_get_broadcast_address
#define datalink_get_my_address arcnet_get_my_address
#elif defined(BACDL_MSTP)
#include "bacnet/datalink/dlmstp.h"
#define datalink_init dlmstp_init
#define datalink_send_pdu dlmstp_send_pdu
#define datalink_receive dlmstp_receive
#define datalink_cleanup dlmstp_cleanup
#define datalink_get_broadcast_address dlmstp_get_broadcast_address
#define datalink_get_my_address dlmstp_get_my_address
#elif defined(BACDL_BIP)
#include "bacnet/datalink/bip.h"
#include "bacnet/datalink/bvlc.h"
#define datalink_init bip_init
#if defined(BBMD_ENABLED) && BBMD_ENABLED
#define datalink_send_pdu bvlc_send_pdu
#define datalink_receive bvlc_receive
#else
#define datalink_send_pdu bip_send_pdu
#define datalink_receive bip_receive
#endif
#define datalink_cleanup bip_cleanup
#define datalink_get_broadcast_address bip_get_broadcast_address
#ifdef BAC_ROUTING
extern void routed_get_my_address(
BACNET_ADDRESS * my_address);
#define datalink_get_my_address routed_get_my_address
#else
#define datalink_get_my_address bip_get_my_address
#endif
#elif defined(BACDL_BIP6)
#include "bacnet/datalink/bip6.h"
#include "bacnet/datalink/bvlc6.h"
#define datalink_init bip6_init
#define datalink_send_pdu bip6_send_pdu
#define datalink_receive bip6_receive
#define datalink_cleanup bip6_cleanup
#define datalink_get_broadcast_address bip6_get_broadcast_address
#define datalink_get_my_address bip6_get_my_address
#elif defined(BACDL_ALL) || defined(BACDL_NONE)
#include "bacnet/npdu.h"
#define MAX_HEADER (8)
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int datalink_send_pdu(
BACNET_ADDRESS * dest,
BACNET_NPDU_DATA * npdu_data,
uint8_t * pdu,
unsigned pdu_len);
extern uint16_t datalink_receive(
BACNET_ADDRESS * src,
uint8_t * pdu,
uint16_t max_pdu,
unsigned timeout);
extern void datalink_cleanup(
void);
extern void datalink_get_broadcast_address(
BACNET_ADDRESS * dest);
extern void datalink_get_my_address(
BACNET_ADDRESS * my_address);
extern void datalink_set_interface(
char *ifname);
extern void datalink_set(
char *datalink_string);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
/** @defgroup DataLink The BACnet Network (DataLink) Layer
* <b>6 THE NETWORK LAYER </b><br>
* The purpose of the BACnet network layer is to provide the means by which
* messages can be relayed from one BACnet network to another, regardless of
* the BACnet data link technology in use on that network. Whereas the data
* link layer provides the capability to address messages to a single device
* or broadcast them to all devices on the local network, the network layer
* allows messages to be directed to a single remote device, broadcast on a
* remote network, or broadcast globally to all devices on all networks.
* A BACnet Device is uniquely located by a network number and a MAC address.
*
* Each client or server application must define exactly one of these
* DataLink settings, which will control which parts of the code will be built:
* - BACDL_ETHERNET -- for Clause 7 ISO 8802-3 ("Ethernet") LAN
* - BACDL_ARCNET -- for Clause 8 ARCNET LAN
* - BACDL_MSTP -- for Clause 9 MASTER-SLAVE/TOKEN PASSING (MS/TP) LAN
* - BACDL_BIP -- for ANNEX J - BACnet/IP
* - BACDL_ALL -- Unspecified for the build, so the transport can be
* chosen at runtime from among these choices.
* - Clause 10 POINT-TO-POINT (PTP) and Clause 11 EIA/CEA-709.1 ("LonTalk") LAN
* are not currently supported by this project.
*//** @defgroup DLTemplates DataLink Template Functions
* @ingroup DataLink
* Most of the functions in this group are function templates which are assigned
* to a specific DataLink network layer implementation either at compile time or
* at runtime.
*/
#endif
+506
View File
@@ -0,0 +1,506 @@
/**************************************************************************
*
* Copyright (C) 2009 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
/* environment variables used for the command line tools */
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "bacnet/config.h"
#include "bacnet/bacdef.h"
#include "bacnet/apdu.h"
#include "bacnet/datalink/datalink.h"
#include "bacnet/basic/services.h"
#include "bacnet/datalink/dlenv.h"
#include "bacnet/basic/tsm/tsm.h"
#if (BACNET_PROTOCOL_REVISION >= 17)
#include "bacnet/basic/object/netport.h"
#endif
/** @file dlenv.c Initialize the DataLink configuration. */
#if defined(BACDL_BIP)
/* timer used to renew Foreign Device Registration */
static uint16_t BBMD_Timer_Seconds;
/* BBMD variables */
static long bbmd_timetolive_seconds = 60000;
static long bbmd_port = 0xBAC0;
static long bbmd_address = 0;
static long bbmd_mask = 0xFFFFFFFF;
static int bbmd_result = 0;
static BBMD_TABLE_ENTRY BBMD_Table_Entry;
/* Simple setters for BBMD registration variables. */
/** Sets the IPv4 address for BBMD registration.
* If not set here or provided by Environment variables,
* no BBMD registration will occur.
* @param address - IPv4 address (long) of BBMD to register with,
* in network byte order.
*/
void dlenv_bbmd_address_set(long address)
{
bbmd_address = address;
}
/** Set the port for BBMD registration.
* Default if not set is 0xBAC0.
* @param port - The port number (provided in network byte order).
*/
void dlenv_bbmd_port_set(int port)
{
bbmd_port = port;
}
/** Set the Lease Time (Time-to-Live) for BBMD registration.
* Default if not set is 60000 (1000 minutes).
* @param ttl_secs - The Lease Time, in seconds.
*/
void dlenv_bbmd_ttl_set(int ttl_secs)
{
bbmd_timetolive_seconds = ttl_secs;
}
/** Get the result of the last attempt to register with the indicated BBMD.
* If we sent a foreign registration request, then see if we've received
* a NAK in our BVLC handler.
*
* @return Positive number (of bytes sent) if registration was successful,
* 0 if no registration request was made, or
* -1 if registration attempt failed.
*/
int dlenv_bbmd_result(void)
{
if ((bbmd_result > 0) &&
(bvlc_get_last_result() == BVLC_RESULT_REGISTER_FOREIGN_DEVICE_NAK)) {
return -1;
}
/* Else, show our send: */
return bbmd_result;
}
#endif
/** Register as a Foreign Device with the designated BBMD.
* @ingroup DataLink
* The BBMD's address, port, and lease time must be provided by
* internal variables or Environment variables.
* If no address for the BBMD is provided, no BBMD registration will occur.
*
* The Environment Variables depend on define of BACDL_BIP:
* - BACNET_BBMD_PORT - 0..65534, defaults to 47808
* - BACNET_BBMD_TIMETOLIVE - 0..65535 seconds, defaults to 60000
* - BACNET_BBMD_ADDRESS - dotted IPv4 address
* @return Positive number (of bytes sent) on success,
* 0 if no registration request is sent, or
* -1 if registration fails.
*/
int dlenv_register_as_foreign_device(void)
{
int retval = 0;
#if defined(BACDL_BIP)
char *pEnv = NULL;
unsigned a[4] = { 0 };
char bbmd_env[32] = "";
unsigned entry_number = 0;
int c;
pEnv = getenv("BACNET_BBMD_PORT");
if (pEnv) {
bbmd_port = strtol(pEnv, NULL, 0);
if (bbmd_port > 0xFFFF) {
bbmd_port = 0xBAC0;
}
}
pEnv = getenv("BACNET_BBMD_TIMETOLIVE");
if (pEnv) {
bbmd_timetolive_seconds = strtol(pEnv, NULL, 0);
if (bbmd_timetolive_seconds > 0xFFFF) {
bbmd_timetolive_seconds = 0xFFFF;
}
}
pEnv = getenv("BACNET_BBMD_ADDRESS");
if (pEnv) {
bbmd_address = bip_getaddrbyname(pEnv);
}
if (bbmd_address) {
struct in_addr addr;
addr.s_addr = bbmd_address;
fprintf(stderr, "Registering with BBMD at %s:%ld for %ld seconds\n",
inet_ntoa(addr), bbmd_port, bbmd_timetolive_seconds);
retval = bvlc_register_with_bbmd(bbmd_address,
htons((uint16_t)bbmd_port), (uint16_t)bbmd_timetolive_seconds);
if (retval < 0) {
fprintf(stderr, "FAILED to Register with BBMD at %s \n",
inet_ntoa(addr));
}
BBMD_Timer_Seconds = (uint16_t)bbmd_timetolive_seconds;
} else {
for (entry_number = 1; entry_number <= 128; entry_number++) {
sprintf(bbmd_env, "BACNET_BDT_ADDR_%u", entry_number);
pEnv = getenv(bbmd_env);
if (pEnv) {
bbmd_address = bip_getaddrbyname(pEnv);
} else if (entry_number == 1) {
/* BDT 1 is self (note: can be overridden) */
bbmd_address = bip_get_addr();
}
if (bbmd_address) {
bbmd_port = 0xBAC0;
sprintf(bbmd_env, "BACNET_BDT_PORT_%u", entry_number);
pEnv = getenv(bbmd_env);
if (pEnv) {
bbmd_port = strtol(pEnv, NULL, 0);
if (bbmd_port > 0xFFFF) {
bbmd_port = 0xBAC0;
}
} else if (entry_number == 1) {
/* BDT 1 is self (note: can be overridden) */
bbmd_port = bip_get_port();
}
bbmd_mask = 0xFFFFFFFF;
sprintf(bbmd_env, "BACNET_BDT_MASK_%u", entry_number);
pEnv = getenv(bbmd_env);
if (pEnv) {
c = sscanf(
pEnv, "%3u.%3u.%3u.%3u", &a[0], &a[1], &a[2], &a[3]);
if (c == 4) {
bbmd_mask = ((a[0] & 0xFF) << 24) |
((a[1] & 0xFF) << 16) | ((a[2] & 0xFF) << 8) |
(a[3] & 0xFF);
}
}
BBMD_Table_Entry.valid = true;
BBMD_Table_Entry.dest_address.s_addr = bbmd_address;
BBMD_Table_Entry.dest_port = bbmd_port;
BBMD_Table_Entry.broadcast_mask.s_addr = bbmd_mask;
bvlc_add_bdt_entry_local(&BBMD_Table_Entry);
}
}
}
bbmd_result = retval;
#endif
return retval;
}
#if (BACNET_PROTOCOL_REVISION >= 17)
#if defined(BACDL_BIP)
/**
* Datalink network port object settings
*/
static void dlenv_network_port_init(void)
{
uint32_t instance = 1;
uint32_t address = 0;
uint32_t broadcast = 0;
uint32_t test_broadcast = 0;
uint32_t mask = 0;
uint16_t port = 0;
uint8_t mac[4 + 2] = { 0 };
uint8_t prefix = 0;
Network_Port_Object_Instance_Number_Set(0, instance);
Network_Port_Name_Set(instance, "BACnet/IP Port");
Network_Port_Type_Set(instance, PORT_TYPE_BIP);
port = bip_get_port();
Network_Port_BIP_Port_Set(instance, port);
address = bip_get_addr();
memcpy(&mac[0], &address, 4);
memcpy(&mac[4], &port, 2);
Network_Port_MAC_Address_Set(instance, &mac[0], 6);
broadcast = bip_get_broadcast_addr();
for (prefix = 0; prefix < 32; prefix++) {
mask = htonl((0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF);
test_broadcast = (address & mask) | (~mask);
if (test_broadcast == broadcast) {
break;
}
}
Network_Port_IP_Subnet_Prefix_Set(instance, prefix);
Network_Port_Link_Speed_Set(instance, 0.0);
/* common NP data */
Network_Port_Reliability_Set(instance, RELIABILITY_NO_FAULT_DETECTED);
Network_Port_Out_Of_Service_Set(instance, false);
Network_Port_Quality_Set(instance, PORT_QUALITY_UNKNOWN);
Network_Port_APDU_Length_Set(instance, MAX_APDU);
Network_Port_Network_Number_Set(instance, 0);
/* last thing - clear pending changes - we don't want to set these
since they are already set */
Network_Port_Changes_Pending_Set(instance, false);
}
#elif defined(BACDL_MSTP)
/**
* Datalink network port object settings
*/
static void dlenv_network_port_init(void)
{
uint32_t instance = 1;
uint8_t mac[1] = { 0 };
Network_Port_Object_Instance_Number_Set(0, instance);
Network_Port_Name_Set(instance, "MS/TP Port");
Network_Port_Type_Set(instance, PORT_TYPE_MSTP);
Network_Port_MSTP_Max_Master_Set(instance, dlmstp_max_master());
Network_Port_MSTP_Max_Info_Frames_Set(instance, dlmstp_max_info_frames());
Network_Port_Link_Speed_Set(instance, dlmstp_baud_rate());
mac[0] = dlmstp_mac_address();
Network_Port_MAC_Address_Set(instance, &mac[0], 1);
/* common NP data */
Network_Port_Reliability_Set(instance, RELIABILITY_NO_FAULT_DETECTED);
Network_Port_Out_Of_Service_Set(instance, false);
Network_Port_Quality_Set(instance, PORT_QUALITY_UNKNOWN);
Network_Port_APDU_Length_Set(instance, MAX_APDU);
Network_Port_Network_Number_Set(instance, 0);
/* last thing - clear pending changes - we don't want to set these
since they are already set */
Network_Port_Changes_Pending_Set(instance, false);
}
#elif defined(BACDL_BIP6)
/**
* Datalink network port object settings
*/
static void dlenv_network_port_init(void)
{
uint32_t instance = 1;
uint8_t prefix = 0;
BACNET_ADDRESS addr = { 0 };
BACNET_IP6_ADDRESS addr6 = { 0 };
Network_Port_Object_Instance_Number_Set(0, instance);
Network_Port_Name_Set(instance, "BACnet/IPv6 Port");
Network_Port_Type_Set(instance, PORT_TYPE_BIP6);
Network_Port_BIP6_Port_Set(instance, bip6_get_port());
bip6_get_my_address(&addr);
Network_Port_MAC_Address_Set(instance, &addr.mac[0], addr.mac_len);
bip6_get_addr(&addr6);
Network_Port_IPv6_Address_Set(instance, &addr6.address[0]);
bip6_get_broadcast_addr(&addr6);
Network_Port_IPv6_Multicast_Address_Set(instance, &addr6.address[0]);
Network_Port_IPv6_Subnet_Prefix_Set(instance, prefix);
Network_Port_Reliability_Set(instance, RELIABILITY_NO_FAULT_DETECTED);
Network_Port_Link_Speed_Set(instance, 0.0);
Network_Port_Out_Of_Service_Set(instance, false);
Network_Port_Quality_Set(instance, PORT_QUALITY_UNKNOWN);
Network_Port_APDU_Length_Set(instance, MAX_APDU);
Network_Port_Network_Number_Set(instance, 0);
/* last thing - clear pending changes - we don't want to set these
since they are already set */
Network_Port_Changes_Pending_Set(instance, false);
}
#endif
#else
/**
* Datalink network port object settings
*/
static void dlenv_network_port_init(void)
{
/* do nothing */
}
#endif
/** Datalink maintenance timer
* @ingroup DataLink
*
* Call this function to renew our Foreign Device Registration
* @param elapsed_seconds Number of seconds that have elapsed since last called.
*/
void dlenv_maintenance_timer(uint16_t elapsed_seconds)
{
#if defined(BACDL_BIP)
if (BBMD_Timer_Seconds) {
if (BBMD_Timer_Seconds <= elapsed_seconds) {
BBMD_Timer_Seconds = 0;
} else {
BBMD_Timer_Seconds -= elapsed_seconds;
}
if (BBMD_Timer_Seconds == 0) {
(void)dlenv_register_as_foreign_device();
/* If that failed (negative), maybe just a network issue.
* If nothing happened (0), may be un/misconfigured.
* Set up to try again later in all cases. */
BBMD_Timer_Seconds = (uint16_t)bbmd_timetolive_seconds;
}
}
#endif
}
/** Initialize the DataLink configuration from Environment variables,
* or else to defaults.
* @ingroup DataLink
* The items configured depend on which BACDL_ the code is built for,
* eg, BACDL_BIP.
*
* For most items, checks first for an environment variable, and, if
* found, uses that to set the item's value. Otherwise, will set
* to a default value.
*
* The Environment Variables, by BACDL_ type, are:
* - BACDL_ALL: (the general-purpose solution)
* - BACNET_DATALINK to set which BACDL_ type we are using.
* - (Any):
* - BACNET_APDU_TIMEOUT - set this value in milliseconds to change
* the APDU timeout. APDU Timeout is how much time a client
* waits for a response from a BACnet device.
* - BACNET_APDU_RETRIES - indicate the maximum number of times that
* an APDU shall be retransmitted.
* - BACNET_IFACE - set this value to dotted IP address (Windows) of
* the interface (see ipconfig command on Windows) for which you
* want to bind. On Linux, set this to the /dev interface
* (i.e. eth0, arc0). Default is eth0 on Linux, and the default
* interface on Windows. Hence, if there is only a single network
* interface on Windows, the applications will choose it, and this
* setting will not be needed.
* - BACDL_BIP: (BACnet/IP)
* - BACNET_IP_PORT - UDP/IP port number (0..65534) used for BACnet/IP
* communications. Default is 47808 (0xBAC0).
* - BACNET_BBMD_PORT - UDP/IP port number (0..65534) used for Foreign
* Device Registration. Defaults to 47808 (0xBAC0).
* - BACNET_BBMD_TIMETOLIVE - number of seconds used in Foreign Device
* Registration (0..65535). Defaults to 60000 seconds.
* - BACNET_BBMD_ADDRESS - dotted IPv4 address of the BBMD or Foreign
* Device Registrar.
* - BACNET_BDT_ADDR_1 - dotted IPv4 address of the BBMD table entry 1..128
* - BACNET_BDT_PORT_1 - UDP port of the BBMD table entry 1..128 (optional)
* - BACNET_BDT_MASK_1 - dotted IPv4 mask of the BBMD table
* entry 1..128 (optional)
* - BACNET_IP_NAT_ADDR - dotted IPv4 address of the public facing router
* - BACDL_MSTP: (BACnet MS/TP)
* - BACNET_MAX_INFO_FRAMES
* - BACNET_MAX_MASTER
* - BACNET_MSTP_BAUD
* - BACNET_MSTP_MAC
* - BACDL_BIP6: (BACnet/IPv6)
* - BACNET_BIP6_PORT - UDP/IP port number (0..65534) used for BACnet/IPv6
* communications. Default is 47808 (0xBAC0).
* - BACNET_BIP6_BROADCAST - FF05::BAC0 or FF02::BAC0 or ...
*/
void dlenv_init(void)
{
char *pEnv = NULL;
#if defined(BACDL_ALL)
pEnv = getenv("BACNET_DATALINK");
if (pEnv) {
datalink_set(pEnv);
} else {
datalink_set(NULL);
}
#endif
#if defined(BACDL_BIP6)
BACNET_IP6_ADDRESS addr;
pEnv = getenv("BACNET_BIP6_BROADCAST");
if (pEnv) {
bvlc6_address_set(&addr, (uint16_t)strtol(pEnv, NULL, 0), 0, 0, 0, 0, 0,
0, BIP6_MULTICAST_GROUP_ID);
bip6_set_broadcast_addr(&addr);
} else {
bvlc6_address_set(&addr, BIP6_MULTICAST_SITE_LOCAL, 0, 0, 0, 0, 0, 0,
BIP6_MULTICAST_GROUP_ID);
bip6_set_broadcast_addr(&addr);
}
pEnv = getenv("BACNET_BIP6_PORT");
if (pEnv) {
bip6_set_port((uint16_t)strtol(pEnv, NULL, 0));
} else {
bip6_set_port(0xBAC0);
}
#endif
#if defined(BACDL_BIP)
#if defined(BIP_DEBUG)
BIP_Debug = true;
#endif
pEnv = getenv("BACNET_IP_PORT");
if (pEnv) {
bip_set_port(htons((uint16_t)strtol(pEnv, NULL, 0)));
} else {
/* BIP_Port is statically initialized to 0xBAC0,
* so if it is different, then it was programmatically altered,
* and we shouldn't just stomp on it here.
* Unless it is set below 1024, since:
* "The range for well-known ports managed by the IANA is 0-1023."
*/
if (ntohs(bip_get_port()) < 1024) {
bip_set_port(htons(0xBAC0));
}
}
pEnv = getenv("BACNET_IP_NAT_ADDR");
if (pEnv) {
struct in_addr nat_addr;
nat_addr.s_addr = bip_getaddrbyname(pEnv);
if (nat_addr.s_addr) {
bvlc_set_global_address_for_nat(&nat_addr);
}
}
#elif defined(BACDL_MSTP)
pEnv = getenv("BACNET_MAX_INFO_FRAMES");
if (pEnv) {
dlmstp_set_max_info_frames(strtol(pEnv, NULL, 0));
} else {
dlmstp_set_max_info_frames(1);
}
pEnv = getenv("BACNET_MAX_MASTER");
if (pEnv) {
dlmstp_set_max_master(strtol(pEnv, NULL, 0));
} else {
dlmstp_set_max_master(127);
}
pEnv = getenv("BACNET_MSTP_BAUD");
if (pEnv) {
dlmstp_set_baud_rate(strtol(pEnv, NULL, 0));
} else {
dlmstp_set_baud_rate(38400);
}
pEnv = getenv("BACNET_MSTP_MAC");
if (pEnv) {
dlmstp_set_mac_address(strtol(pEnv, NULL, 0));
} else {
dlmstp_set_mac_address(127);
}
#endif
pEnv = getenv("BACNET_APDU_TIMEOUT");
if (pEnv) {
apdu_timeout_set((uint16_t)strtol(pEnv, NULL, 0));
} else {
#if defined(BACDL_MSTP)
apdu_timeout_set(60000);
#endif
}
pEnv = getenv("BACNET_APDU_RETRIES");
if (pEnv) {
apdu_retries_set((uint8_t)strtol(pEnv, NULL, 0));
}
/* === Initialize the Datalink Here === */
if (!datalink_init(getenv("BACNET_IFACE"))) {
exit(1);
}
#if (MAX_TSM_TRANSACTIONS)
pEnv = getenv("BACNET_INVOKE_ID");
if (pEnv) {
tsm_invokeID_set((uint8_t)strtol(pEnv, NULL, 0));
}
#endif
dlenv_network_port_init();
dlenv_register_as_foreign_device();
}
+52
View File
@@ -0,0 +1,52 @@
/**************************************************************************
*
* Copyright (C) 2009 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
#ifndef DLENV_H
#define DLENV_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void dlenv_init(
void);
int dlenv_register_as_foreign_device(
void);
void dlenv_maintenance_timer(
uint16_t elapsed_seconds);
/* Simple setters and getter. */
void dlenv_bbmd_address_set(
long address);
void dlenv_bbmd_port_set(
int port);
void dlenv_bbmd_ttl_set(
int ttl_secs);
int dlenv_bbmd_result(
void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+122
View File
@@ -0,0 +1,122 @@
/**************************************************************************
*
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*********************************************************************/
#ifndef DLMSTP_H
#define DLMSTP_H
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include "bacnet/bacdef.h"
#include "bacnet/npdu.h"
/* defines specific to MS/TP */
/* preamble+type+dest+src+len+crc8+crc16 */
#define MAX_HEADER (2+1+1+1+2+1+2)
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
typedef struct dlmstp_packet {
bool ready; /* true if ready to be sent or received */
BACNET_ADDRESS address; /* source address */
uint8_t frame_type; /* type of message */
uint16_t pdu_len; /* packet length */
uint8_t pdu[MAX_MPDU]; /* packet */
} DLMSTP_PACKET;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
bool dlmstp_init(
char *ifname);
void dlmstp_reset(
void);
void dlmstp_cleanup(
void);
/* returns number of bytes sent on success, negative on failure */
int dlmstp_send_pdu(
BACNET_ADDRESS * dest, /* destination address */
BACNET_NPDU_DATA * npdu_data, /* network information */
uint8_t * pdu, /* any data to be sent - may be null */
unsigned pdu_len); /* number of bytes of data */
/* returns the number of octets in the PDU, or zero on failure */
uint16_t dlmstp_receive(
BACNET_ADDRESS * src, /* source address */
uint8_t * pdu, /* PDU data */
uint16_t max_pdu, /* amount of space available in the PDU */
unsigned timeout); /* milliseconds to wait for a packet */
/* This parameter represents the value of the Max_Info_Frames property of */
/* the node's Device object. The value of Max_Info_Frames specifies the */
/* maximum number of information frames the node may send before it must */
/* pass the token. Max_Info_Frames may have different values on different */
/* nodes. This may be used to allocate more or less of the available link */
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
/* node, its value shall be 1. */
void dlmstp_set_max_info_frames(
uint8_t max_info_frames);
uint8_t dlmstp_max_info_frames(
void);
/* This parameter represents the value of the Max_Master property of the */
/* node's Device object. The value of Max_Master specifies the highest */
/* allowable address for master nodes. The value of Max_Master shall be */
/* less than or equal to 127. If Max_Master is not writable in a node, */
/* its value shall be 127. */
void dlmstp_set_max_master(
uint8_t max_master);
uint8_t dlmstp_max_master(
void);
/* MAC address 0-127 */
void dlmstp_set_mac_address(
uint8_t my_address);
uint8_t dlmstp_mac_address(
void);
void dlmstp_get_my_address(
BACNET_ADDRESS * my_address);
void dlmstp_get_broadcast_address(
BACNET_ADDRESS * dest); /* destination address */
/* RS485 Baud Rate 9600, 19200, 38400, 57600, 115200 */
void dlmstp_set_baud_rate(
uint32_t baud);
uint32_t dlmstp_baud_rate(
void);
void dlmstp_fill_bacnet_address(
BACNET_ADDRESS * src,
uint8_t mstp_address);
bool dlmstp_sole_master(
void);
bool dlmstp_send_pdu_queue_empty(void);
bool dlmstp_send_pdu_queue_full(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+82
View File
@@ -0,0 +1,82 @@
/**************************************************************************
*
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*********************************************************************/
#ifndef ETHERNET_H
#define ETHERNET_H
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include "bacnet/bacdef.h"
#include "bacnet/npdu.h"
/* specific defines for Ethernet */
#define MAX_HEADER (6+6+2+1+1+1)
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
bool ethernet_valid(
void);
void ethernet_cleanup(
void);
bool ethernet_init(
char *interface_name);
/* function to send a packet out the 802.2 socket */
/* returns number of bytes sent on success, negative on failure */
int ethernet_send_pdu(
BACNET_ADDRESS * dest, /* destination address */
BACNET_NPDU_DATA * npdu_data, /* network information */
uint8_t * pdu, /* any data to be sent - may be null */
unsigned pdu_len); /* number of bytes of data */
/* receives an 802.2 framed packet */
/* returns the number of octets in the PDU, or zero on failure */
uint16_t ethernet_receive(
BACNET_ADDRESS * src, /* source address */
uint8_t * pdu, /* PDU data */
uint16_t max_pdu, /* amount of space available in the PDU */
unsigned timeout); /* milliseconds to wait for a packet */
void ethernet_set_my_address(
BACNET_ADDRESS * my_address);
void ethernet_get_my_address(
BACNET_ADDRESS * my_address);
void ethernet_get_broadcast_address(
BACNET_ADDRESS * dest); /* destination address */
/* some functions from Linux driver */
void ethernet_debug_address(
const char *info,
BACNET_ADDRESS * dest);
int ethernet_send(
uint8_t * mtu,
int mtu_len);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
File diff suppressed because it is too large Load Diff
+232
View File
@@ -0,0 +1,232 @@
/**************************************************************************
*
* Copyright (C) 2004 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
#ifndef MSTP_H
#define MSTP_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "bacnet/datalink/mstpdef.h"
struct mstp_port_struct_t {
MSTP_RECEIVE_STATE receive_state;
/* When a master node is powered up or reset, */
/* it shall unconditionally enter the INITIALIZE state. */
MSTP_MASTER_STATE master_state;
/* A Boolean flag set to TRUE by the Receive State Machine */
/* if an error is detected during the reception of a frame. */
/* Set to FALSE by the Master or Slave Node state machine. */
unsigned ReceiveError:1;
/* There is data in the buffer */
unsigned DataAvailable:1;
unsigned ReceivedInvalidFrame:1;
/* A Boolean flag set to TRUE by the Receive State Machine */
/* if a valid frame is received. */
/* Set to FALSE by the Master or Slave Node state machine. */
unsigned ReceivedValidFrame:1;
/* A Boolean flag set to TRUE by the Receive State Machine */
/* if a valid frame is received but it is not addressed to us. */
/* Set to FALSE by the Master or Slave Node state machine. */
unsigned ReceivedValidFrameNotForUs:1;
/* A Boolean flag set to TRUE by the master machine if this node is the */
/* only known master node. */
unsigned SoleMaster:1;
/* stores the latest received data */
uint8_t DataRegister;
/* Used to accumulate the CRC on the data field of a frame. */
uint16_t DataCRC;
/* Used to store the actual CRC from the data field. */
uint8_t DataCRCActualMSB;
uint8_t DataCRCActualLSB;
/* Used to store the data length of a received frame. */
uint16_t DataLength;
/* Used to store the destination address of a received frame. */
uint8_t DestinationAddress;
/* Used to count the number of received octets or errors. */
/* This is used in the detection of link activity. */
/* Compared to Nmin_octets */
uint8_t EventCount;
/* Used to store the frame type of a received frame. */
uint8_t FrameType;
/* The number of frames sent by this node during a single token hold. */
/* When this counter reaches the value Nmax_info_frames, the node must */
/* pass the token. */
uint8_t FrameCount;
/* Used to accumulate the CRC on the header of a frame. */
uint8_t HeaderCRC;
/* Used to store the actual CRC from the header. */
uint8_t HeaderCRCActual;
/* Used as an index by the Receive State Machine, up to a maximum value of */
/* InputBufferSize. */
uint32_t Index;
/* An array of octets, used to store octets as they are received. */
/* InputBuffer is indexed from 0 to InputBufferSize-1. */
/* The maximum size of a frame is 501 octets. */
/* FIXME: assign this to an actual array of bytes! */
/* Note: the buffer is designed as a pointer since some compilers
and microcontroller architectures have limits as to places to
hold contiguous memory. */
uint8_t *InputBuffer;
uint16_t InputBufferSize;
/* "Next Station," the MAC address of the node to which This Station passes */
/* the token. If the Next_Station is unknown, Next_Station shall be equal to */
/* This_Station. */
uint8_t Next_Station;
/* "Poll Station," the MAC address of the node to which This Station last */
/* sent a Poll For Master. This is used during token maintenance. */
uint8_t Poll_Station;
/* A counter of transmission retries used for Token and Poll For Master */
/* transmission. */
unsigned RetryCount;
/* A timer with nominal 5 millisecond resolution used to measure and */
/* generate silence on the medium between octets. It is incremented by a */
/* timer process and is cleared by the Receive State Machine when activity */
/* is detected and by the SendFrame procedure as each octet is transmitted. */
/* Since the timer resolution is limited and the timer is not necessarily */
/* synchronized to other machine events, a timer value of N will actually */
/* denote intervals between N-1 and N */
/* Note: done here as functions - put into timer task or ISR
so that you can be atomic on 8 bit microcontrollers */
uint32_t(
*SilenceTimer) (
void *pArg);
void (
*SilenceTimerReset) (
void *pArg);
/* A timer used to measure and generate Reply Postponed frames. It is */
/* incremented by a timer process and is cleared by the Master Node State */
/* Machine when a Data Expecting Reply Answer activity is completed. */
/* note: we always send a reply postponed since a message other than
the reply may be in the transmit queue */
/* uint16_t ReplyPostponedTimer; */
/* Used to store the Source Address of a received frame. */
uint8_t SourceAddress;
/* The number of tokens received by this node. When this counter reaches the */
/* value Npoll, the node polls the address range between TS and NS for */
/* additional master nodes. TokenCount is set to zero at the end of the */
/* polling process. */
unsigned TokenCount;
/* "This Station," the MAC address of this node. TS is generally read from a */
/* hardware DIP switch, or from nonvolatile memory. Valid values for TS are */
/* 0 to 254. The value 255 is used to denote broadcast when used as a */
/* destination address but is not allowed as a value for TS. */
uint8_t This_Station;
/* This parameter represents the value of the Max_Info_Frames property of */
/* the node's Device object. The value of Max_Info_Frames specifies the */
/* maximum number of information frames the node may send before it must */
/* pass the token. Max_Info_Frames may have different values on different */
/* nodes. This may be used to allocate more or less of the available link */
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
/* node, its value shall be 1. */
uint8_t Nmax_info_frames;
/* This parameter represents the value of the Max_Master property of the */
/* node's Device object. The value of Max_Master specifies the highest */
/* allowable address for master nodes. The value of Max_Master shall be */
/* less than or equal to 127. If Max_Master is not writable in a node, */
/* its value shall be 127. */
uint8_t Nmax_master;
/* An array of octets, used to store octets for transmitting */
/* OutputBuffer is indexed from 0 to OutputBufferSize-1. */
/* The maximum size of a frame is 501 octets. */
/* FIXME: assign this to an actual array of bytes! */
/* Note: the buffer is designed as a pointer since some compilers
and microcontroller architectures have limits as to places to
hold contiguous memory. */
uint8_t *OutputBuffer;
uint16_t OutputBufferSize;
/*Platform-specific port data */
void *UserData;
};
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void MSTP_Init(
volatile struct mstp_port_struct_t *mstp_port);
void MSTP_Receive_Frame_FSM(
volatile struct mstp_port_struct_t
*mstp_port);
bool MSTP_Master_Node_FSM(
volatile struct mstp_port_struct_t
*mstp_port);
void MSTP_Slave_Node_FSM(
volatile struct mstp_port_struct_t *mstp_port);
/* returns true if line is active */
bool MSTP_Line_Active(
volatile struct mstp_port_struct_t *mstp_port);
uint16_t MSTP_Create_Frame(
uint8_t * buffer, /* where frame is loaded */
uint16_t buffer_len, /* amount of space available */
uint8_t frame_type, /* type of frame to send - see defines */
uint8_t destination, /* destination address */
uint8_t source, /* source address */
uint8_t * data, /* any data to be sent - may be null */
uint16_t data_len); /* number of bytes of data (up to 501) */
void MSTP_Create_And_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, /* port to send from */
uint8_t frame_type, /* type of frame to send - see defines */
uint8_t destination, /* destination address */
uint8_t source, /* source address */
uint8_t * data, /* any data to be sent - may be null */
uint16_t data_len);
void MSTP_Fill_BACnet_Address(
BACNET_ADDRESS * src,
uint8_t mstp_address);
/* functions used by the MS/TP state machine to put or get data */
/* FIXME: developer must implement these in their DLMSTP module */
uint16_t MSTP_Put_Receive(
volatile struct mstp_port_struct_t *mstp_port);
/* for the MS/TP state machine to use for getting data to send */
/* Return: amount of PDU data */
uint16_t MSTP_Get_Send(
volatile struct mstp_port_struct_t *mstp_port,
unsigned timeout); /* milliseconds to wait for a packet */
/* for the MS/TP state machine to use for getting the reply for
Data-Expecting-Reply Frame */
/* Return: amount of PDU data */
uint16_t MSTP_Get_Reply(
volatile struct mstp_port_struct_t *mstp_port,
unsigned timeout); /* milliseconds to wait for a packet */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+134
View File
@@ -0,0 +1,134 @@
/**************************************************************************
*
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*********************************************************************/
#ifndef MSTPDEF_H
#define MSTPDEF_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "bacnet/bacdef.h"
/* The value 255 is used to denote broadcast when used as a */
/* destination address but is not allowed as a value for a station. */
/* Station addresses for master nodes can be 0-127. */
/* Station addresses for slave nodes can be 127-254. */
#define MSTP_BROADCAST_ADDRESS 255
/* MS/TP Frame Type */
/* Frame Types 8 through 127 are reserved by ASHRAE. */
#define FRAME_TYPE_TOKEN 0
#define FRAME_TYPE_POLL_FOR_MASTER 1
#define FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER 2
#define FRAME_TYPE_TEST_REQUEST 3
#define FRAME_TYPE_TEST_RESPONSE 4
#define FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY 5
#define FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY 6
#define FRAME_TYPE_REPLY_POSTPONED 7
/* Frame Types 128 through 255: Proprietary Frames */
/* These frames are available to vendors as proprietary (non-BACnet) frames. */
/* The first two octets of the Data field shall specify the unique vendor */
/* identification code, most significant octet first, for the type of */
/* vendor-proprietary frame to be conveyed. The length of the data portion */
/* of a Proprietary frame shall be in the range of 2 to 501 octets. */
#define FRAME_TYPE_PROPRIETARY_MIN 128
#define FRAME_TYPE_PROPRIETARY_MAX 255
/* The initial CRC16 checksum value */
#define CRC16_INITIAL_VALUE (0xFFFF)
/* receive FSM states */
typedef enum {
MSTP_RECEIVE_STATE_IDLE = 0,
MSTP_RECEIVE_STATE_PREAMBLE = 1,
MSTP_RECEIVE_STATE_HEADER = 2,
MSTP_RECEIVE_STATE_DATA = 3,
MSTP_RECEIVE_STATE_SKIP_DATA = 4
} MSTP_RECEIVE_STATE;
/* master node FSM states */
typedef enum {
MSTP_MASTER_STATE_INITIALIZE = 0,
MSTP_MASTER_STATE_IDLE = 1,
MSTP_MASTER_STATE_USE_TOKEN = 2,
MSTP_MASTER_STATE_WAIT_FOR_REPLY = 3,
MSTP_MASTER_STATE_DONE_WITH_TOKEN = 4,
MSTP_MASTER_STATE_PASS_TOKEN = 5,
MSTP_MASTER_STATE_NO_TOKEN = 6,
MSTP_MASTER_STATE_POLL_FOR_MASTER = 7,
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8
} MSTP_MASTER_STATE;
/* The time without a DataAvailable or ReceiveError event before declaration */
/* of loss of token: 500 milliseconds. */
#define Tno_token 500
/* The minimum time after the end of the stop bit of the final octet of a */
/* received frame before a node may enable its EIA-485 driver: 40 bit times. */
/* At 9600 baud, 40 bit times would be about 4.166 milliseconds */
/* At 19200 baud, 40 bit times would be about 2.083 milliseconds */
/* At 38400 baud, 40 bit times would be about 1.041 milliseconds */
/* At 57600 baud, 40 bit times would be about 0.694 milliseconds */
/* At 76800 baud, 40 bit times would be about 0.520 milliseconds */
/* At 115200 baud, 40 bit times would be about 0.347 milliseconds */
/* 40 bits is 4 octets including a start and stop bit with each octet */
#define Tturnaround (40UL)
/* turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */
/* The number of tokens received or used before a Poll For Master cycle */
/* is executed: 50. */
#define Npoll 50
/* The number of retries on sending Token: 1. */
#define Nretry_token 1
/* The maximum idle time a sending node may allow to elapse between octets */
/* of a frame the node is transmitting: 20 bit times. */
#define Tframe_gap 20
/* The maximum time after the end of the stop bit of the final */
/* octet of a transmitted frame before a node must disable its */
/* EIA-485 driver: 15 bit times. */
#define Tpostdrive 15
/* The width of the time slot within which a node may generate a token: */
/* 10 milliseconds. */
#define Tslot 10
/* The maximum time a node may wait after reception of the token or */
/* a Poll For Master frame before sending the first octet of a frame: */
/* 15 milliseconds. */
#define Tusage_delay 15
#define DEFAULT_MAX_INFO_FRAMES 1
#define DEFAULT_MAX_MASTER 127
#define DEFAULT_MAC_ADDRESS 127
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+84
View File
@@ -0,0 +1,84 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2007 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
#include <stdio.h>
#include "bacnet/datalink/mstp.h"
#include "bacnet/indtext.h"
#include "bacnet/bacenum.h"
#include "bacnet/datalink/mstptext.h"
/** @file mstptext.c Text mapping functions for BACnet MS/TP */
static INDTEXT_DATA mstp_receive_state_text[] = { { MSTP_RECEIVE_STATE_IDLE,
"IDLE" },
{ MSTP_RECEIVE_STATE_PREAMBLE, "PREAMBLE" },
{ MSTP_RECEIVE_STATE_HEADER, "HEADER" },
{ MSTP_RECEIVE_STATE_DATA, "DATA" }, { 0, NULL } };
const char *mstptext_receive_state(unsigned index)
{
return indtext_by_index_default(mstp_receive_state_text, index, "unknown");
}
static INDTEXT_DATA mstp_master_state_text[] = { { MSTP_MASTER_STATE_INITIALIZE,
"INITIALIZE" },
{ MSTP_MASTER_STATE_IDLE, "IDLE" },
{ MSTP_MASTER_STATE_USE_TOKEN, "USE_TOKEN" },
{ MSTP_MASTER_STATE_WAIT_FOR_REPLY, "WAIT_FOR_REPLY" },
{ MSTP_MASTER_STATE_DONE_WITH_TOKEN, "DONE_WITH_TOKEN" },
{ MSTP_MASTER_STATE_PASS_TOKEN, "PASS_TOKEN" },
{ MSTP_MASTER_STATE_NO_TOKEN, "NO_TOKEN" },
{ MSTP_MASTER_STATE_POLL_FOR_MASTER, "POLL_FOR_MASTER" },
{ MSTP_MASTER_STATE_ANSWER_DATA_REQUEST, "ANSWER_DATA_REQUEST" },
{ 0, NULL } };
const char *mstptext_master_state(unsigned index)
{
return indtext_by_index_default(mstp_master_state_text, index, "unknown");
}
static INDTEXT_DATA mstp_frame_type_text[] = { { FRAME_TYPE_TOKEN, "TOKEN" },
{ FRAME_TYPE_POLL_FOR_MASTER, "POLL_FOR_MASTER" },
{ FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, "REPLY_TO_POLL_FOR_MASTER" },
{ FRAME_TYPE_TEST_REQUEST, "TEST_REQUEST" },
{ FRAME_TYPE_TEST_RESPONSE, "TEST_RESPONSE" },
{ FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY, "BACNET_DATA_EXPECTING_REPLY" },
{ FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY,
"BACNET_DATA_NOT_EXPECTING_REPLY" },
{ FRAME_TYPE_REPLY_POSTPONED, "REPLY_POSTPONED" }, { 0, NULL } };
const char *mstptext_frame_type(unsigned index)
{
return indtext_by_index_split_default(mstp_frame_type_text, index,
FRAME_TYPE_PROPRIETARY_MIN, "UNKNOWN", "PROPRIETARY");
}
+41
View File
@@ -0,0 +1,41 @@
/**************************************************************************
*
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*********************************************************************/
#ifndef MSTPTEXT_H
#define MSTPTEXT_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
const char *mstptext_receive_state(
unsigned index);
const char *mstptext_master_state(
unsigned index);
const char *mstptext_frame_type(
unsigned index);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif