1 /* $OpenBSD: database.c,v 1.32 2015/03/13 02:31:29 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/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 } 438