xref: /openbsd/usr.sbin/eigrpd/rtp.c (revision 43509a12)
1*43509a12Srenato /*	$OpenBSD: rtp.c,v 1.1 2015/10/02 04:26:47 renato Exp $ */
2*43509a12Srenato 
3*43509a12Srenato /*
4*43509a12Srenato  * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
5*43509a12Srenato  *
6*43509a12Srenato  * Permission to use, copy, modify, and distribute this software for any
7*43509a12Srenato  * purpose with or without fee is hereby granted, provided that the above
8*43509a12Srenato  * copyright notice and this permission notice appear in all copies.
9*43509a12Srenato  *
10*43509a12Srenato  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*43509a12Srenato  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*43509a12Srenato  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*43509a12Srenato  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*43509a12Srenato  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*43509a12Srenato  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*43509a12Srenato  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*43509a12Srenato  */
18*43509a12Srenato 
19*43509a12Srenato #include <stdlib.h>
20*43509a12Srenato #include <string.h>
21*43509a12Srenato #include <arpa/inet.h>
22*43509a12Srenato 
23*43509a12Srenato #include "eigrpd.h"
24*43509a12Srenato #include "eigrp.h"
25*43509a12Srenato #include "eigrpe.h"
26*43509a12Srenato #include "rde.h"
27*43509a12Srenato #include "log.h"
28*43509a12Srenato 
29*43509a12Srenato void		 rtp_retrans_timer(int, short, void *);
30*43509a12Srenato void		 rtp_retrans_start_timer(struct packet *);
31*43509a12Srenato void		 rtp_retrans_stop_timer(struct packet *);
32*43509a12Srenato 
33*43509a12Srenato struct pbuf *
34*43509a12Srenato rtp_buf_new(struct ibuf *buf)
35*43509a12Srenato {
36*43509a12Srenato 	struct pbuf	*pbuf;
37*43509a12Srenato 
38*43509a12Srenato 	if ((pbuf = calloc(1, sizeof(*pbuf))) == NULL)
39*43509a12Srenato 		fatal("rtp_buf_new");
40*43509a12Srenato 	pbuf->buf = buf;
41*43509a12Srenato 
42*43509a12Srenato 	return (pbuf);
43*43509a12Srenato }
44*43509a12Srenato 
45*43509a12Srenato struct pbuf *
46*43509a12Srenato rtp_buf_hold(struct pbuf *pbuf)
47*43509a12Srenato {
48*43509a12Srenato 	pbuf->refcnt++;
49*43509a12Srenato 	return (pbuf);
50*43509a12Srenato }
51*43509a12Srenato 
52*43509a12Srenato void
53*43509a12Srenato rtp_buf_release(struct pbuf *pbuf)
54*43509a12Srenato {
55*43509a12Srenato 	if (--pbuf->refcnt == 0) {
56*43509a12Srenato 		ibuf_free(pbuf->buf);
57*43509a12Srenato 		free(pbuf);
58*43509a12Srenato 	}
59*43509a12Srenato }
60*43509a12Srenato 
61*43509a12Srenato struct packet *
62*43509a12Srenato rtp_packet_new(struct nbr *nbr, uint32_t seq_num, struct pbuf *pbuf)
63*43509a12Srenato {
64*43509a12Srenato 	struct packet		*pkt;
65*43509a12Srenato 
66*43509a12Srenato 	if ((pkt = calloc(1, sizeof(struct packet))) == NULL)
67*43509a12Srenato 		fatal("rtp_packet_new");
68*43509a12Srenato 
69*43509a12Srenato 	pkt->nbr = nbr;
70*43509a12Srenato 	pkt->seq_num = seq_num;
71*43509a12Srenato 	pkt->pbuf = rtp_buf_hold(pbuf);
72*43509a12Srenato 	pkt->attempts = 1;
73*43509a12Srenato 	evtimer_set(&pkt->ev_timeout, rtp_retrans_timer, pkt);
74*43509a12Srenato 
75*43509a12Srenato 	return (pkt);
76*43509a12Srenato }
77*43509a12Srenato 
78*43509a12Srenato void
79*43509a12Srenato rtp_packet_del(struct packet *pkt)
80*43509a12Srenato {
81*43509a12Srenato 	TAILQ_REMOVE(&pkt->nbr->retrans_list, pkt, entry);
82*43509a12Srenato 	rtp_retrans_stop_timer(pkt);
83*43509a12Srenato 	rtp_buf_release(pkt->pbuf);
84*43509a12Srenato 	free(pkt);
85*43509a12Srenato }
86*43509a12Srenato 
87*43509a12Srenato void
88*43509a12Srenato rtp_process_ack(struct nbr *nbr, uint32_t ack_num)
89*43509a12Srenato {
90*43509a12Srenato 	struct eigrp	*eigrp = nbr->ei->eigrp;
91*43509a12Srenato 	struct packet	*pkt;
92*43509a12Srenato 
93*43509a12Srenato 	/* window size is one */
94*43509a12Srenato 	pkt = TAILQ_FIRST(&nbr->retrans_list);
95*43509a12Srenato 	if (pkt && pkt->seq_num == ack_num) {
96*43509a12Srenato 		log_debug("%s: nbr %s ack %u", __func__,
97*43509a12Srenato 		    log_addr(eigrp->af, &nbr->addr), ack_num);
98*43509a12Srenato 
99*43509a12Srenato 		/* dequeue packet from retransmission queue */
100*43509a12Srenato 		rtp_packet_del(pkt);
101*43509a12Srenato 
102*43509a12Srenato 		/* enqueue next packet from retransmission queue */
103*43509a12Srenato 		pkt = TAILQ_FIRST(&nbr->retrans_list);
104*43509a12Srenato 		if (pkt)
105*43509a12Srenato 			rtp_send_packet(pkt);
106*43509a12Srenato 	}
107*43509a12Srenato }
108*43509a12Srenato 
109*43509a12Srenato void
110*43509a12Srenato rtp_send_packet(struct packet *pkt)
111*43509a12Srenato {
112*43509a12Srenato 	rtp_retrans_start_timer(pkt);
113*43509a12Srenato 	send_packet(pkt->nbr->ei, pkt->nbr, 0, pkt->pbuf->buf);
114*43509a12Srenato }
115*43509a12Srenato 
116*43509a12Srenato void
117*43509a12Srenato rtp_enqueue_packet(struct packet *pkt)
118*43509a12Srenato {
119*43509a12Srenato 	/* only send packet if transmission queue is empty */
120*43509a12Srenato 	if (TAILQ_EMPTY(&pkt->nbr->retrans_list))
121*43509a12Srenato 		rtp_send_packet(pkt);
122*43509a12Srenato 
123*43509a12Srenato 	TAILQ_INSERT_TAIL(&pkt->nbr->retrans_list, pkt, entry);
124*43509a12Srenato }
125*43509a12Srenato 
126*43509a12Srenato static void
127*43509a12Srenato rtp_seq_inc(struct eigrp *eigrp)
128*43509a12Srenato {
129*43509a12Srenato 	/* automatic wraparound with unsigned arithmetic */
130*43509a12Srenato 	eigrp->seq_num++;
131*43509a12Srenato 
132*43509a12Srenato 	/* sequence number 0 is reserved for unreliably transmission */
133*43509a12Srenato 	if (eigrp->seq_num == 0)
134*43509a12Srenato 		eigrp->seq_num = 1;
135*43509a12Srenato }
136*43509a12Srenato 
137*43509a12Srenato void
138*43509a12Srenato rtp_send_ucast(struct nbr *nbr, struct ibuf *buf)
139*43509a12Srenato {
140*43509a12Srenato 	struct eigrp		*eigrp = nbr->ei->eigrp;
141*43509a12Srenato 	struct packet		*pkt;
142*43509a12Srenato 	struct pbuf		*pbuf;
143*43509a12Srenato 
144*43509a12Srenato 	pbuf = rtp_buf_new(buf);
145*43509a12Srenato 	pkt = rtp_packet_new(nbr, eigrp->seq_num, pbuf);
146*43509a12Srenato 	rtp_enqueue_packet(pkt);
147*43509a12Srenato 	rtp_seq_inc(eigrp);
148*43509a12Srenato }
149*43509a12Srenato 
150*43509a12Srenato void
151*43509a12Srenato rtp_send_mcast(struct eigrp_iface *ei, struct ibuf *buf)
152*43509a12Srenato {
153*43509a12Srenato 	struct eigrp		*eigrp = ei->eigrp;
154*43509a12Srenato 	struct nbr		*nbr;
155*43509a12Srenato 	int			 total = 0, pending = 0;
156*43509a12Srenato 	struct packet		*pkt;
157*43509a12Srenato 	struct pbuf		*pbuf;
158*43509a12Srenato 	uint32_t		 flags = 0;
159*43509a12Srenato 	struct seq_addr_entry	*sa;
160*43509a12Srenato 	struct seq_addr_head	 seq_addr_list;
161*43509a12Srenato 
162*43509a12Srenato 	TAILQ_FOREACH(nbr, &ei->nbr_list, entry) {
163*43509a12Srenato 		if (nbr->flags & F_EIGRP_NBR_SELF)
164*43509a12Srenato 			continue;
165*43509a12Srenato 		if (!TAILQ_EMPTY(&nbr->retrans_list))
166*43509a12Srenato 			pending++;
167*43509a12Srenato 		total++;
168*43509a12Srenato 	}
169*43509a12Srenato 	if (total == 0)
170*43509a12Srenato 		return;
171*43509a12Srenato 
172*43509a12Srenato 	/*
173*43509a12Srenato 	 * send a multicast if there's at least one neighbor with an empty
174*43509a12Srenato 	 * queue on the interface.
175*43509a12Srenato 	 */
176*43509a12Srenato 	if (pending < total) {
177*43509a12Srenato 		/*
178*43509a12Srenato 		 * build a hello packet with a seq tlv indicating all the
179*43509a12Srenato 		 * neighbors that have full queues.
180*43509a12Srenato 		 */
181*43509a12Srenato 		if (pending > 0) {
182*43509a12Srenato 			flags |= EIGRP_HDR_FLAG_CR;
183*43509a12Srenato 			TAILQ_INIT(&seq_addr_list);
184*43509a12Srenato 
185*43509a12Srenato 			TAILQ_FOREACH(nbr, &ei->nbr_list, entry) {
186*43509a12Srenato 				if (TAILQ_EMPTY(&nbr->retrans_list))
187*43509a12Srenato 					continue;
188*43509a12Srenato 				if ((sa = calloc(1, sizeof(*sa))) == NULL)
189*43509a12Srenato 					fatal("rtp_send_mcast");
190*43509a12Srenato 				sa->af = eigrp->af;
191*43509a12Srenato 				memcpy(&sa->addr, &nbr->addr, sizeof(sa->addr));
192*43509a12Srenato 				TAILQ_INSERT_TAIL(&seq_addr_list, sa, entry);
193*43509a12Srenato 			}
194*43509a12Srenato 
195*43509a12Srenato 			send_hello(ei, &seq_addr_list, eigrp->seq_num);
196*43509a12Srenato 			seq_addr_list_clr(&seq_addr_list);
197*43509a12Srenato 		}
198*43509a12Srenato 		send_packet(ei, NULL, flags, buf);
199*43509a12Srenato 	}
200*43509a12Srenato 
201*43509a12Srenato 	/* schedule an unicast retransmission for each neighbor */
202*43509a12Srenato 	pbuf = rtp_buf_new(buf);
203*43509a12Srenato 	TAILQ_FOREACH(nbr, &ei->nbr_list, entry) {
204*43509a12Srenato 		pkt = rtp_packet_new(nbr, eigrp->seq_num, pbuf);
205*43509a12Srenato 		TAILQ_INSERT_TAIL(&nbr->retrans_list, pkt, entry);
206*43509a12Srenato 	}
207*43509a12Srenato 
208*43509a12Srenato 	rtp_seq_inc(eigrp);
209*43509a12Srenato }
210*43509a12Srenato 
211*43509a12Srenato void
212*43509a12Srenato rtp_send(struct eigrp_iface *ei, struct nbr *nbr, struct ibuf *buf)
213*43509a12Srenato {
214*43509a12Srenato 	if (nbr)
215*43509a12Srenato 		rtp_send_ucast(nbr, buf);
216*43509a12Srenato 	else
217*43509a12Srenato 		rtp_send_mcast(ei, buf);
218*43509a12Srenato }
219*43509a12Srenato 
220*43509a12Srenato void
221*43509a12Srenato rtp_send_ack(struct nbr *nbr)
222*43509a12Srenato {
223*43509a12Srenato 	struct eigrp		*eigrp = nbr->ei->eigrp;
224*43509a12Srenato 	struct ibuf		*buf;
225*43509a12Srenato 
226*43509a12Srenato 	if ((buf = ibuf_dynamic(PKG_DEF_SIZE,
227*43509a12Srenato 	    IP_MAXPACKET - sizeof(struct ip))) == NULL)
228*43509a12Srenato 		fatal("rtp_send_ack");
229*43509a12Srenato 
230*43509a12Srenato 	/* EIGRP header */
231*43509a12Srenato 	if (gen_eigrp_hdr(buf, EIGRP_OPC_HELLO, 0, 0, eigrp->as))
232*43509a12Srenato 		goto fail;
233*43509a12Srenato 
234*43509a12Srenato 	/* send unreliably */
235*43509a12Srenato 	send_packet(nbr->ei, nbr, 0, buf);
236*43509a12Srenato 	ibuf_free(buf);
237*43509a12Srenato 	return;
238*43509a12Srenato fail:
239*43509a12Srenato 	log_warnx("%s: failed to send message", __func__);
240*43509a12Srenato 	ibuf_free(buf);
241*43509a12Srenato }
242*43509a12Srenato 
243*43509a12Srenato /* timers */
244*43509a12Srenato 
245*43509a12Srenato /* ARGSUSED */
246*43509a12Srenato void
247*43509a12Srenato rtp_retrans_timer(int fd, short event, void *arg)
248*43509a12Srenato {
249*43509a12Srenato 	struct packet		*pkt = arg;
250*43509a12Srenato 	struct eigrp		*eigrp = pkt->nbr->ei->eigrp;
251*43509a12Srenato 
252*43509a12Srenato 	pkt->attempts++;
253*43509a12Srenato 
254*43509a12Srenato 	if (pkt->attempts > RTP_RTRNS_MAX_ATTEMPTS) {
255*43509a12Srenato 		log_warnx("%s: retry limit exceeded, nbr %s", __func__,
256*43509a12Srenato 		    log_addr(eigrp->af, &pkt->nbr->addr));
257*43509a12Srenato 		nbr_del(pkt->nbr);
258*43509a12Srenato 		return;
259*43509a12Srenato 	}
260*43509a12Srenato 
261*43509a12Srenato 	rtp_send_packet(pkt);
262*43509a12Srenato }
263*43509a12Srenato 
264*43509a12Srenato void
265*43509a12Srenato rtp_retrans_start_timer(struct packet *pkt)
266*43509a12Srenato {
267*43509a12Srenato 	struct timeval		 tv;
268*43509a12Srenato 
269*43509a12Srenato 	timerclear(&tv);
270*43509a12Srenato 	tv.tv_sec = RTP_RTRNS_INTERVAL;
271*43509a12Srenato 	if (evtimer_add(&pkt->ev_timeout, &tv) == -1)
272*43509a12Srenato 		fatal("rtp_retrans_start_timer");
273*43509a12Srenato }
274*43509a12Srenato 
275*43509a12Srenato void
276*43509a12Srenato rtp_retrans_stop_timer(struct packet *pkt)
277*43509a12Srenato {
278*43509a12Srenato 	if (evtimer_pending(&pkt->ev_timeout, NULL) &&
279*43509a12Srenato 	    evtimer_del(&pkt->ev_timeout) == -1)
280*43509a12Srenato 		fatal("rtp_retrans_stop_timer");
281*43509a12Srenato }
282*43509a12Srenato 
283*43509a12Srenato /* ARGSUSED */
284*43509a12Srenato void
285*43509a12Srenato rtp_ack_timer(int fd, short event, void *arg)
286*43509a12Srenato {
287*43509a12Srenato 	struct nbr		*nbr = arg;
288*43509a12Srenato 
289*43509a12Srenato 	rtp_send_ack(nbr);
290*43509a12Srenato }
291*43509a12Srenato 
292*43509a12Srenato void
293*43509a12Srenato rtp_ack_start_timer(struct nbr *nbr)
294*43509a12Srenato {
295*43509a12Srenato 	struct timeval		 tv;
296*43509a12Srenato 
297*43509a12Srenato 	timerclear(&tv);
298*43509a12Srenato 	tv.tv_usec = RTP_ACK_TIMEOUT;
299*43509a12Srenato 	if (evtimer_add(&nbr->ev_ack, &tv) == -1)
300*43509a12Srenato 		fatal("rtp_ack_start_timer");
301*43509a12Srenato }
302*43509a12Srenato 
303*43509a12Srenato void
304*43509a12Srenato rtp_ack_stop_timer(struct nbr *nbr)
305*43509a12Srenato {
306*43509a12Srenato 	if (evtimer_pending(&nbr->ev_ack, NULL) &&
307*43509a12Srenato 	    evtimer_del(&nbr->ev_ack) == -1)
308*43509a12Srenato 		fatal("rtp_ack_stop_timer");
309*43509a12Srenato }
310