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