Annotation of embedaddon/bird2/proto/ospf/dbdes.c, revision 1.1
1.1 ! misho 1: /*
! 2: * BIRD -- OSPF
! 3: *
! 4: * (c) 1999--2004 Ondrej Filip <feela@network.cz>
! 5: * (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
! 6: * (c) 2009--2014 CZ.NIC z.s.p.o.
! 7: *
! 8: * Can be freely distributed and used under the terms of the GNU GPL.
! 9: */
! 10:
! 11: #include "ospf.h"
! 12:
! 13:
! 14: struct ospf_dbdes2_packet
! 15: {
! 16: struct ospf_packet hdr;
! 17: union ospf_auth2 auth;
! 18:
! 19: u16 iface_mtu;
! 20: u8 options;
! 21: u8 imms; /* I, M, MS bits */
! 22: u32 ddseq;
! 23:
! 24: struct ospf_lsa_header lsas[];
! 25: };
! 26:
! 27: struct ospf_dbdes3_packet
! 28: {
! 29: struct ospf_packet hdr;
! 30:
! 31: u32 options;
! 32: u16 iface_mtu;
! 33: u8 padding;
! 34: u8 imms; /* I, M, MS bits */
! 35: u32 ddseq;
! 36:
! 37: struct ospf_lsa_header lsas[];
! 38: };
! 39:
! 40:
! 41: uint
! 42: ospf_dbdes3_options(struct ospf_packet *pkt)
! 43: {
! 44: struct ospf_dbdes3_packet *ps = (void *) pkt;
! 45: return ntohl(ps->options);
! 46: }
! 47:
! 48: static inline uint
! 49: ospf_dbdes_hdrlen(struct ospf_proto *p)
! 50: {
! 51: return ospf_is_v2(p) ?
! 52: sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet);
! 53: }
! 54:
! 55: static void
! 56: ospf_dbdes_body(struct ospf_proto *p, struct ospf_packet *pkt,
! 57: struct ospf_lsa_header **body, uint *count)
! 58: {
! 59: uint plen = ntohs(pkt->length);
! 60: uint hlen = ospf_dbdes_hdrlen(p);
! 61:
! 62: *body = ((void *) pkt) + hlen;
! 63: *count = (plen - hlen) / sizeof(struct ospf_lsa_header);
! 64: }
! 65:
! 66: static void
! 67: ospf_dump_dbdes(struct ospf_proto *p, struct ospf_packet *pkt)
! 68: {
! 69: struct ospf_lsa_header *lsas;
! 70: uint i, lsa_count;
! 71: u32 pkt_ddseq;
! 72: u16 pkt_iface_mtu;
! 73: u8 pkt_imms;
! 74:
! 75: ASSERT(pkt->type == DBDES_P);
! 76: ospf_dump_common(p, pkt);
! 77:
! 78: if (ospf_is_v2(p))
! 79: {
! 80: struct ospf_dbdes2_packet *ps = (void *) pkt;
! 81: pkt_iface_mtu = ntohs(ps->iface_mtu);
! 82: pkt_imms = ps->imms;
! 83: pkt_ddseq = ntohl(ps->ddseq);
! 84: }
! 85: else /* OSPFv3 */
! 86: {
! 87: struct ospf_dbdes3_packet *ps = (void *) pkt;
! 88: pkt_iface_mtu = ntohs(ps->iface_mtu);
! 89: pkt_imms = ps->imms;
! 90: pkt_ddseq = ntohl(ps->ddseq);
! 91: }
! 92:
! 93: log(L_TRACE "%s: mtu %u", p->p.name, pkt_iface_mtu);
! 94: log(L_TRACE "%s: imms %s%s%s", p->p.name,
! 95: (pkt_imms & DBDES_I) ? "I " : "",
! 96: (pkt_imms & DBDES_M) ? "M " : "",
! 97: (pkt_imms & DBDES_MS) ? "MS" : "");
! 98: log(L_TRACE "%s: ddseq %u", p->p.name, pkt_ddseq);
! 99:
! 100: ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
! 101: for (i = 0; i < lsa_count; i++)
! 102: ospf_dump_lsahdr(p, lsas + i);
! 103: }
! 104:
! 105:
! 106: static void
! 107: ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
! 108: {
! 109: struct ospf_iface *ifa = n->ifa;
! 110: struct ospf_packet *pkt;
! 111: uint length;
! 112:
! 113: u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu;
! 114:
! 115: /* Update DBDES buffer */
! 116: if (n->ldd_bsize != ifa->tx_length)
! 117: {
! 118: mb_free(n->ldd_buffer);
! 119: n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
! 120: n->ldd_bsize = ifa->tx_length;
! 121: }
! 122:
! 123: pkt = n->ldd_buffer;
! 124: ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
! 125:
! 126: if (ospf_is_v2(p))
! 127: {
! 128: struct ospf_dbdes2_packet *ps = (void *) pkt;
! 129: ps->iface_mtu = htons(iface_mtu);
! 130: ps->options = ifa->oa->options & DBDES2_OPT_MASK;
! 131: ps->imms = 0; /* Will be set later */
! 132: ps->ddseq = htonl(n->dds);
! 133: length = sizeof(struct ospf_dbdes2_packet);
! 134: }
! 135: else /* OSPFv3 */
! 136: {
! 137: struct ospf_dbdes3_packet *ps = (void *) pkt;
! 138: u32 options = ifa->oa->options | (ifa->autype == OSPF_AUTH_CRYPT ? OPT_AT : 0);
! 139: ps->options = htonl(options & DBDES3_OPT_MASK);
! 140: ps->iface_mtu = htons(iface_mtu);
! 141: ps->padding = 0;
! 142: ps->imms = 0; /* Will be set later */
! 143: ps->ddseq = htonl(n->dds);
! 144: length = sizeof(struct ospf_dbdes3_packet);
! 145: }
! 146:
! 147: /* Prepare DBDES body */
! 148: if (!(n->myimms & DBDES_I) && (n->myimms & DBDES_M))
! 149: {
! 150: struct ospf_lsa_header *lsas;
! 151: struct top_hash_entry *en;
! 152: uint i = 0, lsa_max;
! 153:
! 154: ospf_dbdes_body(p, pkt, &lsas, &lsa_max);
! 155: en = (void *) s_get(&(n->dbsi));
! 156:
! 157: while (i < lsa_max)
! 158: {
! 159: if (!SNODE_VALID(en))
! 160: {
! 161: n->myimms &= ~DBDES_M; /* Unset More bit */
! 162: break;
! 163: }
! 164:
! 165: if ((en->lsa.age < LSA_MAXAGE) &&
! 166: lsa_flooding_allowed(en->lsa_type, en->domain, ifa) &&
! 167: lsa_is_acceptable(en->lsa_type, n, p))
! 168: {
! 169: lsa_hton_hdr(&(en->lsa), lsas + i);
! 170: i++;
! 171: }
! 172:
! 173: en = SNODE_NEXT(en);
! 174: }
! 175:
! 176: s_put(&(n->dbsi), SNODE en);
! 177:
! 178: length += i * sizeof(struct ospf_lsa_header);
! 179: }
! 180:
! 181: if (ospf_is_v2(p))
! 182: ((struct ospf_dbdes2_packet *) pkt)->imms = n->myimms;
! 183: else
! 184: ((struct ospf_dbdes3_packet *) pkt)->imms = n->myimms;
! 185:
! 186: pkt->length = htons(length);
! 187: }
! 188:
! 189: static void
! 190: ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
! 191: {
! 192: struct ospf_iface *ifa = n->ifa;
! 193:
! 194: OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer,
! 195: "DBDES packet sent to nbr %R on %s", n->rid, ifa->ifname);
! 196: sk_set_tbuf(ifa->sk, n->ldd_buffer);
! 197: ospf_send_to(ifa, n->ip);
! 198: sk_set_tbuf(ifa->sk, NULL);
! 199: }
! 200:
! 201: /**
! 202: * ospf_send_dbdes - transmit database description packet
! 203: * @p: OSPF protocol instance
! 204: * @n: neighbor
! 205: *
! 206: * Sending of a database description packet is described in 10.8 of RFC 2328.
! 207: * Reception of each packet is acknowledged in the sequence number of another.
! 208: * When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
! 209: * does not reply, I don't create a new packet but just send the content
! 210: * of the buffer.
! 211: */
! 212: void
! 213: ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
! 214: {
! 215: /* RFC 2328 10.8 */
! 216:
! 217: ASSERT((n->state == NEIGHBOR_EXSTART) || (n->state == NEIGHBOR_EXCHANGE));
! 218:
! 219: if (!n->ifa->oa->rt && !p->gr_recovery)
! 220: return;
! 221:
! 222: ospf_prepare_dbdes(p, n);
! 223: ospf_do_send_dbdes(p, n);
! 224: }
! 225:
! 226: void
! 227: ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
! 228: {
! 229: ASSERT(n->state > NEIGHBOR_EXSTART);
! 230:
! 231: if (!n->ldd_buffer)
! 232: {
! 233: log(L_WARN "%s: No DBDES packet for retransmit", p->p.name);
! 234: ospf_neigh_sm(n, INM_SEQMIS);
! 235: return;
! 236: }
! 237:
! 238: /* Send last packet */
! 239: ospf_do_send_dbdes(p, n);
! 240: }
! 241:
! 242: void
! 243: ospf_reset_ldd(struct ospf_proto *p UNUSED, struct ospf_neighbor *n)
! 244: {
! 245: mb_free(n->ldd_buffer);
! 246: n->ldd_buffer = NULL;
! 247: n->ldd_bsize = 0;
! 248: }
! 249:
! 250: static int
! 251: ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_neighbor *n)
! 252: {
! 253: struct ospf_iface *ifa = n->ifa;
! 254: struct ospf_lsa_header *lsas, lsa;
! 255: struct top_hash_entry *en, *req;
! 256: const char *err_dsc = NULL;
! 257: u32 lsa_type, lsa_domain;
! 258: uint i, lsa_count;
! 259:
! 260: ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
! 261:
! 262: for (i = 0; i < lsa_count; i++)
! 263: {
! 264: lsa_ntoh_hdr(lsas + i, &lsa);
! 265: lsa_get_type_domain(&lsa, ifa, &lsa_type, &lsa_domain);
! 266:
! 267: /* RFC 2328 10.6 and RFC 5340 4.2.2 */
! 268:
! 269: if (!lsa_type)
! 270: DROP1("LSA of unknown type");
! 271:
! 272: if (!oa_is_ext(ifa->oa) && (LSA_SCOPE(lsa_type) == LSA_SCOPE_AS))
! 273: DROP1("LSA with AS scope in stub area");
! 274:
! 275: /* Errata 3746 to RFC 2328 - rt-summary-LSAs forbidden in stub areas */
! 276: if (!oa_is_ext(ifa->oa) && (lsa_type == LSA_T_SUM_RT))
! 277: DROP1("rt-summary-LSA in stub area");
! 278:
! 279: /* Not explicitly mentioned in RFC 5340 4.2.2 but makes sense */
! 280: if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)
! 281: DROP1("LSA with invalid scope");
! 282:
! 283: /* RFC 3623 2.2 (2) special case - check for my router-LSA (GR recovery) */
! 284: if ((lsa_type == LSA_T_RT) && (lsa.rt == p->router_id))
! 285: n->got_my_rt_lsa = 1;
! 286:
! 287: en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type);
! 288: if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER))
! 289: {
! 290: /* This should be splitted to ospf_lsa_lsrq_up() */
! 291: req = ospf_hash_get(n->lsrqh, lsa_domain, lsa.id, lsa.rt, lsa_type);
! 292:
! 293: if (!SNODE_VALID(req))
! 294: s_add_tail(&n->lsrql, SNODE req);
! 295:
! 296: if (!SNODE_VALID(n->lsrqi))
! 297: n->lsrqi = req;
! 298:
! 299: req->lsa = lsa;
! 300: req->lsa_body = LSA_BODY_DUMMY;
! 301:
! 302: if (!tm_active(n->lsrq_timer))
! 303: tm_start(n->lsrq_timer, 0);
! 304: }
! 305: }
! 306:
! 307: return 0;
! 308:
! 309: drop:
! 310: LOG_LSA1("Bad LSA (Type: %04x, Id: %R, Rt: %R) in DBDES", lsa_type, lsa.id, lsa.rt);
! 311: LOG_LSA2(" received from nbr %R on %s - %s", n->rid, ifa->ifname, err_dsc);
! 312:
! 313: ospf_neigh_sm(n, INM_SEQMIS);
! 314: return -1;
! 315: }
! 316:
! 317: void
! 318: ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
! 319: struct ospf_neighbor *n)
! 320: {
! 321: struct ospf_proto *p = ifa->oa->po;
! 322: const char *err_dsc = NULL;
! 323: u32 rcv_ddseq, rcv_options;
! 324: u16 rcv_iface_mtu;
! 325: u8 rcv_imms;
! 326: uint plen, err_val = 0;
! 327:
! 328: /* RFC 2328 10.6 */
! 329:
! 330: plen = ntohs(pkt->length);
! 331: if (plen < ospf_dbdes_hdrlen(p))
! 332: {
! 333: LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, "too short", plen);
! 334: return;
! 335: }
! 336:
! 337: OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet received from nbr %R on %s", n->rid, ifa->ifname);
! 338:
! 339: ospf_neigh_sm(n, INM_HELLOREC);
! 340:
! 341: if (ospf_is_v2(p))
! 342: {
! 343: struct ospf_dbdes2_packet *ps = (void *) pkt;
! 344: rcv_iface_mtu = ntohs(ps->iface_mtu);
! 345: rcv_options = ps->options;
! 346: rcv_imms = ps->imms;
! 347: rcv_ddseq = ntohl(ps->ddseq);
! 348: }
! 349: else /* OSPFv3 */
! 350: {
! 351: struct ospf_dbdes3_packet *ps = (void *) pkt;
! 352: rcv_options = ntohl(ps->options);
! 353: rcv_iface_mtu = ntohs(ps->iface_mtu);
! 354: rcv_imms = ps->imms;
! 355: rcv_ddseq = ntohl(ps->ddseq);
! 356: }
! 357:
! 358: /* Reject packets with non-matching MTU */
! 359: if ((ifa->type != OSPF_IT_VLINK) &&
! 360: (rcv_iface_mtu != ifa->iface->mtu) &&
! 361: (rcv_iface_mtu != 0) && (ifa->iface->mtu != 0))
! 362: {
! 363: LOG_PKT("MTU mismatch with nbr %R on %s (remote %d, local %d)",
! 364: n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
! 365: return;
! 366: }
! 367:
! 368: switch (n->state)
! 369: {
! 370: case NEIGHBOR_DOWN:
! 371: case NEIGHBOR_ATTEMPT:
! 372: case NEIGHBOR_2WAY:
! 373: OSPF_TRACE(D_PACKETS, "DBDES packet ignored - lesser state than ExStart");
! 374: return;
! 375:
! 376: case NEIGHBOR_INIT:
! 377: ospf_neigh_sm(n, INM_2WAYREC);
! 378: if (n->state != NEIGHBOR_EXSTART)
! 379: return;
! 380: /* fallthrough */
! 381:
! 382: case NEIGHBOR_EXSTART:
! 383: if (((rcv_imms & DBDES_IMMS) == DBDES_IMMS) &&
! 384: (n->rid > p->router_id) &&
! 385: (plen == ospf_dbdes_hdrlen(p)))
! 386: {
! 387: /* I'm slave! */
! 388: n->dds = rcv_ddseq;
! 389: n->ddr = rcv_ddseq;
! 390: n->options = rcv_options;
! 391: n->myimms &= ~DBDES_MS;
! 392: n->imms = rcv_imms;
! 393: tm_stop(n->dbdes_timer);
! 394: ospf_neigh_sm(n, INM_NEGDONE);
! 395: ospf_send_dbdes(p, n);
! 396: break;
! 397: }
! 398:
! 399: if (!(rcv_imms & DBDES_I) &&
! 400: !(rcv_imms & DBDES_MS) &&
! 401: (n->rid < p->router_id) &&
! 402: (n->dds == rcv_ddseq))
! 403: {
! 404: /* I'm master! */
! 405: n->options = rcv_options;
! 406: n->ddr = rcv_ddseq - 1; /* It will be set corectly a few lines down */
! 407: n->imms = rcv_imms;
! 408: ospf_neigh_sm(n, INM_NEGDONE);
! 409: /* Continue to the NEIGHBOR_EXCHANGE case */
! 410: }
! 411: else
! 412: {
! 413: DBG("%s: Nothing happend to %I (imms=%d)\n", p->name, n->ip, rcv_imms);
! 414: break;
! 415: }
! 416:
! 417: case NEIGHBOR_EXCHANGE:
! 418: if ((rcv_imms == n->imms) &&
! 419: (rcv_options == n->options) &&
! 420: (rcv_ddseq == n->ddr))
! 421: goto duplicate;
! 422:
! 423: if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS))
! 424: DROP("MS-bit mismatch", rcv_imms);
! 425:
! 426: if (rcv_imms & DBDES_I)
! 427: DROP("I-bit mismatch", rcv_imms);
! 428:
! 429: if (rcv_options != n->options)
! 430: DROP("options mismatch", rcv_options);
! 431:
! 432: n->ddr = rcv_ddseq;
! 433: n->imms = rcv_imms;
! 434:
! 435: if (n->myimms & DBDES_MS)
! 436: {
! 437: /* MASTER */
! 438:
! 439: if (rcv_ddseq != n->dds)
! 440: DROP("DD sequence number mismatch", rcv_ddseq);
! 441:
! 442: n->dds++;
! 443:
! 444: if (ospf_process_dbdes(p, pkt, n) < 0)
! 445: return;
! 446:
! 447: if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
! 448: {
! 449: tm_stop(n->dbdes_timer);
! 450: ospf_reset_ldd(p, n);
! 451: ospf_neigh_sm(n, INM_EXDONE);
! 452: break;
! 453: }
! 454:
! 455: ospf_send_dbdes(p, n);
! 456: tm_start(n->dbdes_timer, n->ifa->rxmtint S);
! 457: }
! 458: else
! 459: {
! 460: /* SLAVE */
! 461:
! 462: if (rcv_ddseq != (n->dds + 1))
! 463: DROP("DD sequence number mismatch", rcv_ddseq);
! 464:
! 465: n->ddr = rcv_ddseq;
! 466: n->dds = rcv_ddseq;
! 467:
! 468: if (ospf_process_dbdes(p, pkt, n) < 0)
! 469: return;
! 470:
! 471: ospf_send_dbdes(p, n);
! 472:
! 473: if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
! 474: {
! 475: /* Use dbdes timer to postpone freeing of Last DBDES packet buffer */
! 476: tm_start(n->dbdes_timer, n->ifa->deadint S);
! 477: ospf_neigh_sm(n, INM_EXDONE);
! 478: }
! 479: }
! 480: break;
! 481:
! 482: case NEIGHBOR_LOADING:
! 483: case NEIGHBOR_FULL:
! 484: if ((rcv_imms == n->imms) &&
! 485: (rcv_options == n->options) &&
! 486: (rcv_ddseq == n->ddr))
! 487: goto duplicate;
! 488:
! 489: DROP("too late for DD exchange", n->state);
! 490:
! 491: default:
! 492: bug("Undefined interface state");
! 493: }
! 494: return;
! 495:
! 496: duplicate:
! 497: OSPF_TRACE(D_PACKETS, "DBDES packet is duplicate");
! 498:
! 499: /* Slave should retransmit DBDES packet */
! 500: if (!(n->myimms & DBDES_MS))
! 501: ospf_rxmt_dbdes(p, n);
! 502: return;
! 503:
! 504: drop:
! 505: LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)",
! 506: n->rid, ifa->ifname, err_dsc, err_val);
! 507:
! 508: ospf_neigh_sm(n, INM_SEQMIS);
! 509: return;
! 510: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>