GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/eigrpd/rtp.c Lines: 0 110 0.0 %
Date: 2017-11-07 Branches: 0 58 0.0 %

Line Branch Exec Source
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)
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
/* 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_ATTEMPTS) {
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);
276
	tv.tv_sec = RTP_RTRNS_INTERVAL;
277
	if (evtimer_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) &&
285
	    evtimer_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);
304
	tv.tv_usec = RTP_ACK_TIMEOUT;
305
	if (evtimer_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) &&
313
	    evtimer_del(&nbr->ev_ack) == -1)
314
		fatal("rtp_ack_stop_timer");
315
}