GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ospfd/database.c Lines: 0 183 0.0 %
Date: 2017-11-07 Branches: 0 128 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: database.c,v 1.33 2016/02/18 15:33:24 bluhm Exp $ */
2
3
/*
4
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5
 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
#include <sys/types.h>
21
#include <sys/socket.h>
22
#include <netinet/in.h>
23
#include <netinet/ip.h>
24
#include <arpa/inet.h>
25
#include <stdlib.h>
26
#include <string.h>
27
#include <unistd.h>
28
29
#include "ospfd.h"
30
#include "ospf.h"
31
#include "log.h"
32
#include "ospfe.h"
33
34
extern struct ospfd_conf	*oeconf;
35
36
void	db_sum_list_next(struct nbr *);
37
38
/* database description packet handling */
39
int
40
send_db_description(struct nbr *nbr)
41
{
42
	struct sockaddr_in	 dst;
43
	struct db_dscrp_hdr	 dd_hdr;
44
	struct lsa_entry	*le, *nle;
45
	struct ibuf		*buf;
46
	int			 ret = 0;
47
	u_int8_t		 bits = 0;
48
49
	if ((buf = ibuf_open(nbr->iface->mtu - sizeof(struct ip))) == NULL)
50
		fatal("send_db_description");
51
52
	/* OSPF header */
53
	if (gen_ospf_hdr(buf, nbr->iface, PACKET_TYPE_DD))
54
		goto fail;
55
56
	/* reserve space for database description header */
57
	if (ibuf_reserve(buf, sizeof(dd_hdr)) == NULL)
58
		goto fail;
59
60
	switch (nbr->state) {
61
	case NBR_STA_DOWN:
62
	case NBR_STA_ATTEMPT:
63
	case NBR_STA_INIT:
64
	case NBR_STA_2_WAY:
65
	case NBR_STA_SNAP:
66
		log_debug("send_db_description: neighbor ID %s: "
67
		    "cannot send packet in state %s", inet_ntoa(nbr->id),
68
		    nbr_state_name(nbr->state));
69
		ret = -1;
70
		goto done;
71
	case NBR_STA_XSTRT:
72
		bits |= OSPF_DBD_MS | OSPF_DBD_M | OSPF_DBD_I;
73
		nbr->dd_more = 1;
74
		break;
75
	case NBR_STA_XCHNG:
76
		if (nbr->dd_master)
77
			bits |= OSPF_DBD_MS;
78
		else
79
			bits &= ~OSPF_DBD_MS;
80
81
		if (TAILQ_EMPTY(&nbr->db_sum_list)) {
82
			bits &= ~OSPF_DBD_M;
83
			nbr->dd_more = 0;
84
		} else {
85
			bits |= OSPF_DBD_M;
86
			nbr->dd_more = 1;
87
		}
88
89
		bits &= ~OSPF_DBD_I;
90
91
		/* build LSA list, keep space for a possible md5 sum */
92
		for (le = TAILQ_FIRST(&nbr->db_sum_list); le != NULL &&
93
		    ibuf_left(buf) >= MD5_DIGEST_LENGTH + sizeof(struct lsa_hdr);
94
		    le = nle) {
95
			nbr->dd_end = nle = TAILQ_NEXT(le, entry);
96
			if (ibuf_add(buf, le->le_lsa, sizeof(struct lsa_hdr)))
97
				goto fail;
98
		}
99
		break;
100
	case NBR_STA_LOAD:
101
	case NBR_STA_FULL:
102
		if (nbr->dd_master)
103
			bits |= OSPF_DBD_MS;
104
		else
105
			bits &= ~OSPF_DBD_MS;
106
		bits &= ~OSPF_DBD_M;
107
		bits &= ~OSPF_DBD_I;
108
109
		nbr->dd_more = 0;
110
		break;
111
	default:
112
		fatalx("send_db_description: unknown neighbor state");
113
	}
114
115
	/* set destination */
116
	dst.sin_family = AF_INET;
117
	dst.sin_len = sizeof(struct sockaddr_in);
118
119
	switch (nbr->iface->type) {
120
	case IF_TYPE_POINTOPOINT:
121
		inet_aton(AllSPFRouters, &dst.sin_addr);
122
		dd_hdr.iface_mtu = htons(nbr->iface->mtu);
123
		break;
124
	case IF_TYPE_BROADCAST:
125
		dst.sin_addr = nbr->addr;
126
		dd_hdr.iface_mtu = htons(nbr->iface->mtu);
127
		break;
128
	case IF_TYPE_NBMA:
129
	case IF_TYPE_POINTOMULTIPOINT:
130
		/* XXX not supported */
131
		break;
132
	case IF_TYPE_VIRTUALLINK:
133
		dst.sin_addr = nbr->iface->dst;
134
		dd_hdr.iface_mtu = 0;
135
		break;
136
	default:
137
		fatalx("send_db_description: unknown interface type");
138
	}
139
140
	/* XXX button or not for opaque LSA? */
141
	dd_hdr.opts = area_ospf_options(nbr->iface->area) | OSPF_OPTION_O;
142
	dd_hdr.bits = bits;
143
	dd_hdr.dd_seq_num = htonl(nbr->dd_seq_num);
144
145
	memcpy(ibuf_seek(buf, sizeof(struct ospf_hdr), sizeof(dd_hdr)),
146
	    &dd_hdr, sizeof(dd_hdr));
147
148
	/* update authentication and calculate checksum */
149
	if (auth_gen(buf, nbr->iface))
150
		goto fail;
151
152
	/* transmit packet */
153
	ret = send_packet(nbr->iface, buf, &dst);
154
done:
155
	ibuf_free(buf);
156
	return (ret);
157
fail:
158
	log_warn("send_db_description");
159
	ibuf_free(buf);
160
	return (-1);
161
}
162
163
void
164
recv_db_description(struct nbr *nbr, char *buf, u_int16_t len)
165
{
166
	struct db_dscrp_hdr	 dd_hdr;
167
	int			 dupe = 0;
168
169
	if (len < sizeof(dd_hdr)) {
170
		log_warnx("recv_db_description: neighbor ID %s: "
171
		    "bad packet size", inet_ntoa(nbr->id));
172
		return;
173
	}
174
	memcpy(&dd_hdr, buf, sizeof(dd_hdr));
175
	buf += sizeof(dd_hdr);
176
	len -= sizeof(dd_hdr);
177
178
	/* db description packet sanity checks */
179
	if (ntohs(dd_hdr.iface_mtu) > nbr->iface->mtu) {
180
		log_warnx("recv_db_description: neighbor ID %s: "
181
		    "invalid MTU %d expected %d", inet_ntoa(nbr->id),
182
		    ntohs(dd_hdr.iface_mtu), nbr->iface->mtu);
183
		return;
184
	}
185
186
	if (nbr->last_rx_options == dd_hdr.opts &&
187
	    nbr->last_rx_bits == dd_hdr.bits &&
188
	    ntohl(dd_hdr.dd_seq_num) == nbr->dd_seq_num - nbr->dd_master ?
189
	    1 : 0) {
190
		log_debug("recv_db_description: dupe from neighbor ID %s",
191
		    inet_ntoa(nbr->id));
192
		dupe = 1;
193
	}
194
195
	switch (nbr->state) {
196
	case NBR_STA_DOWN:
197
	case NBR_STA_ATTEMPT:
198
	case NBR_STA_2_WAY:
199
	case NBR_STA_SNAP:
200
		log_debug("recv_db_description: neighbor ID %s: "
201
		    "packet ignored in state %s", inet_ntoa(nbr->id),
202
		    nbr_state_name(nbr->state));
203
		return;
204
	case NBR_STA_INIT:
205
		/* evaluate dr and bdr after issuing a 2-Way event */
206
		nbr_fsm(nbr, NBR_EVT_2_WAY_RCVD);
207
		if_fsm(nbr->iface, IF_EVT_NBR_CHNG);
208
		if (nbr->state != NBR_STA_XSTRT)
209
			return;
210
		/* FALLTHROUGH */
211
	case NBR_STA_XSTRT:
212
		if (dupe)
213
			return;
214
		nbr->capa_options = dd_hdr.opts;
215
		if ((nbr->capa_options & nbr->options) != nbr->options) {
216
			log_warnx("recv_db_description: neighbor ID %s "
217
			    "sent inconsistent options %x vs. %x",
218
			    inet_ntoa(nbr->id), nbr->capa_options,
219
			    nbr->options);
220
		}
221
		/*
222
		 * check bits: either I,M,MS or only M
223
		 */
224
		if (dd_hdr.bits == (OSPF_DBD_I | OSPF_DBD_M | OSPF_DBD_MS)) {
225
			/* if nbr Router ID is larger than own -> slave */
226
			if ((ntohl(nbr->id.s_addr)) >
227
			    ntohl(ospfe_router_id())) {
228
				/* slave */
229
				nbr->dd_master = 0;
230
				nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
231
232
				/* event negotiation done */
233
				nbr_fsm(nbr, NBR_EVT_NEG_DONE);
234
			}
235
		} else if (!(dd_hdr.bits & (OSPF_DBD_I | OSPF_DBD_MS))) {
236
			/* M only case: we are master */
237
			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
238
				log_warnx("recv_db_description: "
239
				    "neighbor ID %s: "
240
				    "invalid seq num, mine %x his %x",
241
				    inet_ntoa(nbr->id), nbr->dd_seq_num,
242
				    ntohl(dd_hdr.dd_seq_num));
243
				return;
244
			}
245
			nbr->dd_seq_num++;
246
247
			/* event negotiation done */
248
			nbr_fsm(nbr, NBR_EVT_NEG_DONE);
249
250
			/* this packet may already have data so pass it on */
251
			if (len > 0) {
252
				nbr->dd_pending++;
253
				ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid,
254
				    0, buf, len);
255
			}
256
		} else {
257
			/* ignore packet */
258
			log_debug("recv_db_description: neighbor ID %s: "
259
			    "packet ignored in state %s (bad flags)",
260
			    inet_ntoa(nbr->id), nbr_state_name(nbr->state));
261
		}
262
		break;
263
	case NBR_STA_XCHNG:
264
	case NBR_STA_LOAD:
265
	case NBR_STA_FULL:
266
		if (dd_hdr.bits & OSPF_DBD_I ||
267
		    !(dd_hdr.bits & OSPF_DBD_MS) == !nbr->dd_master) {
268
			log_warnx("recv_db_description: neighbor ID %s: "
269
			    "seq num mismatch, bad flags", inet_ntoa(nbr->id));
270
			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
271
			return;
272
		}
273
274
		if (nbr->last_rx_options != dd_hdr.opts) {
275
			log_warnx("recv_db_description: neighbor ID %s: "
276
			    "seq num mismatch, bad options",
277
			    inet_ntoa(nbr->id));
278
			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
279
			return;
280
		}
281
282
		if (dupe) {
283
			if (!nbr->dd_master)
284
				/* retransmit */
285
				start_db_tx_timer(nbr);
286
			return;
287
		}
288
289
		if (nbr->state != NBR_STA_XCHNG) {
290
			log_warnx("recv_db_description: neighbor ID %s: "
291
			    "invalid seq num, mine %x his %x",
292
			    inet_ntoa(nbr->id), nbr->dd_seq_num,
293
			    ntohl(dd_hdr.dd_seq_num));
294
			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
295
			return;
296
		}
297
298
		/* sanity check dd seq number */
299
		if (nbr->dd_master) {
300
			/* master */
301
			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
302
				log_warnx("recv_db_description: "
303
				    "neighbor ID %s: "
304
				    "invalid seq num, mine %x his %x, master",
305
				    inet_ntoa(nbr->id), nbr->dd_seq_num,
306
				    ntohl(dd_hdr.dd_seq_num));
307
				nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
308
				return;
309
			}
310
			nbr->dd_seq_num++;
311
		} else {
312
			/* slave */
313
			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num + 1) {
314
				log_warnx("recv_db_description: "
315
				    "neighbor ID %s: "
316
				    "invalid seq num, mine %x his %x, slave",
317
				    inet_ntoa(nbr->id), nbr->dd_seq_num,
318
				    ntohl(dd_hdr.dd_seq_num));
319
				nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
320
				return;
321
			}
322
			nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
323
		}
324
325
		/* forward to RDE and let it decide which LSAs to request */
326
		if (len > 0) {
327
			nbr->dd_pending++;
328
			ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid, 0,
329
			    buf, len);
330
		}
331
332
		/* next packet */
333
		db_sum_list_next(nbr);
334
		start_db_tx_timer(nbr);
335
336
		if (!(dd_hdr.bits & OSPF_DBD_M) &&
337
		    TAILQ_EMPTY(&nbr->db_sum_list))
338
			if (!nbr->dd_master || !nbr->dd_more)
339
				nbr_fsm(nbr, NBR_EVT_XCHNG_DONE);
340
		break;
341
	default:
342
		fatalx("recv_db_description: unknown neighbor state");
343
	}
344
345
	nbr->last_rx_options = dd_hdr.opts;
346
	nbr->last_rx_bits = dd_hdr.bits;
347
}
348
349
void
350
db_sum_list_add(struct nbr *nbr, struct lsa_hdr *lsa)
351
{
352
	struct lsa_entry	*le;
353
354
	if ((le = calloc(1, sizeof(*le))) == NULL)
355
		fatal("db_sum_list_add");
356
357
	TAILQ_INSERT_TAIL(&nbr->db_sum_list, le, entry);
358
	le->le_lsa = lsa;
359
}
360
361
void
362
db_sum_list_next(struct nbr *nbr)
363
{
364
	struct lsa_entry	*le;
365
366
	while ((le = TAILQ_FIRST(&nbr->db_sum_list)) != nbr->dd_end) {
367
		TAILQ_REMOVE(&nbr->db_sum_list, le, entry);
368
		free(le->le_lsa);
369
		free(le);
370
	}
371
}
372
373
void
374
db_sum_list_clr(struct nbr *nbr)
375
{
376
	nbr->dd_end = NULL;
377
	db_sum_list_next(nbr);
378
}
379
380
/* timers */
381
/* ARGSUSED */
382
void
383
db_tx_timer(int fd, short event, void *arg)
384
{
385
	struct nbr *nbr = arg;
386
	struct timeval tv;
387
388
	switch (nbr->state) {
389
	case NBR_STA_DOWN:
390
	case NBR_STA_ATTEMPT:
391
	case NBR_STA_INIT:
392
	case NBR_STA_2_WAY:
393
	case NBR_STA_SNAP:
394
		return ;
395
	case NBR_STA_XSTRT:
396
	case NBR_STA_XCHNG:
397
	case NBR_STA_LOAD:
398
	case NBR_STA_FULL:
399
		send_db_description(nbr);
400
		break;
401
	default:
402
		log_debug("db_tx_timer: neighbor ID %s: unknown neighbor state",
403
		    inet_ntoa(nbr->id));
404
		break;
405
	}
406
407
	/* reschedule db_tx_timer but only in master mode */
408
	if (nbr->dd_master) {
409
		timerclear(&tv);
410
		tv.tv_sec = nbr->iface->rxmt_interval;
411
		if (evtimer_add(&nbr->db_tx_timer, &tv) == -1)
412
			fatal("db_tx_timer");
413
	}
414
}
415
416
void
417
start_db_tx_timer(struct nbr *nbr)
418
{
419
	struct timeval	tv;
420
421
	if (nbr == nbr->iface->self)
422
		return;
423
424
	timerclear(&tv);
425
	if (evtimer_add(&nbr->db_tx_timer, &tv) == -1)
426
		fatal("start_db_tx_timer");
427
}
428
429
void
430
stop_db_tx_timer(struct nbr *nbr)
431
{
432
	if (nbr == nbr->iface->self)
433
		return;
434
435
	if (evtimer_del(&nbr->db_tx_timer) == -1)
436
		fatal("stop_db_tx_timer");
437
}