Download raw body.
bgpd rewrite rtr pdu parser to new ibuf API
On Thu, Jan 04, 2024 at 11:36:40AM +0100, Claudio Jeker wrote:
> This diff converts the RTR PDU parser to use the ibuf API.
> More cleanup is possible but lets start with a "minimal" conversion.
Yes, it's big enough.
> The ASPA PDU handling is maybe a bit ugly but that part will change once
> SIDROPS made up their mind about how this PDU should look like.
:)
> This introduces ibuf_get_string() which I plan to add to libutil since I
> used the same function in xlock privsep code. Extracting a string from
> an imsg seems to be somewhat common and this API ensures that the string
> is NUL terminated.
This generally looks good. I think there's one bug due to the removal of
the rv dance in rtr_parse_error(). Apart from that it's just nits as
usual.
>
> --
> :wq Claudio
>
> Index: rtr_proto.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rtr_proto.c,v
> diff -u -p -r1.21 rtr_proto.c
> --- rtr_proto.c 3 Jan 2024 16:07:37 -0000 1.21
> +++ rtr_proto.c 4 Jan 2024 10:05:26 -0000
> @@ -266,10 +266,10 @@ rtr_newmsg(struct rtr_session *rs, enum
> */
> static void
> rtr_send_error(struct rtr_session *rs, enum rtr_error err, char *msg,
> - void *pdu, size_t len)
> + struct ibuf *pdu)
> {
> struct ibuf *buf;
> - size_t mlen = 0;
> + size_t len = 0, mlen = 0;
>
> rs->last_sent_error = err;
> if (msg) {
> @@ -278,14 +278,21 @@ rtr_send_error(struct rtr_session *rs, e
> } else
> memset(rs->last_sent_msg, 0, sizeof(rs->last_sent_msg));
>
> + if (pdu) {
I'd prefer an explicit != NULL (also in the if (msg) above).
> + ibuf_rewind(pdu);
> + len = ibuf_size(pdu);
> + }
> +
> buf = rtr_newmsg(rs, ERROR_REPORT, 2 * sizeof(uint32_t) + len + mlen,
> err);
> if (buf == NULL)
> goto fail;
> if (ibuf_add_n32(buf, len) == -1)
> goto fail;
> - if (ibuf_add(buf, pdu, len) == -1)
> - goto fail;
> + if (pdu) {
same here
> + if (ibuf_add_ibuf(buf, pdu) == -1)
> + goto fail;
> + }
> if (ibuf_add_n32(buf, mlen) == -1)
> goto fail;
> if (ibuf_add(buf, msg, mlen) == -1)
> @@ -311,7 +318,7 @@ rtr_send_reset_query(struct rtr_session
> buf = rtr_newmsg(rs, RESET_QUERY, 0, 0);
> if (buf == NULL) {
> log_warn("rtr %s: send reset query", log_rtr(rs));
> - rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL, 0);
> + rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL);
> return;
> }
> ibuf_close(&rs->w, buf);
> @@ -333,7 +340,7 @@ rtr_send_serial_query(struct rtr_session
> fail:
> log_warn("rtr %s: send serial query", log_rtr(rs));
> ibuf_free(buf);
> - rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL, 0);
> + rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL);
> }
>
> /*
> @@ -343,20 +350,21 @@ rtr_send_serial_query(struct rtr_session
> * and the function return 0.
> */
> static int
> -rtr_parse_header(struct rtr_session *rs, void *buf,
> +rtr_parse_header(struct rtr_session *rs, struct ibuf *hdr,
> size_t *msglen, enum rtr_pdu_type *msgtype)
> {
> struct rtr_header rh;
> uint32_t len = 16; /* default for ERROR_REPORT */
> int session_id;
>
> - memcpy(&rh, buf, sizeof(rh));
> + if (ibuf_get(hdr, &rh, sizeof(rh)) == -1)
> + fatal("%s: ibuf_get", __func__);
>
> if (rh.version != rs->version && rh.type != ERROR_REPORT) {
> badversion:
> log_warnx("rtr %s: received %s message: unexpected version %d",
> log_rtr(rs), log_rtr_type(rh.type), rh.version);
> - rtr_send_error(rs, UNEXP_PROTOCOL_VERS, NULL, &rh, sizeof(rh));
> + rtr_send_error(rs, UNEXP_PROTOCOL_VERS, NULL, hdr);
> return -1;
> }
>
> @@ -401,8 +409,7 @@ rtr_parse_header(struct rtr_session *rs,
> toobig:
> log_warnx("rtr %s: received %s: msg too big: %zu byte",
> log_rtr(rs), log_rtr_type(rh.type), *msglen);
> - rtr_send_error(rs, CORRUPT_DATA, "too big",
> - &rh, sizeof(rh));
> + rtr_send_error(rs, CORRUPT_DATA, "too big", hdr);
> return -1;
> }
> if (*msglen < len) {
> @@ -410,8 +417,7 @@ rtr_parse_header(struct rtr_session *rs,
> log_warnx("rtr %s: received %s: msg too small: "
> "%zu byte", log_rtr(rs), log_rtr_type(rh.type),
> *msglen);
> - rtr_send_error(rs, CORRUPT_DATA, "too small",
> - &rh, sizeof(rh));
> + rtr_send_error(rs, CORRUPT_DATA, "too small", hdr);
> return -1;
> }
> /*
> @@ -434,15 +440,14 @@ rtr_parse_header(struct rtr_session *rs,
> default:
> log_warnx("rtr %s: received unknown message: type %s",
> log_rtr(rs), log_rtr_type(rh.type));
> - rtr_send_error(rs, UNSUPP_PDU_TYPE, NULL, &rh, sizeof(rh));
> + rtr_send_error(rs, UNSUPP_PDU_TYPE, NULL, hdr);
> return -1;
> }
>
> if (len != *msglen) {
> log_warnx("rtr %s: received %s: illegal len: %zu byte not %u",
> log_rtr(rs), log_rtr_type(rh.type), *msglen, len);
> - rtr_send_error(rs, CORRUPT_DATA, "bad length",
> - &rh, sizeof(rh));
> + rtr_send_error(rs, CORRUPT_DATA, "bad length", hdr);
> return -1;
> }
>
> @@ -454,8 +459,7 @@ rtr_parse_header(struct rtr_session *rs,
> log_warnx("rtr %s: received %s: bad session_id: %d != %d",
> log_rtr(rs), log_rtr_type(rh.type), ntohs(rh.session_id),
> session_id);
> - rtr_send_error(rs, CORRUPT_DATA, "bad session_id",
> - &rh, sizeof(rh));
> + rtr_send_error(rs, CORRUPT_DATA, "bad session_id", hdr);
> return -1;
> }
>
> @@ -463,7 +467,7 @@ rtr_parse_header(struct rtr_session *rs,
> }
>
> static int
> -rtr_parse_notify(struct rtr_session *rs, uint8_t *buf, size_t len)
> +rtr_parse_notify(struct rtr_session *rs, struct ibuf *pdu)
> {
> if (rs->state == RTR_STATE_EXCHANGE ||
> rs->state == RTR_STATE_NEGOTIATION) {
> @@ -478,7 +482,7 @@ rtr_parse_notify(struct rtr_session *rs,
> }
>
> static int
> -rtr_parse_cache_response(struct rtr_session *rs, uint8_t *buf, size_t len)
> +rtr_parse_cache_response(struct rtr_session *rs, struct ibuf *pdu)
> {
> if (rs->state != RTR_STATE_ESTABLISHED &&
> rs->state != RTR_STATE_NEGOTIATION) {
> @@ -492,39 +496,39 @@ rtr_parse_cache_response(struct rtr_sess
> }
>
> static int
> -rtr_parse_ipv4_prefix(struct rtr_session *rs, uint8_t *buf, size_t len)
> +rtr_parse_ipv4_prefix(struct rtr_session *rs, struct ibuf *pdu)
> {
> struct rtr_ipv4 ip4;
> struct roa *roa;
>
> - if (len != sizeof(struct rtr_header) + sizeof(ip4)) {
> + if (ibuf_skip(pdu, sizeof(struct rtr_header)) == -1 ||
> + ibuf_get(pdu, &ip4, sizeof(ip4)) == -1) {
> log_warnx("rtr %s: received %s: bad pdu len",
> log_rtr(rs), log_rtr_type(IPV4_PREFIX));
> - rtr_send_error(rs, CORRUPT_DATA, "bad len", buf, len);
> + rtr_send_error(rs, CORRUPT_DATA, "bad len", pdu);
> return -1;
> }
>
> if (rs->state != RTR_STATE_EXCHANGE) {
> log_warnx("rtr %s: received %s: out of context",
> log_rtr(rs), log_rtr_type(IPV4_PREFIX));
> - rtr_send_error(rs, CORRUPT_DATA, NULL, buf, len);
> + rtr_send_error(rs, CORRUPT_DATA, NULL, pdu);
> return -1;
> }
>
> - memcpy(&ip4, buf + sizeof(struct rtr_header), sizeof(ip4));
> if (ip4.prefixlen > 32 || ip4.maxlen > 32 ||
> ip4.prefixlen > ip4.maxlen) {
> log_warnx("rtr: %s: received %s: bad prefixlen / maxlen",
> log_rtr(rs), log_rtr_type(IPV4_PREFIX));
> rtr_send_error(rs, CORRUPT_DATA, "bad prefixlen / maxlen",
> - buf, len);
> + pdu);
Can't this be unwrapped?
> return -1;
> }
>
> if ((roa = calloc(1, sizeof(*roa))) == NULL) {
> log_warn("rtr %s: received %s",
> log_rtr(rs), log_rtr_type(IPV4_PREFIX));
> - rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL, 0);
> + rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL);
> return -1;
> }
> roa->aid = AID_INET;
> @@ -537,7 +541,7 @@ rtr_parse_ipv4_prefix(struct rtr_session
> if (RB_INSERT(roa_tree, &rs->roa_set, roa) != NULL) {
> log_warnx("rtr %s: received %s: duplicate announcement",
> log_rtr(rs), log_rtr_type(IPV4_PREFIX));
> - rtr_send_error(rs, DUP_REC_RECV, NULL, buf, len);
> + rtr_send_error(rs, DUP_REC_RECV, NULL, pdu);
> free(roa);
> return -1;
> }
> @@ -548,7 +552,7 @@ rtr_parse_ipv4_prefix(struct rtr_session
> if (r == NULL) {
> log_warnx("rtr %s: received %s: unknown withdrawal",
> log_rtr(rs), log_rtr_type(IPV4_PREFIX));
> - rtr_send_error(rs, UNK_REC_WDRAWL, NULL, buf, len);
> + rtr_send_error(rs, UNK_REC_WDRAWL, NULL, pdu);
> free(roa);
> return -1;
> }
> @@ -561,39 +565,39 @@ rtr_parse_ipv4_prefix(struct rtr_session
> }
>
> static int
> -rtr_parse_ipv6_prefix(struct rtr_session *rs, uint8_t *buf, size_t len)
> +rtr_parse_ipv6_prefix(struct rtr_session *rs, struct ibuf *pdu)
> {
> struct rtr_ipv6 ip6;
> struct roa *roa;
>
> - if (len != sizeof(struct rtr_header) + sizeof(ip6)) {
> + if (ibuf_skip(pdu, sizeof(struct rtr_header)) == -1 ||
> + ibuf_get(pdu, &ip6, sizeof(ip6)) == -1) {
> log_warnx("rtr %s: received %s: bad pdu len",
> log_rtr(rs), log_rtr_type(IPV6_PREFIX));
> - rtr_send_error(rs, CORRUPT_DATA, "bad len", buf, len);
> + rtr_send_error(rs, CORRUPT_DATA, "bad len", pdu);
> return -1;
> }
>
> if (rs->state != RTR_STATE_EXCHANGE) {
> log_warnx("rtr %s: received %s: out of context",
> log_rtr(rs), log_rtr_type(IPV6_PREFIX));
> - rtr_send_error(rs, CORRUPT_DATA, NULL, buf, len);
> + rtr_send_error(rs, CORRUPT_DATA, NULL, pdu);
> return -1;
> }
>
> - memcpy(&ip6, buf + sizeof(struct rtr_header), sizeof(ip6));
> if (ip6.prefixlen > 128 || ip6.maxlen > 128 ||
> ip6.prefixlen > ip6.maxlen) {
> log_warnx("rtr: %s: received %s: bad prefixlen / maxlen",
> log_rtr(rs), log_rtr_type(IPV6_PREFIX));
> rtr_send_error(rs, CORRUPT_DATA, "bad prefixlen / maxlen",
> - buf, len);
> + pdu);
unwrap?
> return -1;
> }
>
> if ((roa = calloc(1, sizeof(*roa))) == NULL) {
> log_warn("rtr %s: received %s",
> log_rtr(rs), log_rtr_type(IPV6_PREFIX));
> - rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL, 0);
> + rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL);
> return -1;
> }
> roa->aid = AID_INET6;
> @@ -606,7 +610,7 @@ rtr_parse_ipv6_prefix(struct rtr_session
> if (RB_INSERT(roa_tree, &rs->roa_set, roa) != NULL) {
> log_warnx("rtr %s: received %s: duplicate announcement",
> log_rtr(rs), log_rtr_type(IPV6_PREFIX));
> - rtr_send_error(rs, DUP_REC_RECV, NULL, buf, len);
> + rtr_send_error(rs, DUP_REC_RECV, NULL, pdu);
> free(roa);
> return -1;
> }
> @@ -617,7 +621,7 @@ rtr_parse_ipv6_prefix(struct rtr_session
> if (r == NULL) {
> log_warnx("rtr %s: received %s: unknown withdrawal",
> log_rtr(rs), log_rtr_type(IPV6_PREFIX));
> - rtr_send_error(rs, UNK_REC_WDRAWL, NULL, buf, len);
> + rtr_send_error(rs, UNK_REC_WDRAWL, NULL, pdu);
> free(roa);
> return -1;
> }
> @@ -629,28 +633,32 @@ rtr_parse_ipv6_prefix(struct rtr_session
> }
>
> static int
> -rtr_parse_aspa(struct rtr_session *rs, uint8_t *buf, size_t len)
> +rtr_parse_aspa(struct rtr_session *rs, struct ibuf *pdu)
> {
> struct rtr_aspa rtr_aspa;
> struct aspa_tree *aspatree;
> struct aspa_set *aspa, *a;
> - size_t offset;
> uint16_t cnt, i;
>
> - memcpy(&rtr_aspa, buf + sizeof(struct rtr_header), sizeof(rtr_aspa));
> - offset = sizeof(struct rtr_header) + sizeof(rtr_aspa);
> + if (ibuf_skip(pdu, sizeof(struct rtr_header)) == -1 ||
> + ibuf_get(pdu, &rtr_aspa, sizeof(rtr_aspa)) == -1) {
> + log_warnx("rtr %s: received %s: bad pdu len",
> + log_rtr(rs), log_rtr_type(ASPA));
> + rtr_send_error(rs, CORRUPT_DATA, "bad len", pdu);
> + return -1;
> + }
> cnt = ntohs(rtr_aspa.cnt);
> - if (len != offset + cnt * sizeof(uint32_t)) {
> + if (ibuf_size(pdu) != cnt * sizeof(uint32_t)) {
> log_warnx("rtr %s: received %s: bad pdu len",
> log_rtr(rs), log_rtr_type(ASPA));
> - rtr_send_error(rs, CORRUPT_DATA, "bad len", buf, len);
> + rtr_send_error(rs, CORRUPT_DATA, "bad len", pdu);
> return -1;
> }
>
> if (rs->state != RTR_STATE_EXCHANGE) {
> log_warnx("rtr %s: received %s: out of context",
> log_rtr(rs), log_rtr_type(ASPA));
> - rtr_send_error(rs, CORRUPT_DATA, NULL, buf, len);
> + rtr_send_error(rs, CORRUPT_DATA, NULL, pdu);
> return -1;
> }
>
> @@ -664,7 +672,7 @@ rtr_parse_aspa(struct rtr_session *rs, u
> if ((aspa = calloc(1, sizeof(*aspa))) == NULL) {
> log_warn("rtr %s: received %s",
> log_rtr(rs), log_rtr_type(ASPA));
> - rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL, 0);
> + rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL);
> return -1;
> }
> aspa->as = ntohl(rtr_aspa.cas);
> @@ -675,14 +683,17 @@ rtr_parse_aspa(struct rtr_session *rs, u
> log_warn("rtr %s: received %s",
> log_rtr(rs), log_rtr_type(ASPA));
> rtr_send_error(rs, INTERNAL_ERROR, "out of memory",
> - NULL, 0);
> + NULL);
> return -1;
> }
> for (i = 0; i < cnt; i++) {
> - uint32_t tas;
> - memcpy(&tas, buf + offset + i * sizeof(tas),
> - sizeof(tas));
> - aspa->tas[i] = ntohl(tas);
> + if (ibuf_get_n32(pdu, &aspa->tas[i]) == -1) {
> + log_warnx("rtr %s: received %s: bad pdu len",
> + log_rtr(rs), log_rtr_type(ASPA));
> + rtr_send_error(rs, CORRUPT_DATA, "bad len",
> + pdu);
> + return -1;
> + }
> }
> }
>
> @@ -696,7 +707,7 @@ rtr_parse_aspa(struct rtr_session *rs, u
> log_warnx("rtr %s: received %s: corrupt tree",
> log_rtr(rs), log_rtr_type(ASPA));
> rtr_send_error(rs, INTERNAL_ERROR,
> - "corrupt aspa tree", NULL, 0);
> + "corrupt aspa tree", NULL);
> free_aspa(aspa);
> return -1;
> }
> @@ -706,7 +717,7 @@ rtr_parse_aspa(struct rtr_session *rs, u
> if (a == NULL) {
> log_warnx("rtr %s: received %s: unknown withdrawal",
> log_rtr(rs), log_rtr_type(ASPA));
> - rtr_send_error(rs, UNK_REC_WDRAWL, NULL, buf, len);
> + rtr_send_error(rs, UNK_REC_WDRAWL, NULL, pdu);
> free_aspa(aspa);
> return -1;
> }
> @@ -719,15 +730,13 @@ rtr_parse_aspa(struct rtr_session *rs, u
> }
>
> static int
> -rtr_parse_end_of_data(struct rtr_session *rs, uint8_t *buf, size_t len)
> +rtr_parse_end_of_data(struct rtr_session *rs, struct ibuf *pdu)
> {
> struct rtr_endofdata eod;
> uint32_t t;
>
> - buf += sizeof(struct rtr_header);
> - len -= sizeof(struct rtr_header);
> -
> - if (len != sizeof(eod)) {
> + if (ibuf_skip(pdu, sizeof(struct rtr_header)) == -1 ||
> + ibuf_get(pdu, &eod, sizeof(eod)) == -1) {
> log_warnx("rtr %s: received %s: bad pdu len",
> log_rtr(rs), log_rtr_type(END_OF_DATA));
> return -1;
> @@ -739,8 +748,6 @@ rtr_parse_end_of_data(struct rtr_session
> 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);
> @@ -768,7 +775,7 @@ bad:
> }
>
> static int
> -rtr_parse_cache_reset(struct rtr_session *rs, uint8_t *buf, size_t len)
> +rtr_parse_cache_reset(struct rtr_session *rs, struct ibuf *pdu)
> {
> if (rs->state != RTR_STATE_ESTABLISHED) {
> log_warnx("rtr %s: received %s: out of context",
> @@ -780,61 +787,60 @@ rtr_parse_cache_reset(struct rtr_session
> return 0;
> }
>
> +static char *
> +ibuf_get_string(struct ibuf *buf, size_t len)
> +{
> + char *str;
> +
> + if (ibuf_size(buf) < len) {
> + errno = EBADMSG;
> + return (NULL);
> + }
> + str = strndup(ibuf_data(buf), len);
> + if (str == NULL)
> + return (NULL);
> + ibuf_skip(buf, len);
> + return (str);
> +}
> +
> /*
> * Parse an Error Response message. This function behaves a bit different
> * from other parse functions since on error the connection needs to be
> * dropped without sending an error response back.
> */
> static int
> -rtr_parse_error(struct rtr_session *rs, uint8_t *buf, size_t len)
> +rtr_parse_error(struct rtr_session *rs, struct ibuf *pdu)
> {
> struct rtr_header rh;
> + struct ibuf err_pdu;
> uint32_t pdu_len, msg_len;
> - uint8_t *msg;
> char *str = NULL;
> uint16_t errcode;
> - int rv = -1;
>
> - memcpy(&rh, buf, sizeof(rh));
> - buf += sizeof(struct rtr_header);
> - len -= sizeof(struct rtr_header);
> + if (ibuf_get(pdu, &rh, sizeof(rh)) == -1)
> + goto fail;
> errcode = ntohs(rh.session_id);
>
> - memcpy(&pdu_len, buf, sizeof(pdu_len));
> - pdu_len = ntohl(pdu_len);
> -
> - if (len < pdu_len + sizeof(pdu_len)) {
> - log_warnx("rtr %s: received %s: bad encapsulated pdu len: %u "
> - "byte", log_rtr(rs), log_rtr_type(ERROR_REPORT), pdu_len);
> - rtr_fsm(rs, RTR_EVNT_RESET_AND_CLOSE);
> - return -1;
> - }
> + if (ibuf_get_n32(pdu, &pdu_len) == -1)
> + goto fail;
>
> /* for now just ignore the embedded pdu */
> - buf += pdu_len + sizeof(pdu_len);
> - len -= pdu_len + sizeof(pdu_len);
> -
> - memcpy(&msg_len, buf, sizeof(msg_len));
> - msg_len = ntohl(msg_len);
> + if (ibuf_get_ibuf(pdu, pdu_len, &err_pdu) == -1)
> + goto fail;
>
> - if (len < msg_len + sizeof(msg_len)) {
> - log_warnx("rtr %s: received %s: bad msg len: %u byte",
> - log_rtr(rs), log_rtr_type(ERROR_REPORT), msg_len);
> - rtr_fsm(rs, RTR_EVNT_RESET_AND_CLOSE);
> - return -1;
> - }
> + if (ibuf_get_n32(pdu, &msg_len) == -1)
> + goto fail;
>
> - msg = buf + sizeof(msg_len);
> if (msg_len != 0)
> /* optional error msg, no need to check for failure */
This comment no longer applies. I'd also add braces:
if (msg_len != 0) {
> - str = strndup(msg, msg_len);
> + if ((str = ibuf_get_string(pdu, msg_len)) == NULL)
> + goto fail;
}
>
> log_warnx("rtr %s: received error: %s%s%s", log_rtr(rs),
> log_rtr_error(errcode), str ? ": " : "", str ? str : "");
>
> if (errcode == NO_DATA_AVAILABLE) {
> rtr_fsm(rs, RTR_EVNT_NO_DATA);
> - rv = 0;
Getting rid of this rv dance makes the UNSUPP_PROTOCOL_VERS and
RESET_AND_CLOSE no longer return -1, so we won't return from
rtr_process_msg().
> } else if (errcode == UNSUPP_PROTOCOL_VERS)
> rtr_fsm(rs, RTR_EVNT_UNSUPP_PROTO_VERSION);
> else
> @@ -849,7 +855,13 @@ rtr_parse_error(struct rtr_session *rs,
> sizeof(rs->last_recv_msg));
I'd be tempted to unwrap the two strlcpy and memset calls.
>
> free(str);
> - return rv;
> + return 0;
> +
> + fail:
> + log_warnx("rtr %s: received %s: bad encoding", log_rtr(rs),
> + log_rtr_type(ERROR_REPORT));
> + rtr_fsm(rs, RTR_EVNT_RESET_AND_CLOSE);
> + return -1;
> }
>
> /*
> @@ -860,61 +872,58 @@ rtr_parse_error(struct rtr_session *rs,
> static void
> rtr_process_msg(struct rtr_session *rs)
> {
> - size_t rpos, av, left;
> - void *rptr;
> + struct ibuf rbuf, hdr, msg;
> size_t msglen;
> enum rtr_pdu_type msgtype;
>
> - rpos = 0;
> - av = rs->r.wpos;
> + ibuf_from_buffer(&rbuf, rs->r.buf, rs->r.wpos);
>
> for (;;) {
> - if (rpos + sizeof(struct rtr_header) > av)
> + if (ibuf_size(&rbuf) < sizeof(struct rtr_header))
> break;
> - rptr = rs->r.buf + rpos;
> - if (rtr_parse_header(rs, rptr, &msglen, &msgtype) == -1)
> +
> + /* parse header */
> + ibuf_from_buffer(&hdr, ibuf_data(&rbuf),
> + sizeof(struct rtr_header));
> + if (rtr_parse_header(rs, &hdr, &msglen, &msgtype) == -1)
> return;
>
> - /* missing data */
> - if (rpos + msglen > av)
> + /* extract message */
> + if (ibuf_get_ibuf(&rbuf, msglen, &msg) == -1)
> break;
>
> switch (msgtype) {
> case SERIAL_NOTIFY:
> - if (rtr_parse_notify(rs, rptr, msglen) == -1) {
> - rtr_send_error(rs, CORRUPT_DATA, NULL,
> - rptr, msglen);
> + if (rtr_parse_notify(rs, &msg) == -1) {
> + rtr_send_error(rs, CORRUPT_DATA, NULL, &msg);
> return;
> }
> break;
> case CACHE_RESPONSE:
> - if (rtr_parse_cache_response(rs, rptr, msglen) == -1) {
> - rtr_send_error(rs, CORRUPT_DATA, NULL,
> - rptr, msglen);
> + if (rtr_parse_cache_response(rs, &msg) == -1) {
> + rtr_send_error(rs, CORRUPT_DATA, NULL, &msg);
> return;
> }
> break;
> case IPV4_PREFIX:
> - if (rtr_parse_ipv4_prefix(rs, rptr, msglen) == -1) {
> + if (rtr_parse_ipv4_prefix(rs, &msg) == -1) {
> return;
> }
> break;
> case IPV6_PREFIX:
> - if (rtr_parse_ipv6_prefix(rs, rptr, msglen) == -1) {
> + if (rtr_parse_ipv6_prefix(rs, &msg) == -1) {
> return;
> }
> break;
> case END_OF_DATA:
> - if (rtr_parse_end_of_data(rs, rptr, msglen) == -1) {
> - rtr_send_error(rs, CORRUPT_DATA, NULL,
> - rptr, msglen);
> + if (rtr_parse_end_of_data(rs, &msg) == -1) {
> + rtr_send_error(rs, CORRUPT_DATA, NULL, &msg);
> return;
> }
> break;
> case CACHE_RESET:
> - if (rtr_parse_cache_reset(rs, rptr, msglen) == -1) {
> - rtr_send_error(rs, CORRUPT_DATA, NULL,
> - rptr, msglen);
> + if (rtr_parse_cache_reset(rs, &msg) == -1) {
> + rtr_send_error(rs, CORRUPT_DATA, NULL, &msg);
> return;
> }
> break;
> @@ -922,27 +931,26 @@ rtr_process_msg(struct rtr_session *rs)
> /* silently ignore router key */
> break;
> case ERROR_REPORT:
> - if (rtr_parse_error(rs, rptr, msglen) == -1)
> + if (rtr_parse_error(rs, &msg) == -1) {
> /* no need to send back an error */
> return;
> + }
> break;
> case ASPA:
> - if (rtr_parse_aspa(rs, rptr, msglen) == -1) {
> + if (rtr_parse_aspa(rs, &msg) == -1) {
> return;
> }
> break;
> default:
> log_warnx("rtr %s: received %s: unexpected pdu type",
> log_rtr(rs), log_rtr_type(msgtype));
> - rtr_send_error(rs, INVALID_REQUEST, NULL, rptr, msglen);
> + rtr_send_error(rs, INVALID_REQUEST, NULL, &msg);
> return;
> }
> - rpos += msglen;
> }
>
> - left = av - rpos;
> - memmove(&rs->r.buf, rs->r.buf + rpos, left);
> - rs->r.wpos = left;
> + memmove(&rs->r.buf, ibuf_data(&rbuf), ibuf_size(&rbuf));
> + rs->r.wpos = ibuf_size(&rbuf);
> }
>
> /*
> @@ -968,7 +976,7 @@ rtr_fsm(struct rtr_session *rs, enum rtr
> log_warnx("rtr %s: version negotiation failed",
> log_rtr(rs));
> rtr_send_error(rs, UNSUPP_PROTOCOL_VERS,
> - NULL, NULL, 0);
> + NULL, NULL);
> return;
> }
>
> @@ -991,11 +999,6 @@ rtr_fsm(struct rtr_session *rs, enum rtr
> rtr_recalc();
> /* FALLTHROUGH */
> case RTR_EVNT_CON_CLOSE:
> - 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->fd != -1) {
> /* flush buffers */
> msgbuf_clear(&rs->w);
>
bgpd rewrite rtr pdu parser to new ibuf API