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.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((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 | 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_ATTEMPTS16) { | |||
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)(&tv)->tv_sec = (&tv)->tv_usec = 0; | |||
275 | tv.tv_sec = RTP_RTRNS_INTERVAL5; | |||
276 | if (evtimer_add(&pkt->ev_timeout, &tv)event_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)event_pending(&pkt->ev_timeout, 0x01, ((void *)0)) && | |||
284 | evtimer_del(&pkt->ev_timeout)event_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)(&tv)->tv_sec = (&tv)->tv_usec = 0; | |||
302 | tv.tv_usec = RTP_ACK_TIMEOUT100000; | |||
303 | if (evtimer_add(&nbr->ev_ack, &tv)event_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)event_pending(&nbr->ev_ack, 0x01, ((void *)0)) && | |||
311 | evtimer_del(&nbr->ev_ack)event_del(&nbr->ev_ack) == -1) | |||
312 | fatal("rtp_ack_stop_timer"); | |||
313 | } |