| File: | src/usr.sbin/eigrpd/rtp.c |
| Warning: | line 215, column 2 Potential leak of memory pointed to by 'pbuf' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: rtp.c,v 1.7 2016/09/02 16:44:33 renato 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((void *)0)) | |||
| 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((void *)0)) | |||
| 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)event_set(&pkt->ev_timeout, -1, 0, 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)do { if (((pkt)->entry.tqe_next) != ((void *)0)) (pkt)-> entry.tqe_next->entry.tqe_prev = (pkt)->entry.tqe_prev; else (&pkt->nbr->retrans_list)->tqh_last = (pkt )->entry.tqe_prev; *(pkt)->entry.tqe_prev = (pkt)->entry .tqe_next; ; ; } while (0); | |||
| 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)((&nbr->retrans_list)->tqh_first); | |||
| 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)((&nbr->retrans_list)->tqh_first); | |||
| 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)(((&pkt->nbr->retrans_list)->tqh_first) == ((void *)0))) | |||
| 128 | rtp_send_packet(pkt); | |||
| 129 | ||||
| 130 | TAILQ_INSERT_TAIL(&pkt->nbr->retrans_list, pkt, entry)do { (pkt)->entry.tqe_next = ((void *)0); (pkt)->entry. tqe_prev = (&pkt->nbr->retrans_list)->tqh_last; * (&pkt->nbr->retrans_list)->tqh_last = (pkt); (& pkt->nbr->retrans_list)->tqh_last = &(pkt)->entry .tqe_next; } while (0); | |||
| 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)for((nbr) = ((&ei->nbr_list)->tqh_first); (nbr) != ( (void *)0); (nbr) = ((nbr)->entry.tqe_next)) { | |||
| 170 | if (nbr->flags & F_EIGRP_NBR_SELF0x01) | |||
| 171 | continue; | |||
| 172 | if (!TAILQ_EMPTY(&nbr->retrans_list)(((&nbr->retrans_list)->tqh_first) == ((void *)0))) | |||
| 173 | pending++; | |||
| 174 | total++; | |||
| 175 | } | |||
| 176 | if (total
| |||
| 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
| |||
| 184 | /* | |||
| 185 | * build a hello packet with a seq tlv indicating all the | |||
| 186 | * neighbors that have full queues. | |||
| 187 | */ | |||
| 188 | if (pending
| |||
| 189 | flags |= EIGRP_HDR_FLAG_CR0x02; | |||
| 190 | TAILQ_INIT(&seq_addr_list)do { (&seq_addr_list)->tqh_first = ((void *)0); (& seq_addr_list)->tqh_last = &(&seq_addr_list)->tqh_first ; } while (0); | |||
| 191 | ||||
| 192 | TAILQ_FOREACH(nbr, &ei->nbr_list, entry)for((nbr) = ((&ei->nbr_list)->tqh_first); (nbr) != ( (void *)0); (nbr) = ((nbr)->entry.tqe_next)) { | |||
| 193 | if (TAILQ_EMPTY(&nbr->retrans_list)(((&nbr->retrans_list)->tqh_first) == ((void *)0))) | |||
| 194 | continue; | |||
| 195 | if ((sa = calloc(1, sizeof(*sa))) == NULL((void *)0)) | |||
| 196 | fatal("rtp_send_mcast"); | |||
| 197 | sa->af = eigrp->af; | |||
| 198 | sa->addr = nbr->addr; | |||
| 199 | TAILQ_INSERT_TAIL(&seq_addr_list, sa, entry)do { (sa)->entry.tqe_next = ((void *)0); (sa)->entry.tqe_prev = (&seq_addr_list)->tqh_last; *(&seq_addr_list)-> tqh_last = (sa); (&seq_addr_list)->tqh_last = &(sa )->entry.tqe_next; } while (0); | |||
| 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((void *)0), 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)for((nbr) = ((&ei->nbr_list)->tqh_first); (nbr) != ( (void *)0); (nbr) = ((nbr)->entry.tqe_next)) { | |||
| 211 | pkt = rtp_packet_new(nbr, eigrp->seq_num, pbuf); | |||
| 212 | TAILQ_INSERT_TAIL(&nbr->retrans_list, pkt, entry)do { (pkt)->entry.tqe_next = ((void *)0); (pkt)->entry. tqe_prev = (&nbr->retrans_list)->tqh_last; *(&nbr ->retrans_list)->tqh_last = (pkt); (&nbr->retrans_list )->tqh_last = &(pkt)->entry.tqe_next; } while (0); | |||
| 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_SIZE512, | |||
| 234 | IP_MAXPACKET65535 - sizeof(struct ip))) == NULL((void *)0)) | |||
| 235 | fatal("rtp_send_ack"); | |||
| 236 | ||||
| 237 | /* EIGRP header */ | |||
| 238 | if (gen_eigrp_hdr(buf, EIGRP_OPC_HELLO5, 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 | /* ARGSUSED */ | |||
| 252 | static void | |||
| 253 | rtp_retrans_timer(int fd, short event, void *arg) | |||
| 254 | { | |||
| 255 | struct packet *pkt = arg; | |||
| 256 | struct eigrp *eigrp = pkt->nbr->ei->eigrp; | |||
| 257 | ||||
| 258 | pkt->attempts++; | |||
| 259 | ||||
| 260 | if (pkt->attempts > RTP_RTRNS_MAX_ATTEMPTS16) { | |||
| 261 | log_warnx("%s: retry limit exceeded, nbr %s", __func__, | |||
| 262 | log_addr(eigrp->af, &pkt->nbr->addr)); | |||
| 263 | nbr_del(pkt->nbr); | |||
| 264 | return; | |||
| 265 | } | |||
| 266 | ||||
| 267 | rtp_send_packet(pkt); | |||
| 268 | } | |||
| 269 | ||||
| 270 | static void | |||
| 271 | rtp_retrans_start_timer(struct packet *pkt) | |||
| 272 | { | |||
| 273 | struct timeval tv; | |||
| 274 | ||||
| 275 | timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0; | |||
| 276 | tv.tv_sec = RTP_RTRNS_INTERVAL5; | |||
| 277 | if (evtimer_add(&pkt->ev_timeout, &tv)event_add(&pkt->ev_timeout, &tv) == -1) | |||
| 278 | fatal("rtp_retrans_start_timer"); | |||
| 279 | } | |||
| 280 | ||||
| 281 | static void | |||
| 282 | rtp_retrans_stop_timer(struct packet *pkt) | |||
| 283 | { | |||
| 284 | if (evtimer_pending(&pkt->ev_timeout, NULL)event_pending(&pkt->ev_timeout, 0x01, ((void *)0)) && | |||
| 285 | evtimer_del(&pkt->ev_timeout)event_del(&pkt->ev_timeout) == -1) | |||
| 286 | fatal("rtp_retrans_stop_timer"); | |||
| 287 | } | |||
| 288 | ||||
| 289 | /* ARGSUSED */ | |||
| 290 | void | |||
| 291 | rtp_ack_timer(int fd, short event, void *arg) | |||
| 292 | { | |||
| 293 | struct nbr *nbr = arg; | |||
| 294 | ||||
| 295 | rtp_send_ack(nbr); | |||
| 296 | } | |||
| 297 | ||||
| 298 | void | |||
| 299 | rtp_ack_start_timer(struct nbr *nbr) | |||
| 300 | { | |||
| 301 | struct timeval tv; | |||
| 302 | ||||
| 303 | timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0; | |||
| 304 | tv.tv_usec = RTP_ACK_TIMEOUT100000; | |||
| 305 | if (evtimer_add(&nbr->ev_ack, &tv)event_add(&nbr->ev_ack, &tv) == -1) | |||
| 306 | fatal("rtp_ack_start_timer"); | |||
| 307 | } | |||
| 308 | ||||
| 309 | void | |||
| 310 | rtp_ack_stop_timer(struct nbr *nbr) | |||
| 311 | { | |||
| 312 | if (evtimer_pending(&nbr->ev_ack, NULL)event_pending(&nbr->ev_ack, 0x01, ((void *)0)) && | |||
| 313 | evtimer_del(&nbr->ev_ack)event_del(&nbr->ev_ack) == -1) | |||
| 314 | fatal("rtp_ack_stop_timer"); | |||
| 315 | } |