fr_client_t const *client;
fr_pair_t *vp, *reply, *my, *your;
bfd_wrapper_t const *wrapper = (bfd_wrapper_t const *) data;
- bfd_packet_t const *packet = (bfd_packet_t const *) wrapper->packet;
+ bfd_packet_t const *bfd = (bfd_packet_t const *) wrapper->packet;
/*
* Set the request dictionary so that we can do
/*
* Hacks for now until we have a lower-level decode routine.
*/
- request->packet->code = packet->state;
- request->packet->id = fr_nbo_to_uint32((uint8_t const *) &packet->my_disc);
+ request->packet->code = bfd->state;
+ request->packet->id = fr_nbo_to_uint32((uint8_t const *) &bfd->my_disc);
request->reply->id = request->packet->id;
request->packet->data = talloc_memdup(request->packet, data, data_len);
request->packet->data_len = data_len;
+ /*
+ * Set the rest of the fields.
+ */
+ request->client = UNCONST(fr_client_t *, client);
+
+ request->packet->socket = address->socket;
+ fr_socket_addr_swap(&request->reply->socket, &address->socket);
+
+ REQUEST_VERIFY(request);
+
+ /*
+ * Decode the packet into the reply.
+ */
+ if (wrapper->type == BFD_WRAPPER_SEND_PACKET) {
+ if (fr_bfd_decode(request->reply_ctx, &request->reply_pairs,
+ (uint8_t const *) bfd, bfd->length,
+ client->secret, talloc_array_length(client->secret) - 1) < 0) {
+ RPEDEBUG("Failed decoding packet");
+ return -1;
+ }
+
+ request->reply->code = bfd->state;
+
+ return 0;
+ }
+
/*
* Note that we don't set a limit on max_attributes here.
* That MUST be set and checked in the underlying
* transport, via a call to fr_radius_ok().
*/
if (fr_bfd_decode(request->request_ctx, &request->request_pairs,
- (uint8_t const *) packet, packet->length,
+ (uint8_t const *) bfd, bfd->length,
client->secret, talloc_array_length(client->secret) - 1) < 0) {
RPEDEBUG("Failed decoding packet");
return -1;
}
- /*
- * Set the rest of the fields.
- */
- request->client = UNCONST(fr_client_t *, client);
-
- request->packet->socket = address->socket;
- fr_socket_addr_swap(&request->reply->socket, &address->socket);
-
- REQUEST_VERIFY(request);
-
/*
* Initialize the reply.
*/
fr_io_address_t const *address = track->address;
fr_client_t const *client;
bfd_wrapper_t const *wrapper = (bfd_wrapper_t const *) request->packet->data;
+ bfd_packet_t const *bfd = (bfd_packet_t const *) wrapper->packet;
/*
* Process layer NAK, or "Do not respond".
return sizeof(new_client);
}
+ fr_assert((wrapper->packet + bfd->length) == (request->packet->data + request->packet->data_len));
+
/*
- * @todo - change our state based on the reply packet.
+ * Don't bother re-encoding the packet.
*/
- *buffer = 0x00;
- return 1;
+ memcpy(buffer, bfd, bfd->length);
+
+ fr_assert(fr_bfd_packet_ok(NULL, buffer, bfd->length));
+
+ return bfd->length;
}
/** Open listen sockets/connect to external event source
*/
flags = UDP_FLAGS_CONNECTED * (thread->connection != NULL);
- data_size = udp_recv(thread->sockfd, flags, &address->socket, wrapper->packet, buffer_len - (wrapper->packet - buffer), recv_time_p);
+ data_size = udp_recv(thread->sockfd, flags, &address->socket, wrapper->packet, buffer_len - offsetof(bfd_wrapper_t, packet), recv_time_p);
if (data_size < 0) {
PDEBUG2("proto_bfd_udp got read error");
return data_size;
*/
client = fr_rb_find(inst->peers, &(fr_client_t) { .ipaddr = address->socket.inet.src_ipaddr, .proto = IPPROTO_UDP });
if (!client) {
- DEBUG2("proto_bfd_udp - Received invalid packet on %s - uknown client %pV:%u", thread->name,
+ DEBUG2("BFD %s - Received invalid packet on %s - unknown client %pV:%u", inst->server_name, thread->name,
fr_box_ipaddr(address->socket.inet.src_ipaddr), address->socket.inet.src_port);
thread->stats.total_packets_dropped++;
return 0;
packet_len = data_size;
if (!fr_bfd_packet_ok(&err, wrapper->packet, packet_len)) {
- DEBUG2("proto_bfd_udp - Received invalid packet on %s - %s", thread->name, err);
+ DEBUG2("BFD %s - Received invalid packet on %s - %s", inst->server_name, thread->name, err);
thread->stats.total_malformed_requests++;
return 0;
}
uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
{
proto_bfd_udp_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_bfd_udp_thread_t);
- fr_io_track_t *track = talloc_get_type_abort(packet_ctx, fr_io_track_t);
-
- fr_socket_t socket;
-
- int flags;
+ fr_io_track_t *track = talloc_get_type_abort(packet_ctx, fr_io_track_t);
+ bfd_session_t *session;
+ ssize_t rcode;
+ char const *err;
/*
* @todo - share a stats interface with the parent? or
*/
thread->stats.total_responses++;
- flags = UDP_FLAGS_CONNECTED * (thread->connection != NULL);
-
- /*
- * Swap src/dst address so we send the response to
- * the client, not ourselves.
- */
- fr_socket_addr_swap(&socket, &track->address->socket);
+ session = UNCONST(bfd_session_t *, track->address->radclient);
- /*
- * We only write RADIUS packets.
- */
fr_assert(buffer_len >= FR_BFD_HEADER_LENGTH);
- /*
- * Only write replies if they're RADIUS packets.
- * sometimes we want to NOT send a reply...
- */
- return udp_send(&socket, flags, buffer, buffer_len);
+ fr_assert(fr_bfd_packet_ok(&err, buffer, buffer_len));
+
+ DEBUG("BFD %s peer %s sending %s",
+ session->server_name, session->client.shortname, fr_bfd_packet_names[session->session_state]);
+
+ rcode = sendfromto(session->sockfd, buffer, buffer_len, 0, 0,
+ (struct sockaddr *) &session->local_sockaddr, session->local_salen,
+ (struct sockaddr *) &session->remote_sockaddr, session->remote_salen);
+ if (rcode < 0) {
+ ERROR("Failed sending packet: %s", fr_syserror(errno));
+ fr_assert(0);
+ }
+
+ return rcode;
}
static void mod_network_get(void *instance, int *ipproto, bool *dynamic_clients, fr_trie_t const **trie)
peer->nr = (fr_network_t *) nr;
peer->sockfd = thread->sockfd;
peer->server_name = inst->server_name;
+ peer->only_state_changes = inst->only_state_changes;
bfd_session_start(peer);
}
* we will need to define some other kind of fake packet to send to the process
* module.
*/
-static void bfd_trigger(bfd_session_t *session, bfd_state_change_t change)
+static void bfd_trigger(UNUSED bfd_session_t *session, UNUSED bfd_state_change_t change)
{
+#if 0
bfd_wrapper_t wrapper;
+ fr_io_track_t *track;
wrapper.type = BFD_WRAPPER_STATE_CHANGE;
wrapper.state_change = change;
wrapper.session = session;
- /*
- * @todo - proto_bfd.c mod_decode() has to be updated to check for non-existent packet,
- * and create a fake "timeout" packet with appropriate data.
- */
+ track = fr_master_io_track_alloc(session->listen, &session->client, &session->client.ipaddr, session->port,
+ &session->client.src_ipaddr, session->port);
+ if (!track) return;
-// (void) fr_network_listen_inject(session->nr, session->listen, (uint8_t const *) &wrapper, sizeof(wrapper), fr_time());
+ (void) fr_network_sendto_worker(session->nr, session->listen, track, (uint8_t const *) &wrapper, sizeof(wrapper), fr_time());
+#endif
}
/*
bfd->min_echo_rx_interval = fr_time_delta_to_usec(session->my_min_echo_rx_interval);
}
+static void bfd_send_init(bfd_session_t *session, bfd_packet_t *bfd)
+{
+ bfd_control_packet_init(session, bfd);
+
+ bfd->poll = session->doing_poll;
+
+ if (!bfd->demand) {
+ bfd_start_packets(session);
+ }
+
+ bfd_sign(session, bfd);
+}
/*
* Send one BFD packet.
bfd_session_t *session = ctx;
bfd_packet_t bfd;
- bfd_control_packet_init(session, &bfd);
-
- bfd.poll = session->doing_poll;
-
- if (!bfd.demand) {
- bfd_start_packets(session);
- }
-
- bfd_sign(session, &bfd);
+ bfd_send_init(session, &bfd);
DEBUG("BFD %s peer %s sending %s",
session->server_name, session->client.shortname, fr_bfd_packet_names[session->session_state]);
}
}
+/*
+ * Send one BFD packet.
+ */
+static void bfd_unlang_send_packet(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *ctx)
+{
+ bfd_session_t *session = ctx;
+ bfd_packet_t *bfd;
+ bfd_wrapper_t *wrapper;
+ fr_io_track_t *track;
+ fr_listen_t *parent;
+ uint8_t buffer[sizeof(bfd_wrapper_t) + sizeof(*bfd)];
+
+ wrapper = (bfd_wrapper_t *) buffer;
+ bfd = (bfd_packet_t *) wrapper->packet;
+
+ bfd_send_init(session, bfd);
+
+ session->last_sent = fr_time();
+
+ wrapper->type = BFD_WRAPPER_SEND_PACKET;
+ wrapper->state_change = BFD_STATE_CHANGE_NONE;
+ wrapper->session = session;
+
+ parent = talloc_parent(session->listen);
+ (void) talloc_get_type_abort(parent, fr_listen_t);
+
+ track = fr_master_io_track_alloc(session->listen, &session->client, &session->client.ipaddr, session->port,
+ &session->client.src_ipaddr, session->port);
+ if (!track) return;
+
+ (void) fr_network_sendto_worker(session->nr, parent, track, (uint8_t const *) wrapper, (wrapper->packet + bfd->length) - (uint8_t *) wrapper, fr_time());
+}
+
/*
* Start sending packets.
*/
{
uint64_t interval, base;
uint64_t jitter;
+ fr_event_timer_cb_t cb;
if (session->ev_packet) return;
interval = base;
interval += jitter;
+ if (!session->only_state_changes) {
+ cb = bfd_unlang_send_packet;
+ } else {
+ cb = bfd_send_packet;
+ }
+
if (fr_event_timer_in(session, session->el, &session->ev_packet,
fr_time_delta_wrap(interval),
- bfd_send_packet, session) < 0) {
+ cb, session) < 0) {
fr_assert("Failed to insert event" == NULL);
}
}
char const *server_name; //!< our name
+ bool only_state_changes; //!< copied from proto_bfd_udp.c
+
/*
* Peers are defined globally to a virtual server. Each
* peer can only have one session associated with it.