void apdu_handler( BACNET_ADDRESS * src, uint8_t * apdu, /* APDU data */ uint16_t apdu_len) { BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 }; uint8_t service_choice = 0; uint8_t *service_request = NULL; uint16_t service_request_len = 0; uint16_t len = 0; /* counts where we are in PDU */ if (apdu) { /* PDU Type */ switch (apdu[0] & 0xF0) { case PDU_TYPE_CONFIRMED_SERVICE_REQUEST: len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */ apdu_len, &service_data, &service_choice, &service_request, &service_request_len); if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) { handler_read_property(service_request, service_request_len, src, &service_data); } #ifdef WRITE_PROPERTY else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) { handler_write_property(service_request, service_request_len, src, &service_data); } #endif else { handler_unrecognized_service(service_request, service_request_len, src, &service_data); } break; case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST: service_choice = apdu[1]; service_request = &apdu[2]; service_request_len = apdu_len - 2; if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) { handler_who_is(service_request, service_request_len, src); } break; case PDU_TYPE_SIMPLE_ACK: case PDU_TYPE_COMPLEX_ACK: case PDU_TYPE_SEGMENT_ACK: case PDU_TYPE_ERROR: case PDU_TYPE_REJECT: case PDU_TYPE_ABORT: default: break; } } return; }
void apdu_handler( BACNET_ADDRESS * src, uint8_t * apdu, /* APDU data */ uint16_t apdu_len) { BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 }; uint8_t service_choice = 0; uint8_t *service_request = NULL; uint16_t service_request_len = 0; uint16_t len = 0; /* counts where we are in PDU */ if (apdu) { /* PDU Type */ switch (apdu[0] & 0xF0) { case PDU_TYPE_CONFIRMED_SERVICE_REQUEST: len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */ apdu_len, &service_data, &service_choice, &service_request, &service_request_len); if (apdu_confirmed_dcc_disabled(service_choice)) { /* When network communications are completely disabled, only DeviceCommunicationControl and ReinitializeDevice APDUs shall be processed and no messages shall be initiated. */ break; } if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) { handler_read_property(service_request, service_request_len, src, &service_data); } else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) { handler_write_property(service_request, service_request_len, src, &service_data); } else if (service_choice == SERVICE_CONFIRMED_REINITIALIZE_DEVICE) { handler_reinitialize_device(service_request, service_request_len, src, &service_data); } else if (service_choice == SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL) { handler_device_communication_control(service_request, service_request_len, src, &service_data); } else { handler_unrecognized_service(service_request, service_request_len, src, &service_data); } break; case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST: service_choice = apdu[1]; service_request = &apdu[2]; service_request_len = apdu_len - 2; if (apdu_unconfirmed_dcc_disabled(service_choice)) { /* When network communications are disabled, only DeviceCommunicationControl and ReinitializeDevice APDUs shall be processed and no messages shall be initiated. If communications have been initiation disabled, then WhoIs may be processed. */ break; } if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) { handler_who_is(service_request, service_request_len, src); } break; case PDU_TYPE_SIMPLE_ACK: case PDU_TYPE_COMPLEX_ACK: case PDU_TYPE_SEGMENT_ACK: case PDU_TYPE_ERROR: case PDU_TYPE_REJECT: case PDU_TYPE_ABORT: default: break; } } return; }
/** Process the APDU header and invoke the appropriate service handler * to manage the received request. * Almost all requests and ACKs invoke this function. * @ingroup MISCHNDLR * * @param src [in] The BACNET_ADDRESS of the message's source. * @param apdu [in] The apdu portion of the request, to be processed. * @param apdu_len [in] The total (remaining) length of the apdu. */ void apdu_handler( BACNET_ADDRESS * src, uint8_t * apdu, /* APDU data */ uint16_t apdu_len) { BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 }; BACNET_CONFIRMED_SERVICE_ACK_DATA service_ack_data = { 0 }; //uint8_t invoke_id = 0; uint8_t service_choice = 0; uint8_t *service_request = NULL; uint16_t service_request_len = 0; int len = 0; /* counts where we are in PDU */ uint8_t tag_number = 0; uint32_t len_value = 0; uint32_t error_code = 0; uint32_t error_class = 0; // uint8_t reason = 0; // bool server = false; if (apdu) { /* PDU Type */ switch (apdu[0] & 0xF0) { case PDU_TYPE_CONFIRMED_SERVICE_REQUEST: len = (int) apdu_decode_confirmed_service_request(&apdu[0], apdu_len, &service_data, &service_choice, &service_request, &service_request_len); #if 0 if (apdu_confirmed_dcc_disabled(service_choice)) { tbd: chelsea /* When network communications are completely disabled, only DeviceCommunicationControl and ReinitializeDevice APDUs shall be processed and no messages shall be initiated. */ break; } if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) && (Confirmed_Function[service_choice])) Confirmed_Function[service_choice] (service_request, service_request_len/*, src, &service_data*/); else if (Unrecognized_Service_Handler) Unrecognized_Service_Handler(service_request, service_request_len/*, src, &service_data*/); #endif // #if READ_WRITE_PROPERTY #if 1 if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) { handler_read_property(service_request, service_request_len, src, &service_data); } else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) { handler_write_property(service_request, service_request_len, src, &service_data); } else #endif if (service_choice == SERVICE_CONFIRMED_PRIVATE_TRANSFER) { handler_private_transfer(apdu,apdu_len,src); // add private transfer by chelsea } else { handler_unrecognized_service(service_request, service_request_len, src, &service_data); } break; case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST: { //U8_T i; service_choice = apdu[1]; service_request = &apdu[2]; service_request_len = apdu_len - 2; #if 0 if (apdu_unconfirmed_dcc_disabled(service_choice)) { /* When network communications are disabled, only DeviceCommunicationControl and ReinitializeDevice APDUs shall be processed and no messages shall be initiated. If communications have been initiation disabled, then WhoIs may be processed. */ break; } if (service_choice < MAX_BACNET_UNCONFIRMED_SERVICE) { if (Unconfirmed_Function[service_choice]) Unconfirmed_Function[service_choice] ( service_request, service_request_len/*, src*/); // tbd: chelsea } #endif if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) { if( modbus.protocal == BAC_MSTP) { handler_who_is(service_request, service_request_len, src); } else if((modbus.protocal == BAC_IP) || (modbus.protocal == BAC_GSM)) { Send_I_Am(&Handler_Transmit_Buffer[0]); } } else if (service_choice == SERVICE_UNCONFIRMED_PRIVATE_TRANSFER) { // add unconfirmedPrivateTransfer handler, for TEMCO private handler_private_transfer(apdu,apdu_len,src); } } break; case PDU_TYPE_SIMPLE_ACK: // invoke_id = apdu[1]; service_choice = apdu[2]; switch (service_choice) { case SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM: case SERVICE_CONFIRMED_COV_NOTIFICATION: case SERVICE_CONFIRMED_EVENT_NOTIFICATION: case SERVICE_CONFIRMED_SUBSCRIBE_COV: case SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY: case SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION: /* Object Access Services */ case SERVICE_CONFIRMED_ADD_LIST_ELEMENT: case SERVICE_CONFIRMED_REMOVE_LIST_ELEMENT: case SERVICE_CONFIRMED_DELETE_OBJECT: case SERVICE_CONFIRMED_WRITE_PROPERTY: case SERVICE_CONFIRMED_WRITE_PROP_MULTIPLE: /* Remote Device Management Services */ case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL: case SERVICE_CONFIRMED_REINITIALIZE_DEVICE: case SERVICE_CONFIRMED_TEXT_MESSAGE: /* Virtual Terminal Services */ case SERVICE_CONFIRMED_VT_CLOSE: /* Security Services */ case SERVICE_CONFIRMED_REQUEST_KEY: if (Confirmed_ACK_Function[service_choice] != NULL) { // tbd: chelsea // ((confirmed_simple_ack_function) // Confirmed_ACK_Function[service_choice]) (src, // invoke_id); } // tsm_free_invoke_id(invoke_id); break; default: break; } break; case PDU_TYPE_COMPLEX_ACK: service_ack_data.segmented_message = (apdu[0] & BIT3) ? true : false; service_ack_data.more_follows = (apdu[0] & BIT2) ? true : false; // invoke_id = service_ack_data.invoke_id = apdu[1]; len = 2; if (service_ack_data.segmented_message) { service_ack_data.sequence_number = apdu[len++]; service_ack_data.proposed_window_number = apdu[len++]; } service_choice = apdu[len++]; service_request = &apdu[len]; service_request_len = apdu_len - (uint16_t) len; switch (service_choice) { case SERVICE_CONFIRMED_GET_ALARM_SUMMARY: case SERVICE_CONFIRMED_GET_ENROLLMENT_SUMMARY: case SERVICE_CONFIRMED_GET_EVENT_INFORMATION: /* File Access Services */ case SERVICE_CONFIRMED_ATOMIC_READ_FILE: case SERVICE_CONFIRMED_ATOMIC_WRITE_FILE: /* Object Access Services */ case SERVICE_CONFIRMED_CREATE_OBJECT: case SERVICE_CONFIRMED_READ_PROPERTY: case SERVICE_CONFIRMED_READ_PROP_CONDITIONAL: case SERVICE_CONFIRMED_READ_PROP_MULTIPLE: case SERVICE_CONFIRMED_READ_RANGE: case SERVICE_CONFIRMED_PRIVATE_TRANSFER: /* Virtual Terminal Services */ case SERVICE_CONFIRMED_VT_OPEN: case SERVICE_CONFIRMED_VT_DATA: /* Security Services */ case SERVICE_CONFIRMED_AUTHENTICATE: if (Confirmed_ACK_Function[service_choice] != NULL) { // (Confirmed_ACK_Function[service_choice]) // (service_request, service_request_len/*, src, // &service_ack_data*/); // tbd: chelsea } // tsm_free_invoke_id(invoke_id); break; default: break; } break; case PDU_TYPE_SEGMENT_ACK: /* FIXME: what about a denial of service attack here? we could check src to see if that matched the tsm */ // tsm_free_invoke_id(invoke_id); break; case PDU_TYPE_ERROR: // invoke_id = apdu[1]; service_choice = apdu[2]; len = 3; /* FIXME: Currently special case for C_P_T but there are others which may need consideration such as ChangeList-Error, CreateObject-Error, WritePropertyMultiple-Error and VTClose_Error but they may be left as is for now until support for these services is added */ if (service_choice == SERVICE_CONFIRMED_PRIVATE_TRANSFER) { /* skip over opening tag 0 */ if (decode_is_opening_tag_number(&apdu[len], 0)) { len++; /* a tag number of 0 is not extended so only one octet */ } } len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); /* FIXME: we could validate that the tag is enumerated... */ len += decode_enumerated(&apdu[len], len_value, &error_class); len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); /* FIXME: we could validate that the tag is enumerated... */ len += decode_enumerated(&apdu[len], len_value, &error_code); if (service_choice == SERVICE_CONFIRMED_PRIVATE_TRANSFER) { /* skip over closing tag 0 */ if (decode_is_closing_tag_number(&apdu[len], 0)) { len++; /* a tag number of 0 is not extended so only one octet */ } } if (service_choice < MAX_BACNET_CONFIRMED_SERVICE) { // if (Error_Function[service_choice]) // Error_Function[service_choice] (src, invoke_id/*, // (BACNET_ERROR_CLASS) error_class, // (BACNET_ERROR_CODE) error_code*/); // tbd: chelsea } // tsm_free_invoke_id(invoke_id); break; case PDU_TYPE_REJECT: // invoke_id = apdu[1]; // reason = apdu[2]; // if (Reject_Function) // Reject_Function(src, invoke_id, reason); // tsm_free_invoke_id(invoke_id); break; case PDU_TYPE_ABORT: // server = apdu[0] & 0x01; // invoke_id = apdu[1]; // reason = apdu[2]; // if (Abort_Function) // Abort_Function(src, invoke_id, reason, server); // tsm_free_invoke_id(invoke_id); break; default: break; } memset(Handler_Transmit_Buffer,0,MAX_PDU); //printf("apdu_done\r\n"); } return; }