-/* $OpenBSD: rtr_proto.c,v 1.13 2023/03/09 17:21:21 claudio Exp $ */
+/* $OpenBSD: rtr_proto.c,v 1.14 2023/03/11 10:04:59 claudio Exp $ */
/*
* Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
enum rtr_state {
RTR_STATE_CLOSED,
RTR_STATE_ERROR,
+ /* sessions with a state below this line will poll for incoming data */
RTR_STATE_IDLE,
RTR_STATE_ACTIVE,
RTR_STATE_NEGOTIATION,
}
};
+static void
+rtr_reset_cache(struct rtr_session *rs)
+{
+ /* reset session */
+ rs->session_id = -1;
+ timer_stop(&rs->timers, Timer_Rtr_Expire);
+ free_roatree(&rs->roa_set);
+ free_aspatree(&rs->aspa_v4);
+ free_aspatree(&rs->aspa_v6);
+}
+
static struct ibuf *
rtr_newmsg(struct rtr_session *rs, enum rtr_pdu_type type, uint32_t len,
uint16_t session_id)
} else
memset(rs->last_sent_msg, 0, sizeof(rs->last_sent_msg));
- rtr_fsm(rs, RTR_EVNT_SEND_ERROR);
-
buf = rtr_newmsg(rs, ERROR_REPORT, 2 * sizeof(hdrlen) + len + mlen,
err);
if (buf == NULL) {
log_warnx("rtr %s: sending error report[%u] %s", log_rtr(rs), err,
msg ? msg : "");
+
+ rtr_fsm(rs, RTR_EVNT_SEND_ERROR);
}
static void
-rtr_reset_query(struct rtr_session *rs)
+rtr_send_reset_query(struct rtr_session *rs)
{
struct ibuf *buf;
}
static void
-rtr_serial_query(struct rtr_session *rs)
+rtr_send_serial_query(struct rtr_session *rs)
{
struct ibuf *buf;
uint32_t s;
static int
rtr_parse_notify(struct rtr_session *rs, uint8_t *buf, size_t len)
{
- if (rs->state == RTR_STATE_ACTIVE) {
- log_warnx("rtr %s: received %s: while active (ignored)",
- log_rtr(rs), log_rtr_type(SERIAL_NOTIFY));
+ if (rs->state == RTR_STATE_ACTIVE ||
+ rs->state == RTR_STATE_NEGOTIATION) {
+ log_warnx("rtr %s: received %s: while in state %s (ignored)",
+ log_rtr(rs), log_rtr_type(SERIAL_NOTIFY),
+ rtr_statenames[rs->state]);
return 0;
}
return -1;
}
- memcpy(&eod, buf, sizeof(eod));
-
if (rs->state != RTR_STATE_ACTIVE) {
log_warnx("rtr %s: received %s: out of context",
log_rtr(rs), log_rtr_type(END_OF_DATA));
return -1;
}
+ memcpy(&eod, buf, sizeof(eod));
+
rs->serial = ntohl(eod.serial);
/* validate timer values to be in the right range */
t = ntohl(eod.refresh);
return;
}
- /* flush buffers */
- msgbuf_clear(&rs->w);
- rs->r.wpos = 0;
- close(rs->fd);
- rs->fd = -1;
+ if (rs->fd != -1) {
+ /* flush buffers */
+ msgbuf_clear(&rs->w);
+ rs->r.wpos = 0;
+ close(rs->fd);
+ rs->fd = -1;
+ }
/* retry connection with lower version */
timer_set(&rs->timers, Timer_Rtr_Retry, rs->retry);
}
/* FALLTHROUGH */
case RTR_EVNT_RESET_AND_CLOSE:
- rs->state = RTR_STATE_ERROR;
+ rtr_reset_cache(rs);
+ rtr_recalc();
/* FALLTHROUGH */
case RTR_EVNT_CON_CLOSE:
- if (rs->state == RTR_STATE_ERROR) {
- /* reset session */
- rs->session_id = -1;
- free_roatree(&rs->roa_set);
- free_aspatree(&rs->aspa_v4);
- free_aspatree(&rs->aspa_v6);
- rtr_recalc();
+ if (rs->state == RTR_STATE_NEGOTIATION) {
+ /* consider any close event as a version failure. */
+ rtr_fsm(rs, RTR_EVNT_UNSUPP_PROTO_VERSION);
+ break;
}
- if (rs->state != RTR_STATE_CLOSED) {
+ if (rs->fd != -1) {
/* flush buffers */
msgbuf_clear(&rs->w);
rs->r.wpos = 0;
case RTR_EVNT_CON_OPEN:
timer_stop(&rs->timers, Timer_Rtr_Retry);
if (rs->session_id == -1)
- rtr_reset_query(rs);
+ rtr_send_reset_query(rs);
else
- rtr_serial_query(rs);
+ rtr_send_serial_query(rs);
break;
case RTR_EVNT_SERIAL_NOTIFY:
/* schedule a refresh after a quick wait */
break;
case RTR_EVNT_TIMER_REFRESH:
/* send serial query */
- rtr_serial_query(rs);
+ rtr_send_serial_query(rs);
break;
case RTR_EVNT_TIMER_EXPIRE:
- free_roatree(&rs->roa_set);
- free_aspatree(&rs->aspa_v4);
- free_aspatree(&rs->aspa_v6);
+ rtr_reset_cache(rs);
rtr_recalc();
break;
case RTR_EVNT_CACHE_RESPONSE:
rtr_recalc();
break;
case RTR_EVNT_CACHE_RESET:
- /* reset session and retry after a quick wait */
- rs->session_id = -1;
- free_roatree(&rs->roa_set);
- free_aspatree(&rs->aspa_v4);
- free_aspatree(&rs->aspa_v6);
+ rtr_reset_cache(rs);
rtr_recalc();
+ /* retry after a quick wait */
timer_set(&rs->timers, Timer_Rtr_Retry,
arc4random_uniform(10));
break;
rs->state = RTR_STATE_IDLE;
break;
case RTR_EVNT_SEND_ERROR:
+ rtr_reset_cache(rs);
+ rtr_recalc();
rs->state = RTR_STATE_ERROR;
/* flush receive buffer */
rs->r.wpos = 0;
rtr_fsm(rs, RTR_EVNT_CON_CLOSE);
}
}
- if (error == 0) {
+ if (error == 0)
rtr_fsm(rs, RTR_EVNT_CON_CLOSE);
- }
if (rs->w.queued == 0 && rs->state == RTR_STATE_ERROR)
rtr_fsm(rs, RTR_EVNT_CON_CLOSE);
}
if (rs == NULL)
return;
+ rtr_reset_cache(rs);
rtr_fsm(rs, RTR_EVNT_CON_CLOSE);
timer_remove_all(&rs->timers);
- free_roatree(&rs->roa_set);
- free_aspatree(&rs->aspa_v4);
- free_aspatree(&rs->aspa_v6);
free(rs);
}