From: pcarana Date: Thu, 28 Feb 2019 14:33:33 +0000 (-0600) Subject: Implement error report PDU and send when no data is available X-Git-Tag: v0.0.2~52^2~52 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4b295c080c66e73bf5760198ade1a2ef6becc02c;p=thirdparty%2FFORT-validator.git Implement error report PDU and send when no data is available --- diff --git a/src/rtr/pdu.h b/src/rtr/pdu.h index 4e5fe921..95f288cf 100644 --- a/src/rtr/pdu.h +++ b/src/rtr/pdu.h @@ -9,11 +9,22 @@ #define RTR_V0 0 #define RTR_V1 1 -#define CACHE_RESPONSE_PDU_TYPE 3 -#define IPV4_PREFIX_PDU_TYPE 4 -#define IPV6_PREFIX_PDU_TYPE 6 -#define END_OF_DATA_PDU_TYPE 7 -#define CACHE_RESET_PDU_TYPE 8 +#define PDU_TYPE_CACHE_RESPONSE 3 +#define PDU_TYPE_IPV4_PREFIX 4 +#define PDU_TYPE_IPV6_PREFIX 6 +#define PDU_TYPE_END_OF_DATA 7 +#define PDU_TYPE_CACHE_RESET 8 +#define PDU_TYPE_ERROR_REPORT 10 + +#define ERR_CORRUPT_DATA 0 +#define ERR_INTERNAL_ERROR 1 +#define ERR_NO_DATA_AVAILABLE 2 +#define ERR_INVALID_REQUEST 3 +#define ERR_UNSUP_PROTO_VERSION 4 +#define ERR_UNSUP_PDU_TYPE 5 +#define ERR_WITHDRAWAL_UNKNOWN 6 +#define ERR_DUPLICATE_ANNOUNCE 7 +#define UNEXPECTED_PROTO_VERSION 8 struct pdu_header { u_int8_t protocol_version; @@ -78,7 +89,9 @@ struct cache_reset_pdu { struct error_report_pdu { struct pdu_header header; - void *erroneous_pdu; + u_int32_t error_pdu_length; + void *erroneous_pdu; + u_int32_t error_message_length; rtr_char *error_message; }; diff --git a/src/rtr/pdu_handler.c b/src/rtr/pdu_handler.c index f34aa29b..0fec38e1 100644 --- a/src/rtr/pdu_handler.c +++ b/src/rtr/pdu_handler.c @@ -59,10 +59,9 @@ handle_serial_query_pdu(int fd, void *pdu) updates = deltas_db_status(common.start_serial); switch (updates) { - /* TODO Implement error */ -// case NO_DATA_AVAILABLE: + case NO_DATA_AVAILABLE: /* https://tools.ietf.org/html/rfc8210#section-8.4 */ -// return send_error_pdu; + return send_error_report_pdu(&common, ERR_NO_DATA_AVAILABLE, NULL, NULL); case DIFF_UNDETERMINED: /* https://tools.ietf.org/html/rfc8210#section-8.3 */ return send_cache_reset_pdu(&common); @@ -99,10 +98,9 @@ handle_reset_query_pdu(int fd, void *pdu) updates = deltas_db_status(common.start_serial); switch (updates) { - /* TODO Implement error */ -// case NO_DATA_AVAILABLE: + case NO_DATA_AVAILABLE: /* https://tools.ietf.org/html/rfc8210#section-8.4 */ -// return send_error_pdu; + return send_error_report_pdu(&common, ERR_NO_DATA_AVAILABLE, NULL, NULL); case DIFF_AVAILABLE: /* https://tools.ietf.org/html/rfc8210#section-8.1 */ return send_commmon_exchange(&common); diff --git a/src/rtr/pdu_sender.c b/src/rtr/pdu_sender.c index b6e385af..d7163509 100644 --- a/src/rtr/pdu_sender.c +++ b/src/rtr/pdu_sender.c @@ -61,6 +61,14 @@ length_end_of_data_pdu(struct end_of_data_pdu *pdu) return len; } +static u_int32_t +length_error_report_pdu(struct error_report_pdu *pdu) +{ + return HEADER_LENGTH + + pdu->error_pdu_length + sizeof(pdu->error_pdu_length) + + pdu->error_message_length + sizeof(pdu->error_message_length); +} + static int send_response(int fd, char *data, size_t data_len) { @@ -96,7 +104,7 @@ send_cache_reset_pdu(struct sender_common *common) size_t len; /* This PDU has only the header */ - set_header_values(&pdu.header, common->version, CACHE_RESET_PDU_TYPE, 0); + set_header_values(&pdu.header, common->version, PDU_TYPE_CACHE_RESET, 0); pdu.header.length = HEADER_LENGTH; len = serialize_cache_reset_pdu(&pdu, data); @@ -111,8 +119,8 @@ send_cache_response_pdu(struct sender_common *common) size_t len; /* This PDU has only the header */ - set_header_values(&pdu.header, common->version, - CACHE_RESPONSE_PDU_TYPE, *common->session_id); + set_header_values(&pdu.header, common->version, PDU_TYPE_CACHE_RESPONSE, + *common->session_id); pdu.header.length = HEADER_LENGTH; len = serialize_cache_response_pdu(&pdu, data); @@ -127,7 +135,7 @@ send_ipv4_prefix_pdu(struct sender_common *common, struct vrp *vrp) char data[BUFFER_SIZE]; size_t len; - set_header_values(&pdu.header, common->version, IPV4_PREFIX_PDU_TYPE, 0); + set_header_values(&pdu.header, common->version, PDU_TYPE_IPV4_PREFIX, 0); pdu.flags = vrp->flags; pdu.prefix_length = vrp->prefix_length; @@ -149,7 +157,7 @@ send_ipv6_prefix_pdu(struct sender_common *common, struct vrp *vrp) char data[BUFFER_SIZE]; size_t len; - set_header_values(&pdu.header, common->version, IPV6_PREFIX_PDU_TYPE, 0); + set_header_values(&pdu.header, common->version, PDU_TYPE_IPV6_PREFIX, 0); pdu.flags = vrp->flags; pdu.prefix_length = vrp->prefix_length; @@ -197,7 +205,8 @@ send_end_of_data_pdu(struct sender_common *common) char data[BUFFER_SIZE]; size_t len; - set_header_values(&pdu.header, common->version, END_OF_DATA_PDU_TYPE, *common->session_id); + set_header_values(&pdu.header, common->version, PDU_TYPE_END_OF_DATA, + *common->session_id); pdu.serial_number = *common->end_serial; if (common->version == RTR_V1) { pdu.refresh_interval = config_get_refresh_interval(); @@ -210,3 +219,42 @@ send_end_of_data_pdu(struct sender_common *common) return send_response(common->fd, data, len); } + +int +send_error_report_pdu(struct sender_common *common, u_int16_t code, + void *err_pdu, char *message) +{ + struct error_report_pdu pdu; + char data[BUFFER_SIZE]; + size_t len; + + set_header_values(&pdu.header, common->version, PDU_TYPE_ERROR_REPORT, + code); + if (err_pdu == NULL) { + pdu.error_pdu_length = 0; + pdu.erroneous_pdu = NULL; + } else { + /* TODO Really? Or get the PDU header length field */ + pdu.error_pdu_length = sizeof(*err_pdu); + pdu.erroneous_pdu = err_pdu; + } + if (message == NULL) { + pdu.error_message_length = 0; + pdu.error_message = NULL; + } else { + pdu.error_message = malloc(strlen(message) + 1); + if (pdu.error_message == NULL) { + warn("Error message couldn't be allocated, removed from PDU"); + pdu.error_message_length = 0; + } else { + pdu.error_message_length = strlen(message) + 1; + strcpy(pdu.error_message, message); + } + } + + /* Calculate lengths */ + pdu.header.length = length_error_report_pdu(&pdu); + + len = serialize_error_report_pdu(&pdu, data); + return send_response(common->fd, data, len); +} diff --git a/src/rtr/pdu_sender.h b/src/rtr/pdu_sender.h index d91bf40d..607eb2a4 100644 --- a/src/rtr/pdu_sender.h +++ b/src/rtr/pdu_sender.h @@ -18,6 +18,7 @@ int send_cache_reset_pdu(struct sender_common *); int send_cache_response_pdu(struct sender_common *); int send_payload_pdus(struct sender_common *); int send_end_of_data_pdu(struct sender_common *); +int send_error_report_pdu(struct sender_common *, u_int16_t, void *, char *); #endif /* SRC_RTR_PDU_SENDER_H_ */ diff --git a/src/rtr/pdu_serializer.c b/src/rtr/pdu_serializer.c index 4d6fe665..f35dac75 100644 --- a/src/rtr/pdu_serializer.c +++ b/src/rtr/pdu_serializer.c @@ -1,6 +1,7 @@ #include "pdu_serializer.h" #include +#include #include "primitive_writer.h" void @@ -112,6 +113,28 @@ serialize_cache_reset_pdu(struct cache_reset_pdu *pdu, char *buf) size_t serialize_error_report_pdu(struct error_report_pdu *pdu, char *buf) { - // FIXME Complete me! - return 0; + size_t head_size; + char *ptr, *tmp_ptr; + int i; + + head_size = serialize_pdu_header(&pdu->header, pdu->header.error_code, buf); + + ptr = buf + head_size; + + ptr = write_int32(ptr, pdu->error_pdu_length); + if (pdu->error_pdu_length > 0) { + tmp_ptr = pdu->erroneous_pdu; + /* TODO Set only the header of err PDU */ + while (*tmp_ptr != '\0') { + ptr = write_int8(ptr, *tmp_ptr); + tmp_ptr++; + } + } + + ptr = write_int32(ptr, pdu->error_message_length); + tmp_ptr = pdu->error_message; + for (i = 0; i < pdu->error_message_length; i++) + ptr = write_int8(ptr, tmp_ptr[i]); + + return ptr - buf; }