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