xref: /openbsd/usr.sbin/eigrpd/rtp.c (revision 5b133f3f)
1*5b133f3fSguenther /*	$OpenBSD: rtp.c,v 1.8 2023/03/08 04:43:13 guenther Exp $ */
243509a12Srenato 
343509a12Srenato /*
443509a12Srenato  * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
543509a12Srenato  *
643509a12Srenato  * Permission to use, copy, modify, and distribute this software for any
743509a12Srenato  * purpose with or without fee is hereby granted, provided that the above
843509a12Srenato  * copyright notice and this permission notice appear in all copies.
943509a12Srenato  *
1043509a12Srenato  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1143509a12Srenato  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1243509a12Srenato  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1343509a12Srenato  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1443509a12Srenato  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1543509a12Srenato  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1643509a12Srenato  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1743509a12Srenato  */
1843509a12Srenato 
198072de9bSrenato #include <sys/types.h>
208072de9bSrenato #include <netinet/in.h>
218072de9bSrenato #include <netinet/ip.h>
228072de9bSrenato 
2343509a12Srenato #include <stdlib.h>
2443509a12Srenato 
2543509a12Srenato #include "eigrpd.h"
2643509a12Srenato #include "eigrpe.h"
2743509a12Srenato #include "log.h"
2843509a12Srenato 
29ab786365Srenato static struct pbuf	*rtp_buf_new(struct ibuf *);
30ab786365Srenato static struct pbuf	*rtp_buf_hold(struct pbuf *);
31ab786365Srenato static void		 rtp_buf_release(struct pbuf *);
32ab786365Srenato static struct packet	*rtp_packet_new(struct nbr *, uint32_t, struct pbuf *);
33ab786365Srenato static void		 rtp_send_packet(struct packet *);
34ab786365Srenato static void		 rtp_enqueue_packet(struct packet *);
35ab786365Srenato static void		 rtp_send_mcast(struct eigrp_iface *, struct ibuf *);
36ab786365Srenato static void		 rtp_retrans_timer(int, short, void *);
37ab786365Srenato static void		 rtp_retrans_start_timer(struct packet *);
38ab786365Srenato static void		 rtp_retrans_stop_timer(struct packet *);
3943509a12Srenato 
40ab786365Srenato static struct pbuf *
rtp_buf_new(struct ibuf * buf)4143509a12Srenato rtp_buf_new(struct ibuf *buf)
4243509a12Srenato {
4343509a12Srenato 	struct pbuf	*pbuf;
4443509a12Srenato 
4543509a12Srenato 	if ((pbuf = calloc(1, sizeof(*pbuf))) == NULL)
4643509a12Srenato 		fatal("rtp_buf_new");
4743509a12Srenato 	pbuf->buf = buf;
4843509a12Srenato 
4943509a12Srenato 	return (pbuf);
5043509a12Srenato }
5143509a12Srenato 
52ab786365Srenato static struct pbuf *
rtp_buf_hold(struct pbuf * pbuf)5343509a12Srenato rtp_buf_hold(struct pbuf *pbuf)
5443509a12Srenato {
5543509a12Srenato 	pbuf->refcnt++;
5643509a12Srenato 	return (pbuf);
5743509a12Srenato }
5843509a12Srenato 
59ab786365Srenato static void
rtp_buf_release(struct pbuf * pbuf)6043509a12Srenato rtp_buf_release(struct pbuf *pbuf)
6143509a12Srenato {
6243509a12Srenato 	if (--pbuf->refcnt == 0) {
6343509a12Srenato 		ibuf_free(pbuf->buf);
6443509a12Srenato 		free(pbuf);
6543509a12Srenato 	}
6643509a12Srenato }
6743509a12Srenato 
68ab786365Srenato static struct packet *
rtp_packet_new(struct nbr * nbr,uint32_t seq_num,struct pbuf * pbuf)6943509a12Srenato rtp_packet_new(struct nbr *nbr, uint32_t seq_num, struct pbuf *pbuf)
7043509a12Srenato {
7143509a12Srenato 	struct packet		*pkt;
7243509a12Srenato 
7343509a12Srenato 	if ((pkt = calloc(1, sizeof(struct packet))) == NULL)
7443509a12Srenato 		fatal("rtp_packet_new");
7543509a12Srenato 
7643509a12Srenato 	pkt->nbr = nbr;
7743509a12Srenato 	pkt->seq_num = seq_num;
7843509a12Srenato 	pkt->pbuf = rtp_buf_hold(pbuf);
7943509a12Srenato 	pkt->attempts = 1;
8043509a12Srenato 	evtimer_set(&pkt->ev_timeout, rtp_retrans_timer, pkt);
8143509a12Srenato 
8243509a12Srenato 	return (pkt);
8343509a12Srenato }
8443509a12Srenato 
8543509a12Srenato void
rtp_packet_del(struct packet * pkt)8643509a12Srenato rtp_packet_del(struct packet *pkt)
8743509a12Srenato {
8843509a12Srenato 	TAILQ_REMOVE(&pkt->nbr->retrans_list, pkt, entry);
8943509a12Srenato 	rtp_retrans_stop_timer(pkt);
9043509a12Srenato 	rtp_buf_release(pkt->pbuf);
9143509a12Srenato 	free(pkt);
9243509a12Srenato }
9343509a12Srenato 
9443509a12Srenato void
rtp_process_ack(struct nbr * nbr,uint32_t ack_num)9543509a12Srenato rtp_process_ack(struct nbr *nbr, uint32_t ack_num)
9643509a12Srenato {
9743509a12Srenato 	struct eigrp	*eigrp = nbr->ei->eigrp;
9843509a12Srenato 	struct packet	*pkt;
9943509a12Srenato 
10043509a12Srenato 	/* window size is one */
10143509a12Srenato 	pkt = TAILQ_FIRST(&nbr->retrans_list);
10243509a12Srenato 	if (pkt && pkt->seq_num == ack_num) {
10343509a12Srenato 		log_debug("%s: nbr %s ack %u", __func__,
10443509a12Srenato 		    log_addr(eigrp->af, &nbr->addr), ack_num);
10543509a12Srenato 
10643509a12Srenato 		/* dequeue packet from retransmission queue */
10743509a12Srenato 		rtp_packet_del(pkt);
10843509a12Srenato 
10943509a12Srenato 		/* enqueue next packet from retransmission queue */
11043509a12Srenato 		pkt = TAILQ_FIRST(&nbr->retrans_list);
11143509a12Srenato 		if (pkt)
11243509a12Srenato 			rtp_send_packet(pkt);
11343509a12Srenato 	}
11443509a12Srenato }
11543509a12Srenato 
116ab786365Srenato static void
rtp_send_packet(struct packet * pkt)11743509a12Srenato rtp_send_packet(struct packet *pkt)
11843509a12Srenato {
11943509a12Srenato 	rtp_retrans_start_timer(pkt);
12043509a12Srenato 	send_packet(pkt->nbr->ei, pkt->nbr, 0, pkt->pbuf->buf);
12143509a12Srenato }
12243509a12Srenato 
123ab786365Srenato static void
rtp_enqueue_packet(struct packet * pkt)12443509a12Srenato rtp_enqueue_packet(struct packet *pkt)
12543509a12Srenato {
12643509a12Srenato 	/* only send packet if transmission queue is empty */
12743509a12Srenato 	if (TAILQ_EMPTY(&pkt->nbr->retrans_list))
12843509a12Srenato 		rtp_send_packet(pkt);
12943509a12Srenato 
13043509a12Srenato 	TAILQ_INSERT_TAIL(&pkt->nbr->retrans_list, pkt, entry);
13143509a12Srenato }
13243509a12Srenato 
13343509a12Srenato static void
rtp_seq_inc(struct eigrp * eigrp)13443509a12Srenato rtp_seq_inc(struct eigrp *eigrp)
13543509a12Srenato {
13643509a12Srenato 	/* automatic wraparound with unsigned arithmetic */
13743509a12Srenato 	eigrp->seq_num++;
13843509a12Srenato 
13943509a12Srenato 	/* sequence number 0 is reserved for unreliably transmission */
14043509a12Srenato 	if (eigrp->seq_num == 0)
14143509a12Srenato 		eigrp->seq_num = 1;
14243509a12Srenato }
14343509a12Srenato 
14443509a12Srenato void
rtp_send_ucast(struct nbr * nbr,struct ibuf * buf)14543509a12Srenato rtp_send_ucast(struct nbr *nbr, struct ibuf *buf)
14643509a12Srenato {
14743509a12Srenato 	struct eigrp		*eigrp = nbr->ei->eigrp;
14843509a12Srenato 	struct packet		*pkt;
14943509a12Srenato 	struct pbuf		*pbuf;
15043509a12Srenato 
15143509a12Srenato 	pbuf = rtp_buf_new(buf);
15243509a12Srenato 	pkt = rtp_packet_new(nbr, eigrp->seq_num, pbuf);
15343509a12Srenato 	rtp_enqueue_packet(pkt);
15443509a12Srenato 	rtp_seq_inc(eigrp);
15543509a12Srenato }
15643509a12Srenato 
157ab786365Srenato static void
rtp_send_mcast(struct eigrp_iface * ei,struct ibuf * buf)15843509a12Srenato rtp_send_mcast(struct eigrp_iface *ei, struct ibuf *buf)
15943509a12Srenato {
16043509a12Srenato 	struct eigrp		*eigrp = ei->eigrp;
16143509a12Srenato 	struct nbr		*nbr;
16243509a12Srenato 	int			 total = 0, pending = 0;
16343509a12Srenato 	struct packet		*pkt;
16443509a12Srenato 	struct pbuf		*pbuf;
16543509a12Srenato 	uint32_t		 flags = 0;
16643509a12Srenato 	struct seq_addr_entry	*sa;
16743509a12Srenato 	struct seq_addr_head	 seq_addr_list;
16843509a12Srenato 
16943509a12Srenato 	TAILQ_FOREACH(nbr, &ei->nbr_list, entry) {
17043509a12Srenato 		if (nbr->flags & F_EIGRP_NBR_SELF)
17143509a12Srenato 			continue;
17243509a12Srenato 		if (!TAILQ_EMPTY(&nbr->retrans_list))
17343509a12Srenato 			pending++;
17443509a12Srenato 		total++;
17543509a12Srenato 	}
17643509a12Srenato 	if (total == 0)
17743509a12Srenato 		return;
17843509a12Srenato 
17943509a12Srenato 	/*
18043509a12Srenato 	 * send a multicast if there's at least one neighbor with an empty
18143509a12Srenato 	 * queue on the interface.
18243509a12Srenato 	 */
18343509a12Srenato 	if (pending < total) {
18443509a12Srenato 		/*
18543509a12Srenato 		 * build a hello packet with a seq tlv indicating all the
18643509a12Srenato 		 * neighbors that have full queues.
18743509a12Srenato 		 */
18843509a12Srenato 		if (pending > 0) {
18943509a12Srenato 			flags |= EIGRP_HDR_FLAG_CR;
19043509a12Srenato 			TAILQ_INIT(&seq_addr_list);
19143509a12Srenato 
19243509a12Srenato 			TAILQ_FOREACH(nbr, &ei->nbr_list, entry) {
19343509a12Srenato 				if (TAILQ_EMPTY(&nbr->retrans_list))
19443509a12Srenato 					continue;
19543509a12Srenato 				if ((sa = calloc(1, sizeof(*sa))) == NULL)
19643509a12Srenato 					fatal("rtp_send_mcast");
19743509a12Srenato 				sa->af = eigrp->af;
1983eb03b29Srenato 				sa->addr = nbr->addr;
19943509a12Srenato 				TAILQ_INSERT_TAIL(&seq_addr_list, sa, entry);
20043509a12Srenato 			}
20143509a12Srenato 
2020e96235eSrenato 			send_hello(ei, &seq_addr_list, eigrp->seq_num);
20343509a12Srenato 			seq_addr_list_clr(&seq_addr_list);
20443509a12Srenato 		}
20543509a12Srenato 		send_packet(ei, NULL, flags, buf);
20643509a12Srenato 	}
20743509a12Srenato 
20843509a12Srenato 	/* schedule an unicast retransmission for each neighbor */
20943509a12Srenato 	pbuf = rtp_buf_new(buf);
21043509a12Srenato 	TAILQ_FOREACH(nbr, &ei->nbr_list, entry) {
21143509a12Srenato 		pkt = rtp_packet_new(nbr, eigrp->seq_num, pbuf);
21243509a12Srenato 		TAILQ_INSERT_TAIL(&nbr->retrans_list, pkt, entry);
21343509a12Srenato 	}
21443509a12Srenato 
21543509a12Srenato 	rtp_seq_inc(eigrp);
21643509a12Srenato }
21743509a12Srenato 
21843509a12Srenato void
rtp_send(struct eigrp_iface * ei,struct nbr * nbr,struct ibuf * buf)21943509a12Srenato rtp_send(struct eigrp_iface *ei, struct nbr *nbr, struct ibuf *buf)
22043509a12Srenato {
22143509a12Srenato 	if (nbr)
22243509a12Srenato 		rtp_send_ucast(nbr, buf);
22343509a12Srenato 	else
22443509a12Srenato 		rtp_send_mcast(ei, buf);
22543509a12Srenato }
22643509a12Srenato 
22743509a12Srenato void
rtp_send_ack(struct nbr * nbr)22843509a12Srenato rtp_send_ack(struct nbr *nbr)
22943509a12Srenato {
23043509a12Srenato 	struct eigrp		*eigrp = nbr->ei->eigrp;
23143509a12Srenato 	struct ibuf		*buf;
23243509a12Srenato 
23343509a12Srenato 	if ((buf = ibuf_dynamic(PKG_DEF_SIZE,
23443509a12Srenato 	    IP_MAXPACKET - sizeof(struct ip))) == NULL)
23543509a12Srenato 		fatal("rtp_send_ack");
23643509a12Srenato 
23743509a12Srenato 	/* EIGRP header */
2380cefb3adSrenato 	if (gen_eigrp_hdr(buf, EIGRP_OPC_HELLO, 0, 0, eigrp->as)) {
2390cefb3adSrenato 		log_warnx("%s: failed to send message", __func__);
2400cefb3adSrenato 		ibuf_free(buf);
2410cefb3adSrenato 		return;
2420cefb3adSrenato 	}
24343509a12Srenato 
24443509a12Srenato 	/* send unreliably */
24543509a12Srenato 	send_packet(nbr->ei, nbr, 0, buf);
24643509a12Srenato 	ibuf_free(buf);
24743509a12Srenato }
24843509a12Srenato 
24943509a12Srenato /* timers */
25043509a12Srenato 
251ab786365Srenato static void
rtp_retrans_timer(int fd,short event,void * arg)25243509a12Srenato rtp_retrans_timer(int fd, short event, void *arg)
25343509a12Srenato {
25443509a12Srenato 	struct packet		*pkt = arg;
25543509a12Srenato 	struct eigrp		*eigrp = pkt->nbr->ei->eigrp;
25643509a12Srenato 
25743509a12Srenato 	pkt->attempts++;
25843509a12Srenato 
25943509a12Srenato 	if (pkt->attempts > RTP_RTRNS_MAX_ATTEMPTS) {
26043509a12Srenato 		log_warnx("%s: retry limit exceeded, nbr %s", __func__,
26143509a12Srenato 		    log_addr(eigrp->af, &pkt->nbr->addr));
26243509a12Srenato 		nbr_del(pkt->nbr);
26343509a12Srenato 		return;
26443509a12Srenato 	}
26543509a12Srenato 
26643509a12Srenato 	rtp_send_packet(pkt);
26743509a12Srenato }
26843509a12Srenato 
269ab786365Srenato static void
rtp_retrans_start_timer(struct packet * pkt)27043509a12Srenato rtp_retrans_start_timer(struct packet *pkt)
27143509a12Srenato {
27243509a12Srenato 	struct timeval		 tv;
27343509a12Srenato 
27443509a12Srenato 	timerclear(&tv);
27543509a12Srenato 	tv.tv_sec = RTP_RTRNS_INTERVAL;
27643509a12Srenato 	if (evtimer_add(&pkt->ev_timeout, &tv) == -1)
27743509a12Srenato 		fatal("rtp_retrans_start_timer");
27843509a12Srenato }
27943509a12Srenato 
280ab786365Srenato static void
rtp_retrans_stop_timer(struct packet * pkt)28143509a12Srenato rtp_retrans_stop_timer(struct packet *pkt)
28243509a12Srenato {
28343509a12Srenato 	if (evtimer_pending(&pkt->ev_timeout, NULL) &&
28443509a12Srenato 	    evtimer_del(&pkt->ev_timeout) == -1)
28543509a12Srenato 		fatal("rtp_retrans_stop_timer");
28643509a12Srenato }
28743509a12Srenato 
28843509a12Srenato void
rtp_ack_timer(int fd,short event,void * arg)28943509a12Srenato rtp_ack_timer(int fd, short event, void *arg)
29043509a12Srenato {
29143509a12Srenato 	struct nbr		*nbr = arg;
29243509a12Srenato 
29343509a12Srenato 	rtp_send_ack(nbr);
29443509a12Srenato }
29543509a12Srenato 
29643509a12Srenato void
rtp_ack_start_timer(struct nbr * nbr)29743509a12Srenato rtp_ack_start_timer(struct nbr *nbr)
29843509a12Srenato {
29943509a12Srenato 	struct timeval		 tv;
30043509a12Srenato 
30143509a12Srenato 	timerclear(&tv);
30243509a12Srenato 	tv.tv_usec = RTP_ACK_TIMEOUT;
30343509a12Srenato 	if (evtimer_add(&nbr->ev_ack, &tv) == -1)
30443509a12Srenato 		fatal("rtp_ack_start_timer");
30543509a12Srenato }
30643509a12Srenato 
30743509a12Srenato void
rtp_ack_stop_timer(struct nbr * nbr)30843509a12Srenato rtp_ack_stop_timer(struct nbr *nbr)
30943509a12Srenato {
31043509a12Srenato 	if (evtimer_pending(&nbr->ev_ack, NULL) &&
31143509a12Srenato 	    evtimer_del(&nbr->ev_ack) == -1)
31243509a12Srenato 		fatal("rtp_ack_stop_timer");
31343509a12Srenato }
314