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>