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