GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ospfd/lsack.c Lines: 3 122 2.5 %
Date: 2017-11-13 Branches: 1 82 1.2 %

Line Branch Exec Source
1
/*	$OpenBSD: lsack.c,v 1.21 2014/10/25 03:23:49 lteo Exp $ */
2
3
/*
4
 * Copyright (c) 2004, 2005 Esben Norby <norby@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 <sys/socket.h>
21
#include <netinet/in.h>
22
#include <netinet/ip.h>
23
#include <arpa/inet.h>
24
25
#include <stdlib.h>
26
#include <string.h>
27
28
#include "ospfd.h"
29
#include "ospf.h"
30
#include "log.h"
31
#include "ospfe.h"
32
33
int		 send_ls_ack(struct iface *, struct in_addr, struct ibuf *);
34
struct ibuf	*prepare_ls_ack(struct iface *);
35
void		 start_ls_ack_tx_timer_now(struct iface *);
36
37
/* link state acknowledgement packet handling */
38
struct ibuf *
39
prepare_ls_ack(struct iface *iface)
40
{
41
	struct ibuf	*buf;
42
43
	if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL) {
44
		log_warn("prepare_ls_ack");
45
		return (NULL);
46
	}
47
48
	/* OSPF header */
49
	if (gen_ospf_hdr(buf, iface, PACKET_TYPE_LS_ACK)) {
50
		log_warn("prepare_ls_ack");
51
		ibuf_free(buf);
52
		return (NULL);
53
	}
54
55
	return (buf);
56
}
57
58
int
59
send_ls_ack(struct iface *iface, struct in_addr addr, struct ibuf *buf)
60
{
61
	struct sockaddr_in	dst;
62
	int			ret;
63
64
	/* update authentication and calculate checksum */
65
	if (auth_gen(buf, iface)) {
66
		log_warn("send_ls_ack");
67
		return (-1);
68
	}
69
70
	dst.sin_family = AF_INET;
71
	dst.sin_len = sizeof(struct sockaddr_in);
72
	dst.sin_addr.s_addr = addr.s_addr;
73
74
	ret = send_packet(iface, buf, &dst);
75
	return (ret);
76
}
77
78
int
79
send_direct_ack(struct iface *iface, struct in_addr addr, void *d, size_t len)
80
{
81
	struct ibuf	*buf;
82
	int		 ret;
83
84
	if ((buf = prepare_ls_ack(iface)) == NULL)
85
		return (-1);
86
87
	/* LS ack(s) */
88
	if (ibuf_add(buf, d, len)) {
89
		log_warn("send_direct_ack");
90
		ibuf_free(buf);
91
		return (-1);
92
	}
93
94
	ret = send_ls_ack(iface, addr, buf);
95
	ibuf_free(buf);
96
	return (ret);
97
}
98
99
void
100
recv_ls_ack(struct nbr *nbr, char *buf, u_int16_t len)
101
{
102
	struct lsa_hdr	 lsa_hdr;
103
104
	switch (nbr->state) {
105
	case NBR_STA_DOWN:
106
	case NBR_STA_ATTEMPT:
107
	case NBR_STA_INIT:
108
	case NBR_STA_2_WAY:
109
	case NBR_STA_XSTRT:
110
	case NBR_STA_SNAP:
111
		log_debug("recv_ls_ack: packet ignored in state %s, "
112
		    "neighbor ID %s", nbr_state_name(nbr->state),
113
		    inet_ntoa(nbr->id));
114
		break;
115
	case NBR_STA_XCHNG:
116
	case NBR_STA_LOAD:
117
	case NBR_STA_FULL:
118
		while (len >= sizeof(lsa_hdr)) {
119
			memcpy(&lsa_hdr, buf, sizeof(lsa_hdr));
120
121
			if (lsa_hdr_check(nbr, &lsa_hdr)) {
122
				/* try both list in case of DROTHER */
123
				if (nbr->iface->state & IF_STA_DROTHER)
124
					(void)ls_retrans_list_del(
125
					    nbr->iface->self, &lsa_hdr);
126
				(void)ls_retrans_list_del(nbr, &lsa_hdr);
127
			}
128
129
			buf += sizeof(lsa_hdr);
130
			len -= sizeof(lsa_hdr);
131
		}
132
		if (len > 0) {
133
			log_warnx("recv_ls_ack: bad packet size, "
134
			    "neighbor ID %s", inet_ntoa(nbr->id));
135
			return;
136
		}
137
		break;
138
	default:
139
		fatalx("recv_ls_ack: unknown neighbor state");
140
	}
141
}
142
143
int
144
lsa_hdr_check(struct nbr *nbr, struct lsa_hdr *lsa_hdr)
145
{
146
	/* invalid age */
147
	if ((ntohs(lsa_hdr->age) < 1) || (ntohs(lsa_hdr->age) > MAX_AGE)) {
148
		log_debug("lsa_hdr_check: invalid age, neighbor ID %s",
149
		     inet_ntoa(nbr->id));
150
		return (0);
151
	}
152
153
	/* invalid type */
154
	switch (lsa_hdr->type) {
155
	case LSA_TYPE_ROUTER:
156
	case LSA_TYPE_NETWORK:
157
	case LSA_TYPE_SUM_NETWORK:
158
	case LSA_TYPE_SUM_ROUTER:
159
	case LSA_TYPE_EXTERNAL:
160
		break;
161
	default:
162
		log_debug("lsa_hdr_check: invalid LSA type %d, neighbor ID %s",
163
		    lsa_hdr->type, inet_ntoa(nbr->id));
164
		return (0);
165
	}
166
167
	/* invalid sequence number */
168
	if (ntohl(lsa_hdr->seq_num) == RESV_SEQ_NUM) {
169
		log_debug("ls_hdr_check: invalid seq num, neighbor ID %s",
170
			inet_ntoa(nbr->id));
171
		return (0);
172
	}
173
174
	return (1);
175
}
176
177
/* link state ack list */
178
void
179
ls_ack_list_add(struct iface *iface, struct lsa_hdr *lsa)
180
{
181
	struct lsa_entry	*le;
182
183
	if (lsa == NULL)
184
		fatalx("ls_ack_list_add: no LSA header");
185
186
	if ((le = calloc(1, sizeof(*le))) == NULL)
187
		fatal("ls_ack_list_add");
188
189
	if (ls_ack_list_empty(iface))
190
		start_ls_ack_tx_timer(iface);
191
192
	TAILQ_INSERT_TAIL(&iface->ls_ack_list, le, entry);
193
	le->le_lsa = lsa;
194
	iface->ls_ack_cnt++;
195
196
	/* reschedule now if we have enough for a reasonably sized packet */
197
	if (iface->ls_ack_cnt > IP_MSS / sizeof(struct lsa_hdr))
198
		start_ls_ack_tx_timer_now(iface);
199
}
200
201
void
202
ls_ack_list_free(struct iface *iface, struct lsa_entry *le)
203
{
204
	TAILQ_REMOVE(&iface->ls_ack_list, le, entry);
205
	free(le->le_lsa);
206
	free(le);
207
208
	iface->ls_ack_cnt--;
209
}
210
211
void
212
ls_ack_list_clr(struct iface *iface)
213
{
214
	struct lsa_entry	*le;
215
216
72
	while ((le = TAILQ_FIRST(&iface->ls_ack_list)) != NULL) {
217
		TAILQ_REMOVE(&iface->ls_ack_list, le, entry);
218
		free(le->le_lsa);
219
		free(le);
220
	}
221
24
	iface->ls_ack_cnt = 0;
222
24
}
223
224
int
225
ls_ack_list_empty(struct iface *iface)
226
{
227
	return (TAILQ_EMPTY(&iface->ls_ack_list));
228
}
229
230
/* timers */
231
/* ARGSUSED */
232
void
233
ls_ack_tx_timer(int fd, short event, void *arg)
234
{
235
	struct in_addr		 addr;
236
	struct iface		*iface = arg;
237
	struct lsa_entry	*le, *nle;
238
	struct nbr		*nbr;
239
	struct ibuf		*buf;
240
	int			 cnt;
241
242
	while (!ls_ack_list_empty(iface)) {
243
		if ((buf = prepare_ls_ack(iface)) == NULL)
244
			fatal("ls_ack_tx_timer");
245
		cnt = 0;
246
247
		for (le = TAILQ_FIRST(&iface->ls_ack_list); le != NULL;
248
		    le = nle) {
249
			nle = TAILQ_NEXT(le, entry);
250
			if (ibuf_left(buf) < sizeof(struct lsa_hdr) +
251
			    MD5_DIGEST_LENGTH)
252
				break;
253
			if (ibuf_add(buf, le->le_lsa, sizeof(struct lsa_hdr)))
254
				break;
255
			ls_ack_list_free(iface, le);
256
			cnt++;
257
		}
258
		if (cnt == 0) {
259
			log_warnx("ls_ack_tx_timer: lost in space");
260
			ibuf_free(buf);
261
			return;
262
		}
263
264
		/* send LS ack(s) but first set correct destination */
265
		switch (iface->type) {
266
		case IF_TYPE_POINTOPOINT:
267
			inet_aton(AllSPFRouters, &addr);
268
			send_ls_ack(iface, addr, buf);
269
			break;
270
		case IF_TYPE_BROADCAST:
271
			if (iface->state & IF_STA_DRORBDR)
272
				inet_aton(AllSPFRouters, &addr);
273
			else
274
				inet_aton(AllDRouters, &addr);
275
			send_ls_ack(iface, addr, buf);
276
			break;
277
		case IF_TYPE_NBMA:
278
		case IF_TYPE_POINTOMULTIPOINT:
279
		case IF_TYPE_VIRTUALLINK:
280
			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
281
				if (nbr == iface->self)
282
					continue;
283
				if (!(nbr->state & NBR_STA_FLOOD))
284
					continue;
285
				send_ls_ack(iface, nbr->addr, buf);
286
			}
287
			break;
288
		default:
289
			fatalx("lsa_ack_tx_timer: unknown interface type");
290
		}
291
		ibuf_free(buf);
292
	}
293
}
294
295
void
296
start_ls_ack_tx_timer(struct iface *iface)
297
{
298
	struct timeval tv;
299
300
	timerclear(&tv);
301
	tv.tv_sec = iface->rxmt_interval / 2;
302
303
	if (evtimer_add(&iface->lsack_tx_timer, &tv) == -1)
304
		fatal("start_ls_ack_tx_timer");
305
}
306
307
void
308
start_ls_ack_tx_timer_now(struct iface *iface)
309
{
310
	struct timeval tv;
311
312
	timerclear(&tv);
313
	if (evtimer_add(&iface->lsack_tx_timer, &tv) == -1)
314
		fatal("start_ls_ack_tx_timer_now");
315
}
316
317
void
318
stop_ls_ack_tx_timer(struct iface *iface)
319
{
320
	if (evtimer_del(&iface->lsack_tx_timer) == -1)
321
		fatal("stop_ls_ack_tx_timer");
322
}