1 /* $OpenBSD: database.c,v 1.16 2019/05/10 13:50:34 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2005, 2007 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/ip6.h> 24 #include <arpa/inet.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <unistd.h> 28 29 #include "ospf6d.h" 30 #include "ospf6.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 in6_addr 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 ip6_hdr))) == 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: cannot send packet in state %s," 67 " neighbor ID %s", nbr_state_name(nbr->state), 68 inet_ntoa(nbr->id)); 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 */ 92 for (le = TAILQ_FIRST(&nbr->db_sum_list); le != NULL && 93 buf->wpos + sizeof(struct lsa_hdr) < buf->max; le = nle) { 94 nbr->dd_end = nle = TAILQ_NEXT(le, entry); 95 if (ibuf_add(buf, le->le_lsa, sizeof(struct lsa_hdr))) 96 goto fail; 97 } 98 break; 99 case NBR_STA_LOAD: 100 case NBR_STA_FULL: 101 if (nbr->dd_master) 102 bits |= OSPF_DBD_MS; 103 else 104 bits &= ~OSPF_DBD_MS; 105 bits &= ~OSPF_DBD_M; 106 bits &= ~OSPF_DBD_I; 107 108 nbr->dd_more = 0; 109 break; 110 default: 111 fatalx("send_db_description: unknown neighbor state"); 112 } 113 114 bzero(&dd_hdr, sizeof(dd_hdr)); 115 116 switch (nbr->iface->type) { 117 case IF_TYPE_POINTOPOINT: 118 inet_pton(AF_INET6, AllSPFRouters, &dst); 119 dd_hdr.iface_mtu = htons(nbr->iface->mtu); 120 break; 121 case IF_TYPE_BROADCAST: 122 dst = nbr->addr; 123 dd_hdr.iface_mtu = htons(nbr->iface->mtu); 124 break; 125 case IF_TYPE_NBMA: 126 case IF_TYPE_POINTOMULTIPOINT: 127 /* XXX not supported */ 128 break; 129 case IF_TYPE_VIRTUALLINK: 130 dst = nbr->iface->dst; 131 dd_hdr.iface_mtu = 0; 132 break; 133 default: 134 fatalx("send_db_description: unknown interface type"); 135 } 136 137 dd_hdr.opts = htonl(area_ospf_options(area_find(oeconf, 138 nbr->iface->area_id))); 139 dd_hdr.bits = bits; 140 dd_hdr.dd_seq_num = htonl(nbr->dd_seq_num); 141 142 memcpy(ibuf_seek(buf, sizeof(struct ospf_hdr), sizeof(dd_hdr)), 143 &dd_hdr, sizeof(dd_hdr)); 144 145 /* calculate checksum */ 146 if (upd_ospf_hdr(buf, nbr->iface)) 147 goto fail; 148 149 /* transmit packet */ 150 ret = send_packet(nbr->iface, buf->buf, buf->wpos, &dst); 151 done: 152 ibuf_free(buf); 153 return (ret); 154 fail: 155 log_warn("send_db_description"); 156 ibuf_free(buf); 157 return (-1); 158 } 159 160 void 161 recv_db_description(struct nbr *nbr, char *buf, u_int16_t len) 162 { 163 struct db_dscrp_hdr dd_hdr; 164 int dupe = 0; 165 166 if (len < sizeof(dd_hdr)) { 167 log_warnx("recv_db_description: " 168 "bad packet size, neighbor ID %s", inet_ntoa(nbr->id)); 169 return; 170 } 171 memcpy(&dd_hdr, buf, sizeof(dd_hdr)); 172 buf += sizeof(dd_hdr); 173 len -= sizeof(dd_hdr); 174 175 /* db description packet sanity checks */ 176 if (ntohs(dd_hdr.iface_mtu) > nbr->iface->mtu) { 177 log_warnx("recv_db_description: invalid MTU %d sent by " 178 "neighbor ID %s, expected %d", ntohs(dd_hdr.iface_mtu), 179 inet_ntoa(nbr->id), nbr->iface->mtu); 180 return; 181 } 182 183 if (nbr->last_rx_options == dd_hdr.opts && 184 nbr->last_rx_bits == dd_hdr.bits && 185 ntohl(dd_hdr.dd_seq_num) == nbr->dd_seq_num - nbr->dd_master ? 186 1 : 0) { 187 log_debug("recv_db_description: dupe from ID %s", 188 inet_ntoa(nbr->id)); 189 dupe = 1; 190 } 191 192 switch (nbr->state) { 193 case NBR_STA_DOWN: 194 case NBR_STA_ATTEMPT: 195 case NBR_STA_2_WAY: 196 case NBR_STA_SNAP: 197 log_debug("recv_db_description: packet ignored in state %s, " 198 "neighbor ID %s", nbr_state_name(nbr->state), 199 inet_ntoa(nbr->id)); 200 return; 201 case NBR_STA_INIT: 202 /* evaluate dr and bdr after issuing a 2-Way event */ 203 nbr_fsm(nbr, NBR_EVT_2_WAY_RCVD); 204 if_fsm(nbr->iface, IF_EVT_NBR_CHNG); 205 if (nbr->state != NBR_STA_XSTRT) 206 return; 207 /* FALLTHROUGH */ 208 case NBR_STA_XSTRT: 209 if (dupe) 210 return; 211 /* 212 * check bits: either I,M,MS or only M 213 */ 214 if (dd_hdr.bits == (OSPF_DBD_I | OSPF_DBD_M | OSPF_DBD_MS)) { 215 /* if nbr Router ID is larger than own -> slave */ 216 if ((ntohl(nbr->id.s_addr)) > 217 ntohl(ospfe_router_id())) { 218 /* slave */ 219 nbr->dd_master = 0; 220 nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num); 221 222 /* event negotiation done */ 223 nbr_fsm(nbr, NBR_EVT_NEG_DONE); 224 } 225 } else if (!(dd_hdr.bits & (OSPF_DBD_I | OSPF_DBD_MS))) { 226 /* M only case: we are master */ 227 if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) { 228 log_warnx("recv_db_description: invalid " 229 "seq num, mine %x his %x", 230 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num)); 231 return; 232 } 233 nbr->dd_seq_num++; 234 235 /* event negotiation done */ 236 nbr_fsm(nbr, NBR_EVT_NEG_DONE); 237 238 /* this packet may already have data so pass it on */ 239 if (len > 0) { 240 nbr->dd_pending++; 241 ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid, 242 0, buf, len); 243 } 244 } else { 245 /* ignore packet */ 246 log_debug("recv_db_description: packet ignored in " 247 "state %s (bad flags), neighbor ID %s", 248 nbr_state_name(nbr->state), inet_ntoa(nbr->id)); 249 } 250 break; 251 case NBR_STA_XCHNG: 252 case NBR_STA_LOAD: 253 case NBR_STA_FULL: 254 if (dd_hdr.bits & OSPF_DBD_I || 255 !(dd_hdr.bits & OSPF_DBD_MS) == !nbr->dd_master) { 256 log_warnx("recv_db_description: seq num mismatch, " 257 "bad flags"); 258 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); 259 return; 260 } 261 262 if (nbr->last_rx_options != dd_hdr.opts) { 263 log_warnx("recv_db_description: seq num mismatch, " 264 "bad options"); 265 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); 266 return; 267 } 268 269 if (dupe) { 270 if (!nbr->dd_master) 271 /* retransmit */ 272 start_db_tx_timer(nbr); 273 return; 274 } 275 276 if (nbr->state != NBR_STA_XCHNG) { 277 log_warnx("recv_db_description: invalid " 278 "seq num, mine %x his %x", 279 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num)); 280 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); 281 return; 282 } 283 284 /* sanity check dd seq number */ 285 if (nbr->dd_master) { 286 /* master */ 287 if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) { 288 log_warnx("recv_db_description: invalid " 289 "seq num, mine %x his %x", 290 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num)); 291 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); 292 return; 293 } 294 nbr->dd_seq_num++; 295 } else { 296 /* slave */ 297 if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num + 1) { 298 log_warnx("recv_db_description: invalid " 299 "seq num, mine %x his %x", 300 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num)); 301 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); 302 return; 303 } 304 nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num); 305 } 306 307 /* forward to RDE and let it decide which LSAs to request */ 308 if (len > 0) { 309 nbr->dd_pending++; 310 ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid, 0, 311 buf, len); 312 } 313 314 /* next packet */ 315 db_sum_list_next(nbr); 316 start_db_tx_timer(nbr); 317 318 if (!(dd_hdr.bits & OSPF_DBD_M) && 319 TAILQ_EMPTY(&nbr->db_sum_list)) 320 if (!nbr->dd_master || !nbr->dd_more) 321 nbr_fsm(nbr, NBR_EVT_XCHNG_DONE); 322 break; 323 default: 324 fatalx("recv_db_description: unknown neighbor state"); 325 } 326 327 nbr->last_rx_options = dd_hdr.opts; 328 nbr->last_rx_bits = dd_hdr.bits; 329 } 330 331 void 332 db_sum_list_add(struct nbr *nbr, struct lsa_hdr *lsa) 333 { 334 struct lsa_entry *le; 335 336 if ((le = calloc(1, sizeof(*le))) == NULL) 337 fatal("db_sum_list_add"); 338 339 TAILQ_INSERT_TAIL(&nbr->db_sum_list, le, entry); 340 le->le_lsa = lsa; 341 } 342 343 void 344 db_sum_list_next(struct nbr *nbr) 345 { 346 struct lsa_entry *le; 347 348 while ((le = TAILQ_FIRST(&nbr->db_sum_list)) != nbr->dd_end) { 349 TAILQ_REMOVE(&nbr->db_sum_list, le, entry); 350 free(le->le_lsa); 351 free(le); 352 } 353 } 354 355 void 356 db_sum_list_clr(struct nbr *nbr) 357 { 358 nbr->dd_end = NULL; 359 db_sum_list_next(nbr); 360 } 361 362 /* timers */ 363 /* ARGSUSED */ 364 void 365 db_tx_timer(int fd, short event, void *arg) 366 { 367 struct nbr *nbr = arg; 368 struct timeval tv; 369 370 switch (nbr->state) { 371 case NBR_STA_DOWN: 372 case NBR_STA_ATTEMPT: 373 case NBR_STA_INIT: 374 case NBR_STA_2_WAY: 375 case NBR_STA_SNAP: 376 return ; 377 case NBR_STA_XSTRT: 378 case NBR_STA_XCHNG: 379 case NBR_STA_LOAD: 380 case NBR_STA_FULL: 381 send_db_description(nbr); 382 break; 383 default: 384 log_debug("db_tx_timer: unknown neighbor state, " 385 "neighbor ID %s", inet_ntoa(nbr->id)); 386 break; 387 } 388 389 /* reschedule db_tx_timer but only in master mode */ 390 if (nbr->dd_master) { 391 timerclear(&tv); 392 tv.tv_sec = nbr->iface->rxmt_interval; 393 if (evtimer_add(&nbr->db_tx_timer, &tv) == -1) 394 fatal("db_tx_timer"); 395 } 396 } 397 398 void 399 start_db_tx_timer(struct nbr *nbr) 400 { 401 struct timeval tv; 402 403 if (nbr == nbr->iface->self) 404 return; 405 406 timerclear(&tv); 407 if (evtimer_add(&nbr->db_tx_timer, &tv) == -1) 408 fatal("start_db_tx_timer"); 409 } 410 411 void 412 stop_db_tx_timer(struct nbr *nbr) 413 { 414 if (nbr == nbr->iface->self) 415 return; 416 417 if (evtimer_del(&nbr->db_tx_timer) == -1) 418 fatal("stop_db_tx_timer"); 419 } 420