xref: /openbsd/usr.sbin/eigrpd/rtp.c (revision 8072de9b)
1*8072de9bSrenato /*	$OpenBSD: rtp.c,v 1.6 2016/09/02 16:29:55 renato 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 
19*8072de9bSrenato #include <sys/types.h>
20*8072de9bSrenato #include <netinet/in.h>
21*8072de9bSrenato #include <netinet/ip.h>
22*8072de9bSrenato 
2343509a12Srenato #include <stdlib.h>
2443509a12Srenato 
2543509a12Srenato #include "eigrpd.h"
2643509a12Srenato #include "eigrpe.h"
2743509a12Srenato #include "log.h"
2843509a12Srenato 
2943509a12Srenato void		 rtp_retrans_timer(int, short, void *);
3043509a12Srenato void		 rtp_retrans_start_timer(struct packet *);
3143509a12Srenato void		 rtp_retrans_stop_timer(struct packet *);
3243509a12Srenato 
3343509a12Srenato struct pbuf *
3443509a12Srenato rtp_buf_new(struct ibuf *buf)
3543509a12Srenato {
3643509a12Srenato 	struct pbuf	*pbuf;
3743509a12Srenato 
3843509a12Srenato 	if ((pbuf = calloc(1, sizeof(*pbuf))) == NULL)
3943509a12Srenato 		fatal("rtp_buf_new");
4043509a12Srenato 	pbuf->buf = buf;
4143509a12Srenato 
4243509a12Srenato 	return (pbuf);
4343509a12Srenato }
4443509a12Srenato 
4543509a12Srenato struct pbuf *
4643509a12Srenato rtp_buf_hold(struct pbuf *pbuf)
4743509a12Srenato {
4843509a12Srenato 	pbuf->refcnt++;
4943509a12Srenato 	return (pbuf);
5043509a12Srenato }
5143509a12Srenato 
5243509a12Srenato void
5343509a12Srenato rtp_buf_release(struct pbuf *pbuf)
5443509a12Srenato {
5543509a12Srenato 	if (--pbuf->refcnt == 0) {
5643509a12Srenato 		ibuf_free(pbuf->buf);
5743509a12Srenato 		free(pbuf);
5843509a12Srenato 	}
5943509a12Srenato }
6043509a12Srenato 
6143509a12Srenato struct packet *
6243509a12Srenato rtp_packet_new(struct nbr *nbr, uint32_t seq_num, struct pbuf *pbuf)
6343509a12Srenato {
6443509a12Srenato 	struct packet		*pkt;
6543509a12Srenato 
6643509a12Srenato 	if ((pkt = calloc(1, sizeof(struct packet))) == NULL)
6743509a12Srenato 		fatal("rtp_packet_new");
6843509a12Srenato 
6943509a12Srenato 	pkt->nbr = nbr;
7043509a12Srenato 	pkt->seq_num = seq_num;
7143509a12Srenato 	pkt->pbuf = rtp_buf_hold(pbuf);
7243509a12Srenato 	pkt->attempts = 1;
7343509a12Srenato 	evtimer_set(&pkt->ev_timeout, rtp_retrans_timer, pkt);
7443509a12Srenato 
7543509a12Srenato 	return (pkt);
7643509a12Srenato }
7743509a12Srenato 
7843509a12Srenato void
7943509a12Srenato rtp_packet_del(struct packet *pkt)
8043509a12Srenato {
8143509a12Srenato 	TAILQ_REMOVE(&pkt->nbr->retrans_list, pkt, entry);
8243509a12Srenato 	rtp_retrans_stop_timer(pkt);
8343509a12Srenato 	rtp_buf_release(pkt->pbuf);
8443509a12Srenato 	free(pkt);
8543509a12Srenato }
8643509a12Srenato 
8743509a12Srenato void
8843509a12Srenato rtp_process_ack(struct nbr *nbr, uint32_t ack_num)
8943509a12Srenato {
9043509a12Srenato 	struct eigrp	*eigrp = nbr->ei->eigrp;
9143509a12Srenato 	struct packet	*pkt;
9243509a12Srenato 
9343509a12Srenato 	/* window size is one */
9443509a12Srenato 	pkt = TAILQ_FIRST(&nbr->retrans_list);
9543509a12Srenato 	if (pkt && pkt->seq_num == ack_num) {
9643509a12Srenato 		log_debug("%s: nbr %s ack %u", __func__,
9743509a12Srenato 		    log_addr(eigrp->af, &nbr->addr), ack_num);
9843509a12Srenato 
9943509a12Srenato 		/* dequeue packet from retransmission queue */
10043509a12Srenato 		rtp_packet_del(pkt);
10143509a12Srenato 
10243509a12Srenato 		/* enqueue next packet from retransmission queue */
10343509a12Srenato 		pkt = TAILQ_FIRST(&nbr->retrans_list);
10443509a12Srenato 		if (pkt)
10543509a12Srenato 			rtp_send_packet(pkt);
10643509a12Srenato 	}
10743509a12Srenato }
10843509a12Srenato 
10943509a12Srenato void
11043509a12Srenato rtp_send_packet(struct packet *pkt)
11143509a12Srenato {
11243509a12Srenato 	rtp_retrans_start_timer(pkt);
11343509a12Srenato 	send_packet(pkt->nbr->ei, pkt->nbr, 0, pkt->pbuf->buf);
11443509a12Srenato }
11543509a12Srenato 
11643509a12Srenato void
11743509a12Srenato rtp_enqueue_packet(struct packet *pkt)
11843509a12Srenato {
11943509a12Srenato 	/* only send packet if transmission queue is empty */
12043509a12Srenato 	if (TAILQ_EMPTY(&pkt->nbr->retrans_list))
12143509a12Srenato 		rtp_send_packet(pkt);
12243509a12Srenato 
12343509a12Srenato 	TAILQ_INSERT_TAIL(&pkt->nbr->retrans_list, pkt, entry);
12443509a12Srenato }
12543509a12Srenato 
12643509a12Srenato static void
12743509a12Srenato rtp_seq_inc(struct eigrp *eigrp)
12843509a12Srenato {
12943509a12Srenato 	/* automatic wraparound with unsigned arithmetic */
13043509a12Srenato 	eigrp->seq_num++;
13143509a12Srenato 
13243509a12Srenato 	/* sequence number 0 is reserved for unreliably transmission */
13343509a12Srenato 	if (eigrp->seq_num == 0)
13443509a12Srenato 		eigrp->seq_num = 1;
13543509a12Srenato }
13643509a12Srenato 
13743509a12Srenato void
13843509a12Srenato rtp_send_ucast(struct nbr *nbr, struct ibuf *buf)
13943509a12Srenato {
14043509a12Srenato 	struct eigrp		*eigrp = nbr->ei->eigrp;
14143509a12Srenato 	struct packet		*pkt;
14243509a12Srenato 	struct pbuf		*pbuf;
14343509a12Srenato 
14443509a12Srenato 	pbuf = rtp_buf_new(buf);
14543509a12Srenato 	pkt = rtp_packet_new(nbr, eigrp->seq_num, pbuf);
14643509a12Srenato 	rtp_enqueue_packet(pkt);
14743509a12Srenato 	rtp_seq_inc(eigrp);
14843509a12Srenato }
14943509a12Srenato 
15043509a12Srenato void
15143509a12Srenato rtp_send_mcast(struct eigrp_iface *ei, struct ibuf *buf)
15243509a12Srenato {
15343509a12Srenato 	struct eigrp		*eigrp = ei->eigrp;
15443509a12Srenato 	struct nbr		*nbr;
15543509a12Srenato 	int			 total = 0, pending = 0;
15643509a12Srenato 	struct packet		*pkt;
15743509a12Srenato 	struct pbuf		*pbuf;
15843509a12Srenato 	uint32_t		 flags = 0;
15943509a12Srenato 	struct seq_addr_entry	*sa;
16043509a12Srenato 	struct seq_addr_head	 seq_addr_list;
16143509a12Srenato 
16243509a12Srenato 	TAILQ_FOREACH(nbr, &ei->nbr_list, entry) {
16343509a12Srenato 		if (nbr->flags & F_EIGRP_NBR_SELF)
16443509a12Srenato 			continue;
16543509a12Srenato 		if (!TAILQ_EMPTY(&nbr->retrans_list))
16643509a12Srenato 			pending++;
16743509a12Srenato 		total++;
16843509a12Srenato 	}
16943509a12Srenato 	if (total == 0)
17043509a12Srenato 		return;
17143509a12Srenato 
17243509a12Srenato 	/*
17343509a12Srenato 	 * send a multicast if there's at least one neighbor with an empty
17443509a12Srenato 	 * queue on the interface.
17543509a12Srenato 	 */
17643509a12Srenato 	if (pending < total) {
17743509a12Srenato 		/*
17843509a12Srenato 		 * build a hello packet with a seq tlv indicating all the
17943509a12Srenato 		 * neighbors that have full queues.
18043509a12Srenato 		 */
18143509a12Srenato 		if (pending > 0) {
18243509a12Srenato 			flags |= EIGRP_HDR_FLAG_CR;
18343509a12Srenato 			TAILQ_INIT(&seq_addr_list);
18443509a12Srenato 
18543509a12Srenato 			TAILQ_FOREACH(nbr, &ei->nbr_list, entry) {
18643509a12Srenato 				if (TAILQ_EMPTY(&nbr->retrans_list))
18743509a12Srenato 					continue;
18843509a12Srenato 				if ((sa = calloc(1, sizeof(*sa))) == NULL)
18943509a12Srenato 					fatal("rtp_send_mcast");
19043509a12Srenato 				sa->af = eigrp->af;
1913eb03b29Srenato 				sa->addr = nbr->addr;
19243509a12Srenato 				TAILQ_INSERT_TAIL(&seq_addr_list, sa, entry);
19343509a12Srenato 			}
19443509a12Srenato 
1950e96235eSrenato 			send_hello(ei, &seq_addr_list, eigrp->seq_num);
19643509a12Srenato 			seq_addr_list_clr(&seq_addr_list);
19743509a12Srenato 		}
19843509a12Srenato 		send_packet(ei, NULL, flags, buf);
19943509a12Srenato 	}
20043509a12Srenato 
20143509a12Srenato 	/* schedule an unicast retransmission for each neighbor */
20243509a12Srenato 	pbuf = rtp_buf_new(buf);
20343509a12Srenato 	TAILQ_FOREACH(nbr, &ei->nbr_list, entry) {
20443509a12Srenato 		pkt = rtp_packet_new(nbr, eigrp->seq_num, pbuf);
20543509a12Srenato 		TAILQ_INSERT_TAIL(&nbr->retrans_list, pkt, entry);
20643509a12Srenato 	}
20743509a12Srenato 
20843509a12Srenato 	rtp_seq_inc(eigrp);
20943509a12Srenato }
21043509a12Srenato 
21143509a12Srenato void
21243509a12Srenato rtp_send(struct eigrp_iface *ei, struct nbr *nbr, struct ibuf *buf)
21343509a12Srenato {
21443509a12Srenato 	if (nbr)
21543509a12Srenato 		rtp_send_ucast(nbr, buf);
21643509a12Srenato 	else
21743509a12Srenato 		rtp_send_mcast(ei, buf);
21843509a12Srenato }
21943509a12Srenato 
22043509a12Srenato void
22143509a12Srenato rtp_send_ack(struct nbr *nbr)
22243509a12Srenato {
22343509a12Srenato 	struct eigrp		*eigrp = nbr->ei->eigrp;
22443509a12Srenato 	struct ibuf		*buf;
22543509a12Srenato 
22643509a12Srenato 	if ((buf = ibuf_dynamic(PKG_DEF_SIZE,
22743509a12Srenato 	    IP_MAXPACKET - sizeof(struct ip))) == NULL)
22843509a12Srenato 		fatal("rtp_send_ack");
22943509a12Srenato 
23043509a12Srenato 	/* EIGRP header */
2310cefb3adSrenato 	if (gen_eigrp_hdr(buf, EIGRP_OPC_HELLO, 0, 0, eigrp->as)) {
2320cefb3adSrenato 		log_warnx("%s: failed to send message", __func__);
2330cefb3adSrenato 		ibuf_free(buf);
2340cefb3adSrenato 		return;
2350cefb3adSrenato 	}
23643509a12Srenato 
23743509a12Srenato 	/* send unreliably */
23843509a12Srenato 	send_packet(nbr->ei, nbr, 0, buf);
23943509a12Srenato 	ibuf_free(buf);
24043509a12Srenato }
24143509a12Srenato 
24243509a12Srenato /* timers */
24343509a12Srenato 
24443509a12Srenato /* ARGSUSED */
24543509a12Srenato void
24643509a12Srenato rtp_retrans_timer(int fd, short event, void *arg)
24743509a12Srenato {
24843509a12Srenato 	struct packet		*pkt = arg;
24943509a12Srenato 	struct eigrp		*eigrp = pkt->nbr->ei->eigrp;
25043509a12Srenato 
25143509a12Srenato 	pkt->attempts++;
25243509a12Srenato 
25343509a12Srenato 	if (pkt->attempts > RTP_RTRNS_MAX_ATTEMPTS) {
25443509a12Srenato 		log_warnx("%s: retry limit exceeded, nbr %s", __func__,
25543509a12Srenato 		    log_addr(eigrp->af, &pkt->nbr->addr));
25643509a12Srenato 		nbr_del(pkt->nbr);
25743509a12Srenato 		return;
25843509a12Srenato 	}
25943509a12Srenato 
26043509a12Srenato 	rtp_send_packet(pkt);
26143509a12Srenato }
26243509a12Srenato 
26343509a12Srenato void
26443509a12Srenato rtp_retrans_start_timer(struct packet *pkt)
26543509a12Srenato {
26643509a12Srenato 	struct timeval		 tv;
26743509a12Srenato 
26843509a12Srenato 	timerclear(&tv);
26943509a12Srenato 	tv.tv_sec = RTP_RTRNS_INTERVAL;
27043509a12Srenato 	if (evtimer_add(&pkt->ev_timeout, &tv) == -1)
27143509a12Srenato 		fatal("rtp_retrans_start_timer");
27243509a12Srenato }
27343509a12Srenato 
27443509a12Srenato void
27543509a12Srenato rtp_retrans_stop_timer(struct packet *pkt)
27643509a12Srenato {
27743509a12Srenato 	if (evtimer_pending(&pkt->ev_timeout, NULL) &&
27843509a12Srenato 	    evtimer_del(&pkt->ev_timeout) == -1)
27943509a12Srenato 		fatal("rtp_retrans_stop_timer");
28043509a12Srenato }
28143509a12Srenato 
28243509a12Srenato /* ARGSUSED */
28343509a12Srenato void
28443509a12Srenato rtp_ack_timer(int fd, short event, void *arg)
28543509a12Srenato {
28643509a12Srenato 	struct nbr		*nbr = arg;
28743509a12Srenato 
28843509a12Srenato 	rtp_send_ack(nbr);
28943509a12Srenato }
29043509a12Srenato 
29143509a12Srenato void
29243509a12Srenato rtp_ack_start_timer(struct nbr *nbr)
29343509a12Srenato {
29443509a12Srenato 	struct timeval		 tv;
29543509a12Srenato 
29643509a12Srenato 	timerclear(&tv);
29743509a12Srenato 	tv.tv_usec = RTP_ACK_TIMEOUT;
29843509a12Srenato 	if (evtimer_add(&nbr->ev_ack, &tv) == -1)
29943509a12Srenato 		fatal("rtp_ack_start_timer");
30043509a12Srenato }
30143509a12Srenato 
30243509a12Srenato void
30343509a12Srenato rtp_ack_stop_timer(struct nbr *nbr)
30443509a12Srenato {
30543509a12Srenato 	if (evtimer_pending(&nbr->ev_ack, NULL) &&
30643509a12Srenato 	    evtimer_del(&nbr->ev_ack) == -1)
30743509a12Srenato 		fatal("rtp_ack_stop_timer");
30843509a12Srenato }
309