client->meat.fd = fd;
client->meat.serial_number_set = false;
+ client->meat.rtr_version_set = false;
client->meat.addr = addr;
client->meat.tid = tid;
int result;
result = -ENOENT;
- rwlock_write_lock(&lock);
+ rwlock_read_lock(&lock);
HASH_FIND_INT(db.clients, &fd, client);
if (client != NULL) {
return retval;
}
+int
+clients_set_rtr_version(int fd, uint8_t rtr_version)
+{
+ struct hashable_client *client;
+ int result;
+
+ result = -ENOENT;
+ rwlock_write_lock(&lock);
+
+ HASH_FIND_INT(db.clients, &fd, client);
+ if (client == NULL)
+ goto unlock;
+
+ if (client->meat.rtr_version_set) {
+ result = -EINVAL; /* Can't be modified */
+ goto unlock;
+ }
+
+ client->meat.rtr_version = rtr_version;
+ client->meat.rtr_version_set = true;
+ result = 0;
+unlock:
+ rwlock_unlock(&lock);
+
+ return result;
+}
+
+int
+clients_get_rtr_version_set(int fd, bool *is_set, uint8_t *rtr_version)
+{
+ struct hashable_client *client;
+ int result;
+
+ result = -ENOENT;
+ rwlock_read_lock(&lock);
+
+ HASH_FIND_INT(db.clients, &fd, client);
+ if (client != NULL) {
+ (*is_set) = client->meat.rtr_version_set;
+ (*rtr_version) = client->meat.rtr_version;
+ result = 0;
+ }
+
+ rwlock_unlock(&lock);
+
+ return result;
+}
+
void
clients_forget(int fd)
{
serial_t serial_number;
bool serial_number_set;
+
+ uint8_t rtr_version;
+ bool rtr_version_set;
};
int clients_db_init(void);
int clients_get_min_serial(serial_t *);
int clients_get_addr(int, struct sockaddr_storage *);
+int clients_set_rtr_version(int, uint8_t);
+int clients_get_rtr_version_set(int, bool *, uint8_t *);
+
typedef int (*join_thread_cb)(pthread_t, void *);
void clients_db_destroy(join_thread_cb, void *);
int error;
/* Send Serial Notify PDU */
- error = send_serial_notify_pdu(client->fd, *serial);
+ error = send_serial_notify_pdu(client->fd, client->rtr_version,
+ *serial);
/* Error? Log it... */
if (error)
} rtr_error_code_t;
static int
-err_pdu_send(int fd, rtr_error_code_t code, struct rtr_request const *request,
- char const *message_const)
+err_pdu_send(int fd, uint8_t version, rtr_error_code_t code,
+ struct rtr_request const *request, char const *message_const)
{
char *message;
/* Need a clone to remove the const. */
message = (message_const != NULL) ? strdup(message_const) : NULL;
- send_error_report_pdu(fd, code, request, message);
+ send_error_report_pdu(fd, version, code, request, message);
free(message);
return -EINVAL;
}
int
-err_pdu_send_corrupt_data(int fd, struct rtr_request const *request,
- char const *message)
+err_pdu_send_corrupt_data(int fd, uint8_t version,
+ struct rtr_request const *request, char const *message)
{
- return err_pdu_send(fd, ERR_PDU_CORRUPT_DATA, request, message);
+ return err_pdu_send(fd, version, ERR_PDU_CORRUPT_DATA, request,
+ message);
}
/*
* problem.
*/
int
-err_pdu_send_internal_error(int fd)
+err_pdu_send_internal_error(int fd, uint8_t version)
{
- return err_pdu_send(fd, ERR_PDU_INTERNAL_ERROR, NULL, NULL);
+ return err_pdu_send(fd, version, ERR_PDU_INTERNAL_ERROR, NULL, NULL);
}
int
-err_pdu_send_no_data_available(int fd)
+err_pdu_send_no_data_available(int fd, uint8_t version)
{
- err_pdu_send(fd, ERR_PDU_NO_DATA_AVAILABLE, NULL, NULL);
+ err_pdu_send(fd, version, ERR_PDU_NO_DATA_AVAILABLE, NULL, NULL);
/*
* The connection should not be terminated because of this error.
* So don't panic; client should retry later.
}
int
-err_pdu_send_invalid_request(int fd, struct rtr_request const *request,
- char const *message)
+err_pdu_send_invalid_request(int fd, uint8_t version,
+ struct rtr_request const *request, char const *message)
{
- return err_pdu_send(fd, ERR_PDU_INVALID_REQUEST, request, message);
+ return err_pdu_send(fd, version, ERR_PDU_INVALID_REQUEST, request,
+ message);
}
/* Caution: @header is supposed to be in serialized form. */
int
-err_pdu_send_invalid_request_truncated(int fd, unsigned char *header,
- char const *message)
+err_pdu_send_invalid_request_truncated(int fd, uint8_t version,
+ unsigned char *header, char const *message)
{
struct rtr_request request = {
.bytes = header,
.bytes_len = RTRPDU_HDR_LEN,
.pdu = NULL,
};
- return err_pdu_send_invalid_request(fd, &request, message);
+ return err_pdu_send_invalid_request(fd, version, &request, message);
}
int
-err_pdu_send_unsupported_proto_version(int fd, unsigned char *header,
+err_pdu_send_unsupported_proto_version(int fd, uint8_t version,
+ unsigned char *header,
char const *message)
{
struct rtr_request request = {
.bytes_len = RTRPDU_HDR_LEN,
.pdu = NULL,
};
- return err_pdu_send(fd, ERR_PDU_UNSUP_PROTO_VERSION, &request, message);
+ return err_pdu_send(fd, version, ERR_PDU_UNSUP_PROTO_VERSION, &request,
+ message);
+}
+
+int
+err_pdu_send_unsupported_pdu_type(int fd, uint8_t version,
+ struct rtr_request const *request)
+{
+ return err_pdu_send(fd, version, ERR_PDU_UNSUP_PDU_TYPE, request, NULL);
}
int
-err_pdu_send_unsupported_pdu_type(int fd, struct rtr_request const *request)
+err_pdu_send_unexpected_proto_version(int fd, uint8_t version,
+ unsigned char *header, char const *message)
{
- return err_pdu_send(fd, ERR_PDU_UNSUP_PDU_TYPE, request, NULL);
+ struct rtr_request request = {
+ .bytes = header,
+ .bytes_len = RTRPDU_HDR_LEN,
+ .pdu = NULL,
+ };
+ return err_pdu_send(fd, version, ERR_PDU_UNEXPECTED_PROTO_VERSION, &request,
+ message);
}
char const *
* Mainly, this is for the sake of making it easier to see whether the error is
* supposed to contain a message and/or the original PDU or not.
*/
-int err_pdu_send_corrupt_data(int, struct rtr_request const *, char const *);
-int err_pdu_send_internal_error(int);
-int err_pdu_send_no_data_available(int);
-int err_pdu_send_invalid_request(int, struct rtr_request const *, char const *);
-int err_pdu_send_invalid_request_truncated(int, unsigned char *, char const *);
-int err_pdu_send_unsupported_proto_version(int, unsigned char *, char const *);
-int err_pdu_send_unsupported_pdu_type(int, struct rtr_request const *);
+int err_pdu_send_corrupt_data(int, uint8_t, struct rtr_request const *,
+ char const *);
+int err_pdu_send_internal_error(int, uint8_t);
+int err_pdu_send_no_data_available(int, uint8_t);
+int err_pdu_send_invalid_request(int, uint8_t, struct rtr_request const *,
+ char const *);
+int err_pdu_send_invalid_request_truncated(int, uint8_t, unsigned char *,
+ char const *);
+int err_pdu_send_unsupported_proto_version(int, uint8_t, unsigned char *,
+ char const *);
+int err_pdu_send_unsupported_pdu_type(int, uint8_t, struct rtr_request const *);
+int err_pdu_send_unexpected_proto_version(int, uint8_t, unsigned char *,
+ char const *);
char const *err_pdu_to_string(uint16_t);
#include <stdlib.h>
#include <string.h>
+#include "clients.h"
#include "common.h"
#include "log.h"
#include "rtr/err_pdu.h"
#define RESPOND_ERROR(report_cb) \
((header.pdu_type != PDU_TYPE_ERROR_REPORT) ? (report_cb) : -EINVAL);
+static int
+validate_rtr_version(int fd, struct pdu_header *header,
+ unsigned char *hdr_bytes)
+{
+ uint8_t curr_version;
+ bool version_set;
+ int error;
+
+ error = clients_get_rtr_version_set(fd, &version_set, &curr_version);
+ if (error)
+ /* Unlikely, but close connection with min version */
+ return (header->pdu_type != PDU_TYPE_ERROR_REPORT) ?
+ err_pdu_send_internal_error(fd, RTR_V0) : -EINVAL;
+
+ if (version_set) {
+ if (header->protocol_version == curr_version)
+ return 0;
+
+ /* Don't send error on a rcvd error! */
+ if (header->pdu_type == PDU_TYPE_ERROR_REPORT)
+ return -EINVAL;
+
+ switch(curr_version) {
+ case RTR_V1:
+ /* Rcvd version is valid, but unexpected */
+ if (header->protocol_version == RTR_V0)
+ return err_pdu_send_unexpected_proto_version(
+ fd, curr_version, hdr_bytes,
+ "RTR version 0 was expected");
+ /* Send common error */
+ case RTR_V0:
+ return err_pdu_send_unsupported_proto_version(fd,
+ curr_version, hdr_bytes,
+ "RTR version received is unknown.");
+ default:
+ pr_crit("Unknown RTR version %u", curr_version);
+ break;
+ }
+ }
+
+ /* Unsigned and incremental values, so compare against major version */
+ if (header->protocol_version > RTR_V1)
+ /* ...and send error with min version */
+ return (header->pdu_type != PDU_TYPE_ERROR_REPORT) ?
+ err_pdu_send_unsupported_proto_version(fd, RTR_V0,
+ hdr_bytes, "RTR version received is unknown.")
+ : -EINVAL;
+
+ return clients_set_rtr_version(fd, header->protocol_version);
+}
+
int
pdu_load(int fd, struct rtr_request *request,
struct pdu_metadata const **metadata)
struct pdu_reader reader;
struct pdu_header header;
struct pdu_metadata const *meta;
+ uint8_t version;
int error;
/* Read the header into its buffer. */
/* No error response because the PDU might have been an error */
return error;
+ error = validate_rtr_version(fd, &header, hdr_bytes);
+ if (error)
+ return error; /* Error response PDU already sent */
+
+ /* RTR version ok, keep it for later use */
+ version = header.protocol_version;
+
/*
* DO NOT USE THE err_pdu_* functions directly. Wrap them with
* RESPOND_ERROR() INSTEAD.
*/
-
- /*
- * For now, only RTRv0 is supported
- */
- if (header.protocol_version != RTR_V0)
- return RESPOND_ERROR(err_pdu_send_unsupported_proto_version(fd,
- hdr_bytes, "This server only supports RTRv0."));
-
if (header.length < RTRPDU_HDR_LEN)
return RESPOND_ERROR(err_pdu_send_invalid_request_truncated(fd,
- hdr_bytes, "Invalid header length. (< 8 bytes)"));
+ version, hdr_bytes, "Invalid header length. (< 8 bytes)"));
/*
* Error messages can be quite large.
*/
if (header.length > 512)
return RESPOND_ERROR(err_pdu_send_invalid_request_truncated(fd,
- hdr_bytes, "PDU is too large. (> 512 bytes)"));
+ version, hdr_bytes, "PDU is too large. (> 512 bytes)"));
/* Read the rest of the PDU into its buffer. */
request->bytes_len = header.length;
meta = pdu_get_metadata(header.pdu_type);
if (!meta) {
error = RESPOND_ERROR(err_pdu_send_unsupported_pdu_type(fd,
- request));
+ version, request));
goto revert_bytes;
}
error = meta->from_stream(&header, &reader, request->pdu);
if (reader.size != 0) {
- error = RESPOND_ERROR(err_pdu_send_invalid_request(fd,
+ error = RESPOND_ERROR(err_pdu_send_invalid_request(fd, version,
request,
"The PDU length sent doesn't match the real PDU length"));
goto revert_pdu;
}
if (error) {
- RESPOND_ERROR(err_pdu_send_internal_error(fd));
+ RESPOND_ERROR(err_pdu_send_internal_error(fd, version));
goto revert_pdu;
}
#define RTRPDU_CACHE_RESPONSE_LEN 8
#define RTRPDU_IPV4_PREFIX_LEN 20
#define RTRPDU_IPV6_PREFIX_LEN 32
-#define RTRPDU_END_OF_DATA_LEN 12
+#define RTRPDU_END_OF_DATA_V0_LEN 12
+#define RTRPDU_END_OF_DATA_V1_LEN 24
#define RTRPDU_CACHE_RESET_LEN 8
/* Ignores Error Report PDUs, which is fine. */
#include "pdu_sender.h"
#include "rtr/db/vrps.h"
-#define warn_unexpected_pdu(fd, request, pdu_name) \
- err_pdu_send_invalid_request(fd, request, \
- "Clients are not supposed to send " pdu_name " PDUs.");
+#define WARN_UNEXPECTED_PDU(name, fd, request, pdu_name) \
+ struct name##_pdu *pdu = request->pdu; \
+ return err_pdu_send_invalid_request(fd, \
+ pdu->header.protocol_version, \
+ request, "Clients are not supposed to send " pdu_name " PDUs.");
int
handle_serial_notify_pdu(int fd, struct rtr_request const *request)
{
- return warn_unexpected_pdu(fd, request, "Serial Notify");
+ WARN_UNEXPECTED_PDU(serial_notify, fd, request, "Serial Notify");
}
int
struct serial_query_pdu *query = request->pdu;
struct deltas_db deltas;
serial_t final_serial;
+ uint8_t version;
int error;
/*
* the mismatch MUST immediately terminate the session with an Error
* Report PDU with code 0 ("Corrupt Data")"
*/
- if (query->header.m.session_id != get_current_session_id(RTR_V0))
- return err_pdu_send_corrupt_data(fd, request,
+ version = query->header.protocol_version;
+ if (query->header.m.session_id !=
+ get_current_session_id(version))
+ return err_pdu_send_corrupt_data(fd, version, request,
"Session ID doesn't match.");
/*
case 0:
break;
case -EAGAIN: /* Database still under construction */
- error = err_pdu_send_no_data_available(fd);
+ error = err_pdu_send_no_data_available(fd, version);
goto end;
case -ESRCH: /* Invalid serial */
/* https://tools.ietf.org/html/rfc6810#section-6.3 */
- error = send_cache_reset_pdu(fd);
+ error = send_cache_reset_pdu(fd, version);
goto end;
case -ENOMEM: /* Memory allocation failure */
goto end;
* RTR does not provide a code for that. Just fall through.
*/
default:
- error = err_pdu_send_internal_error(fd);
+ error = err_pdu_send_internal_error(fd, version);
goto end;
}
* programming errors. Best avoid error PDUs.
*/
- error = send_cache_response_pdu(fd);
+ error = send_cache_response_pdu(fd, version);
if (error)
goto end;
- error = send_delta_pdus(fd, &deltas);
+ error = send_delta_pdus(fd, version, &deltas);
if (error)
goto end;
- error = send_end_of_data_pdu(fd, final_serial);
+ error = send_end_of_data_pdu(fd, version, final_serial);
end:
deltas_db_cleanup(&deltas, deltagroup_cleanup);
struct base_roa_args {
bool started;
int fd;
+ uint8_t version;
};
static int
int error;
if (!args->started) {
- error = send_cache_response_pdu(args->fd);
+ error = send_cache_response_pdu(args->fd, args->version);
if (error)
return error;
args->started = true;
}
- return send_prefix_pdu(args->fd, vrp, FLAG_ANNOUNCEMENT);
+ return send_prefix_pdu(args->fd, args->version, vrp, FLAG_ANNOUNCEMENT);
}
int
handle_reset_query_pdu(int fd, struct rtr_request const *request)
{
+ struct reset_query_pdu *pdu = request->pdu;
struct base_roa_args args;
serial_t current_serial;
int error;
args.started = false;
args.fd = fd;
+ args.version = pdu->header.protocol_version;
error = get_last_serial_number(¤t_serial);
switch (error) {
case 0:
break;
case -EAGAIN:
- return err_pdu_send_no_data_available(fd);
+ return err_pdu_send_no_data_available(fd, args.version);
default:
- err_pdu_send_internal_error(fd);
+ err_pdu_send_internal_error(fd, args.version);
return error;
}
case 0:
break;
case -EAGAIN:
- return err_pdu_send_no_data_available(fd);
+ return err_pdu_send_no_data_available(fd, args.version);
case EAGAIN:
- err_pdu_send_internal_error(fd);
+ err_pdu_send_internal_error(fd, args.version);
return error;
}
- return send_end_of_data_pdu(fd, current_serial);
+ return send_end_of_data_pdu(fd, args.version, current_serial);
}
int
handle_cache_response_pdu(int fd, struct rtr_request const *request)
{
- return warn_unexpected_pdu(fd, request, "Cache Response");
+ WARN_UNEXPECTED_PDU(cache_response, fd, request, "Cache Response");
}
int
handle_ipv4_prefix_pdu(int fd, struct rtr_request const *request)
{
- return warn_unexpected_pdu(fd, request, "IPv4 Prefix");
+ WARN_UNEXPECTED_PDU(ipv4_prefix, fd, request, "IPv4 Prefix");
}
int
handle_ipv6_prefix_pdu(int fd, struct rtr_request const *request)
{
- return warn_unexpected_pdu(fd, request, "IPv6 Prefix");
+ WARN_UNEXPECTED_PDU(ipv6_prefix, fd, request, "IPv6 Prefix");
}
int
handle_end_of_data_pdu(int fd, struct rtr_request const *request)
{
- return warn_unexpected_pdu(fd, request, "End of Data");
+ WARN_UNEXPECTED_PDU(end_of_data, fd, request, "End of Data");
}
int
handle_cache_reset_pdu(int fd, struct rtr_request const *request)
{
- return warn_unexpected_pdu(fd, request, "Cache Reset");
+ WARN_UNEXPECTED_PDU(cache_reset, fd, request, "Cache Reset");
}
int
handle_router_key_pdu(int fd, struct rtr_request const *request)
{
- return warn_unexpected_pdu(fd, request, "Router Key");
+ WARN_UNEXPECTED_PDU(router_key, fd, request, "Router Key");
}
int
* Set all the header values, EXCEPT length field.
*/
static void
-set_header_values(struct pdu_header *header, uint8_t type, uint16_t reserved)
+set_header_values(struct pdu_header *header, uint8_t version, uint8_t type,
+ uint16_t reserved)
{
- /* FIXME Remove to support RTR_V1 */
- header->protocol_version = RTR_V0;
+ header->protocol_version = version;
header->pdu_type = type;
header->m.reserved = reserved;
}
}
int
-send_serial_notify_pdu(int fd, serial_t start_serial)
+send_serial_notify_pdu(int fd, uint8_t version, serial_t start_serial)
{
struct serial_notify_pdu pdu;
unsigned char data[RTRPDU_SERIAL_NOTIFY_LEN];
size_t len;
- set_header_values(&pdu.header, PDU_TYPE_SERIAL_NOTIFY,
- get_current_session_id(RTR_V0));
+ set_header_values(&pdu.header, version, PDU_TYPE_SERIAL_NOTIFY,
+ get_current_session_id(version));
pdu.serial_number = start_serial;
pdu.header.length = RTRPDU_SERIAL_NOTIFY_LEN;
}
int
-send_cache_reset_pdu(int fd)
+send_cache_reset_pdu(int fd, uint8_t version)
{
struct cache_reset_pdu pdu;
unsigned char data[RTRPDU_CACHE_RESET_LEN];
size_t len;
/* This PDU has only the header */
- set_header_values(&pdu.header, PDU_TYPE_CACHE_RESET, 0);
+ set_header_values(&pdu.header, version, PDU_TYPE_CACHE_RESET, 0);
pdu.header.length = RTRPDU_CACHE_RESET_LEN;
len = serialize_cache_reset_pdu(&pdu, data);
}
int
-send_cache_response_pdu(int fd)
+send_cache_response_pdu(int fd, uint8_t version)
{
struct cache_response_pdu pdu;
unsigned char data[RTRPDU_CACHE_RESPONSE_LEN];
size_t len;
/* This PDU has only the header */
- set_header_values(&pdu.header, PDU_TYPE_CACHE_RESPONSE,
- get_current_session_id(RTR_V0));
+ set_header_values(&pdu.header, version, PDU_TYPE_CACHE_RESPONSE,
+ get_current_session_id(version));
pdu.header.length = RTRPDU_CACHE_RESPONSE_LEN;
len = serialize_cache_response_pdu(&pdu, data);
}
static int
-send_ipv4_prefix_pdu(int fd, struct vrp const *vrp, uint8_t flags)
+send_ipv4_prefix_pdu(int fd, uint8_t version, struct vrp const *vrp,
+ uint8_t flags)
{
struct ipv4_prefix_pdu pdu;
unsigned char data[RTRPDU_IPV4_PREFIX_LEN];
size_t len;
- set_header_values(&pdu.header, PDU_TYPE_IPV4_PREFIX, 0);
+ set_header_values(&pdu.header, version, PDU_TYPE_IPV4_PREFIX, 0);
pdu.header.length = RTRPDU_IPV4_PREFIX_LEN;
pdu.flags = flags;
}
static int
-send_ipv6_prefix_pdu(int fd, struct vrp const *vrp, uint8_t flags)
+send_ipv6_prefix_pdu(int fd, uint8_t version, struct vrp const *vrp,
+ uint8_t flags)
{
struct ipv6_prefix_pdu pdu;
unsigned char data[RTRPDU_IPV6_PREFIX_LEN];
size_t len;
- set_header_values(&pdu.header, PDU_TYPE_IPV6_PREFIX, 0);
+ set_header_values(&pdu.header, version, PDU_TYPE_IPV6_PREFIX, 0);
pdu.header.length = RTRPDU_IPV6_PREFIX_LEN;
pdu.flags = flags;
}
int
-send_prefix_pdu(int fd, struct vrp const *vrp, uint8_t flags)
+send_prefix_pdu(int fd, uint8_t version, struct vrp const *vrp, uint8_t flags)
{
switch (vrp->addr_fam) {
case AF_INET:
- return send_ipv4_prefix_pdu(fd, vrp, flags);
+ return send_ipv4_prefix_pdu(fd, version, vrp, flags);
case AF_INET6:
- return send_ipv6_prefix_pdu(fd, vrp, flags);
+ return send_ipv6_prefix_pdu(fd, version, vrp, flags);
}
return -EINVAL;
}
int
-send_router_key_pdu(int fd, struct router_key const *router_key, uint8_t flags)
+send_router_key_pdu(int fd, uint8_t version,
+ struct router_key const *router_key, uint8_t flags)
{
struct router_key_pdu pdu;
unsigned char *data;
uint16_t reserved;
int error;
- /* TODO Sanity check: this can't be sent on RTRv0 */
+ /* Sanity check: this can't be sent on RTRv0 */
+ if (version == RTR_V0)
+ return 0;
reserved = 0;
/* Set the flags at the first 8 bits of reserved field */
reserved += (flags << 8);
- set_header_values(&pdu.header, PDU_TYPE_ROUTER_KEY, reserved);
+ set_header_values(&pdu.header, version, PDU_TYPE_ROUTER_KEY, reserved);
pdu.ski = sk_info_get_ski(router_key->sk);
pdu.ski_len = RK_SKI_LEN;
return error;
}
+struct simple_param {
+ int fd;
+ uint8_t version;
+};
+
static int
vrp_simply_send(struct delta_vrp const *delta, void *arg)
{
- int *fd = arg;
+ struct simple_param *param = arg;
- return send_prefix_pdu(*fd, &delta->vrp, delta->flags);
+ return send_prefix_pdu(param->fd, param->version, &delta->vrp,
+ delta->flags);
}
static int
router_key_simply_send(struct delta_bgpsec const *delta, void *arg)
{
- int *fd = arg;
+ struct simple_param *param = arg;
- return send_router_key_pdu(*fd, &delta->router_key,
- delta->flags);
+ return send_router_key_pdu(param->fd, param->version,
+ &delta->router_key, delta->flags);
}
int
-send_delta_pdus(int fd, struct deltas_db *deltas)
+send_delta_pdus(int fd, uint8_t version, struct deltas_db *deltas)
{
struct delta_group *group;
+ struct simple_param param;
+
+ param.fd = fd;
+ param.version = version;
/*
* Short circuit: Entries that share serial are already guaranteed to
if (deltas->len == 1) {
group = &deltas->array[0];
return deltas_foreach(group->serial, group->deltas,
- vrp_simply_send, router_key_simply_send, &fd);
+ vrp_simply_send, router_key_simply_send, ¶m);
}
/* FIXME Apply to router keys as well */
- return vrps_foreach_filtered_delta(deltas, vrp_simply_send, &fd);
+ return vrps_foreach_filtered_delta(deltas, vrp_simply_send, ¶m);
}
+#define GET_END_OF_DATA_LENGTH(version) \
+ ((version == RTR_V1) ? \
+ RTRPDU_END_OF_DATA_V1_LEN : RTRPDU_END_OF_DATA_V0_LEN)
+
int
-send_end_of_data_pdu(int fd, serial_t end_serial)
+send_end_of_data_pdu(int fd, uint8_t version, serial_t end_serial)
{
struct end_of_data_pdu pdu;
- unsigned char data[RTRPDU_END_OF_DATA_LEN];
+ unsigned char data[GET_END_OF_DATA_LENGTH(version)];
size_t len;
int error;
- set_header_values(&pdu.header, PDU_TYPE_END_OF_DATA,
- get_current_session_id(RTR_V0));
- pdu.header.length = RTRPDU_END_OF_DATA_LEN;
+ set_header_values(&pdu.header, version, PDU_TYPE_END_OF_DATA,
+ get_current_session_id(version));
+ pdu.header.length = GET_END_OF_DATA_LENGTH(version);
pdu.serial_number = end_serial;
- /* FIXME WRONG!! Check for the real version */
- if (pdu.header.protocol_version == RTR_V1) {
+ if (version == RTR_V1) {
pdu.refresh_interval = config_get_interval_refresh();
pdu.retry_interval = config_get_interval_retry();
pdu.expire_interval = config_get_interval_expire();
}
len = serialize_end_of_data_pdu(&pdu, data);
- if (len != RTRPDU_END_OF_DATA_LEN)
+ if (len != GET_END_OF_DATA_LENGTH(version))
pr_crit("Serialized End of Data is %zu bytes.", len);
error = send_response(fd, data, len);
}
int
-send_error_report_pdu(int fd, uint16_t code, struct rtr_request const *request,
- char *message)
+send_error_report_pdu(int fd, uint8_t version, uint16_t code,
+ struct rtr_request const *request, char *message)
{
struct error_report_pdu pdu;
unsigned char *data;
size_t len;
int error;
- set_header_values(&pdu.header, PDU_TYPE_ERROR_REPORT, code);
+ set_header_values(&pdu.header, version, PDU_TYPE_ERROR_REPORT, code);
if (request != NULL) {
pdu.error_pdu_length = (request->bytes_len > RTRPDU_MAX_LEN)
#include "object/router_key.h"
#include "rtr/db/vrps.h"
-void init_sender_common(int, int, uint8_t);
-
-int send_serial_notify_pdu(int, serial_t);
-int send_cache_reset_pdu(int);
-int send_cache_response_pdu(int);
-int send_prefix_pdu(int, struct vrp const *, uint8_t);
-int send_router_key_pdu(int, struct router_key const *, uint8_t);
-int send_delta_pdus(int, struct deltas_db *);
-int send_end_of_data_pdu(int, serial_t);
-int send_error_report_pdu(int, uint16_t, struct rtr_request const *, char *);
+int send_serial_notify_pdu(int, uint8_t, serial_t);
+int send_cache_reset_pdu(int, uint8_t);
+int send_cache_response_pdu(int, uint8_t);
+int send_prefix_pdu(int, uint8_t, struct vrp const *, uint8_t);
+int send_router_key_pdu(int, uint8_t, struct router_key const *, uint8_t);
+int send_delta_pdus(int, uint8_t, struct deltas_db *);
+int send_end_of_data_pdu(int, uint8_t, serial_t);
+int send_error_report_pdu(int, uint8_t, uint16_t, struct rtr_request const *,
+ char *);
#endif /* SRC_RTR_PDU_SENDER_H_ */
error = pthread_create(¶m->tid, NULL,
client_thread_cb, param);
if (error && error != EAGAIN)
- err_pdu_send_internal_error(client_fd);
+ /* Error with min RTR version */
+ err_pdu_send_internal_error(client_fd, RTR_V0);
if (error) {
pr_errno(error, "Could not spawn the client's thread");
close(client_fd);