"Fossies" - the Fresh Open Source Software Archive 
Member "ospfd/database.c" (31 Jan 2009, 10396 Bytes) of package /linux/privat/old/openospfd-4.6.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "database.c" see the
Fossies "Dox" file reference documentation.
1 /* $OpenBSD: database.c,v 1.26 2009/01/31 11:44:49 claudio 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/in_systm.h>
24 #include <netinet/ip.h>
25 #include <arpa/inet.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include "ospfd.h"
31 #include "ospf.h"
32 #include "log.h"
33 #include "ospfe.h"
34
35 extern struct ospfd_conf *oeconf;
36
37 void db_sum_list_next(struct nbr *);
38
39 /* database description packet handling */
40 int
41 send_db_description(struct nbr *nbr)
42 {
43 struct sockaddr_in dst;
44 struct db_dscrp_hdr dd_hdr;
45 struct lsa_entry *le, *nle;
46 struct buf *buf;
47 int ret = 0;
48 u_int8_t bits = 0;
49
50 if ((buf = buf_open(nbr->iface->mtu - sizeof(struct ip))) == NULL)
51 fatal("send_db_description");
52
53 /* OSPF header */
54 if (gen_ospf_hdr(buf, nbr->iface, PACKET_TYPE_DD))
55 goto fail;
56
57 /* reserve space for database description header */
58 if (buf_reserve(buf, sizeof(dd_hdr)) == NULL)
59 goto fail;
60
61 switch (nbr->state) {
62 case NBR_STA_DOWN:
63 case NBR_STA_ATTEMPT:
64 case NBR_STA_INIT:
65 case NBR_STA_2_WAY:
66 case NBR_STA_SNAP:
67 log_debug("send_db_description: cannot send packet in state %s,"
68 " neighbor ID %s", nbr_state_name(nbr->state),
69 inet_ntoa(nbr->id));
70 ret = -1;
71 goto done;
72 case NBR_STA_XSTRT:
73 bits |= OSPF_DBD_MS | OSPF_DBD_M | OSPF_DBD_I;
74 nbr->dd_more = 1;
75 break;
76 case NBR_STA_XCHNG:
77 if (nbr->dd_master)
78 bits |= OSPF_DBD_MS;
79 else
80 bits &= ~OSPF_DBD_MS;
81
82 if (TAILQ_EMPTY(&nbr->db_sum_list)) {
83 bits &= ~OSPF_DBD_M;
84 nbr->dd_more = 0;
85 } else {
86 bits |= OSPF_DBD_M;
87 nbr->dd_more = 1;
88 }
89
90 bits &= ~OSPF_DBD_I;
91
92 /* build LSA list, keep space for a possible md5 sum */
93 for (le = TAILQ_FIRST(&nbr->db_sum_list); le != NULL &&
94 buf_left(buf) >= MD5_DIGEST_LENGTH + sizeof(struct lsa_hdr);
95 le = nle) {
96 nbr->dd_end = nle = TAILQ_NEXT(le, entry);
97 if (buf_add(buf, le->le_lsa, sizeof(struct lsa_hdr)))
98 goto fail;
99 }
100 break;
101 case NBR_STA_LOAD:
102 case NBR_STA_FULL:
103 if (nbr->dd_master)
104 bits |= OSPF_DBD_MS;
105 else
106 bits &= ~OSPF_DBD_MS;
107 bits &= ~OSPF_DBD_M;
108 bits &= ~OSPF_DBD_I;
109
110 nbr->dd_more = 0;
111 break;
112 default:
113 fatalx("send_db_description: unknown neighbor state");
114 }
115
116 /* set destination */
117 dst.sin_family = AF_INET;
118 dst.sin_len = sizeof(struct sockaddr_in);
119
120 switch (nbr->iface->type) {
121 case IF_TYPE_POINTOPOINT:
122 inet_aton(AllSPFRouters, &dst.sin_addr);
123 dd_hdr.iface_mtu = htons(nbr->iface->mtu);
124 break;
125 case IF_TYPE_BROADCAST:
126 dst.sin_addr = nbr->addr;
127 dd_hdr.iface_mtu = htons(nbr->iface->mtu);
128 break;
129 case IF_TYPE_NBMA:
130 case IF_TYPE_POINTOMULTIPOINT:
131 /* XXX not supported */
132 break;
133 case IF_TYPE_VIRTUALLINK:
134 dst.sin_addr = nbr->iface->dst;
135 dd_hdr.iface_mtu = 0;
136 break;
137 default:
138 fatalx("send_db_description: unknown interface type");
139 }
140
141 dd_hdr.opts = area_ospf_options(nbr->iface->area);
142 dd_hdr.bits = bits;
143 dd_hdr.dd_seq_num = htonl(nbr->dd_seq_num);
144
145 memcpy(buf_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 buf_free(buf);
156 return (ret);
157 fail:
158 log_warn("send_db_description");
159 buf_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: "
171 "bad packet size, neighbor ID %s", 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: invalid MTU %d sent by "
181 "neighbor ID %s, expected %d", ntohs(dd_hdr.iface_mtu),
182 inet_ntoa(nbr->id), 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 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: packet ignored in state %s, "
201 "neighbor ID %s", nbr_state_name(nbr->state),
202 inet_ntoa(nbr->id));
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 /*
215 * check bits: either I,M,MS or only M
216 */
217 if (dd_hdr.bits == (OSPF_DBD_I | OSPF_DBD_M | OSPF_DBD_MS)) {
218 /* if nbr Router ID is larger than own -> slave */
219 if ((ntohl(nbr->id.s_addr)) >
220 ntohl(ospfe_router_id())) {
221 /* slave */
222 nbr->dd_master = 0;
223 nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
224
225 /* event negotiation done */
226 nbr_fsm(nbr, NBR_EVT_NEG_DONE);
227 }
228 } else if (!(dd_hdr.bits & (OSPF_DBD_I | OSPF_DBD_MS))) {
229 /* M only case: we are master */
230 if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
231 log_warnx("recv_db_description: invalid "
232 "seq num, mine %x his %x",
233 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
234 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
235 return;
236 }
237 nbr->dd_seq_num++;
238
239 /* event negotiation done */
240 nbr_fsm(nbr, NBR_EVT_NEG_DONE);
241
242 /* this packet may already have data so pass it on */
243 if (len > 0) {
244 nbr->dd_pending++;
245 ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid,
246 0, buf, len);
247 }
248 } else {
249 /* ignore packet */
250 log_debug("recv_db_description: packet ignored in "
251 "state %s (bad flags), neighbor ID %s",
252 nbr_state_name(nbr->state), inet_ntoa(nbr->id));
253 }
254 break;
255 case NBR_STA_XCHNG:
256 case NBR_STA_LOAD:
257 case NBR_STA_FULL:
258 if (dd_hdr.bits & OSPF_DBD_I ||
259 !(dd_hdr.bits & OSPF_DBD_MS) == !nbr->dd_master) {
260 log_warnx("recv_db_description: seq num mismatch, "
261 "bad flags");
262 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
263 return;
264 }
265
266 if (nbr->last_rx_options != dd_hdr.opts) {
267 log_warnx("recv_db_description: seq num mismatch, "
268 "bad options");
269 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
270 return;
271 }
272
273 if (dupe) {
274 if (!nbr->dd_master)
275 /* retransmit */
276 start_db_tx_timer(nbr);
277 return;
278 }
279
280 if (nbr->state != NBR_STA_XCHNG) {
281 log_warnx("recv_db_description: invalid "
282 "seq num, mine %x his %x",
283 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
284 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
285 return;
286 }
287
288 /* sanity check dd seq number */
289 if (nbr->dd_master) {
290 /* master */
291 if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
292 log_warnx("recv_db_description: invalid "
293 "seq num, mine %x his %x",
294 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
295 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
296 return;
297 }
298 nbr->dd_seq_num++;
299 } else {
300 /* slave */
301 if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num + 1) {
302 log_warnx("recv_db_description: invalid "
303 "seq num, mine %x his %x",
304 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
305 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
306 return;
307 }
308 nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
309 }
310
311 /* forward to RDE and let it decide which LSAs to request */
312 if (len > 0) {
313 nbr->dd_pending++;
314 ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid, 0,
315 buf, len);
316 }
317
318 /* next packet */
319 db_sum_list_next(nbr);
320 start_db_tx_timer(nbr);
321
322 if (!(dd_hdr.bits & OSPF_DBD_M) &&
323 TAILQ_EMPTY(&nbr->db_sum_list))
324 if (!nbr->dd_master || !nbr->dd_more)
325 nbr_fsm(nbr, NBR_EVT_XCHNG_DONE);
326 break;
327 default:
328 fatalx("recv_db_description: unknown neighbor state");
329 }
330
331 nbr->last_rx_options = dd_hdr.opts;
332 nbr->last_rx_bits = dd_hdr.bits;
333 }
334
335 void
336 db_sum_list_add(struct nbr *nbr, struct lsa_hdr *lsa)
337 {
338 struct lsa_entry *le;
339
340 if ((le = calloc(1, sizeof(*le))) == NULL)
341 fatal("db_sum_list_add");
342
343 TAILQ_INSERT_TAIL(&nbr->db_sum_list, le, entry);
344 le->le_lsa = lsa;
345 }
346
347 void
348 db_sum_list_next(struct nbr *nbr)
349 {
350 struct lsa_entry *le;
351
352 while ((le = TAILQ_FIRST(&nbr->db_sum_list)) != nbr->dd_end) {
353 TAILQ_REMOVE(&nbr->db_sum_list, le, entry);
354 free(le->le_lsa);
355 free(le);
356 }
357 }
358
359 void
360 db_sum_list_clr(struct nbr *nbr)
361 {
362 nbr->dd_end = NULL;
363 db_sum_list_next(nbr);
364 }
365
366 /* timers */
367 /* ARGSUSED */
368 void
369 db_tx_timer(int fd, short event, void *arg)
370 {
371 struct nbr *nbr = arg;
372 struct timeval tv;
373
374 switch (nbr->state) {
375 case NBR_STA_DOWN:
376 case NBR_STA_ATTEMPT:
377 case NBR_STA_INIT:
378 case NBR_STA_2_WAY:
379 case NBR_STA_SNAP:
380 return ;
381 case NBR_STA_XSTRT:
382 case NBR_STA_XCHNG:
383 case NBR_STA_LOAD:
384 case NBR_STA_FULL:
385 send_db_description(nbr);
386 break;
387 default:
388 log_debug("db_tx_timer: unknown neighbor state, "
389 "neighbor ID %s", inet_ntoa(nbr->id));
390 break;
391 }
392
393 /* reschedule db_tx_timer but only in master mode */
394 if (nbr->dd_master) {
395 timerclear(&tv);
396 tv.tv_sec = nbr->iface->rxmt_interval;
397 if (evtimer_add(&nbr->db_tx_timer, &tv) == -1)
398 fatal("db_tx_timer");
399 }
400 }
401
402 void
403 start_db_tx_timer(struct nbr *nbr)
404 {
405 struct timeval tv;
406
407 if (nbr == nbr->iface->self)
408 return;
409
410 timerclear(&tv);
411 if (evtimer_add(&nbr->db_tx_timer, &tv) == -1)
412 fatal("start_db_tx_timer");
413 }
414
415 void
416 stop_db_tx_timer(struct nbr *nbr)
417 {
418 if (nbr == nbr->iface->self)
419 return;
420
421 if (evtimer_del(&nbr->db_tx_timer) == -1)
422 fatal("stop_db_tx_timer");
423 }