Annotation of embedaddon/bird2/proto/ospf/dbdes.c, revision 1.1.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>