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 * 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 * 53 rtp_buf_hold(struct pbuf *pbuf) 54 { 55 pbuf->refcnt++; 56 return (pbuf); 57 } 58 59 static void 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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