People running ospfd should better test this diff.

The diff is a start at supporting opaque LSA (type 9, 10 and 11). Those
are used for things like graceful restart. Now even if you don't have
systems emitting such LSA it is important to test the diff to make sure
normal operation is still working.
If you have systems announcing the new LSA I would be interested in
ospfctl show da output. I do not have such systems around.

happy testing
-- 
:wq Claudio

Index: ospfctl/ospfctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfctl/ospfctl.c,v
retrieving revision 1.55
diff -u -p -r1.55 ospfctl.c
--- ospfctl/ospfctl.c   25 Sep 2010 13:29:56 -0000      1.55
+++ ospfctl/ospfctl.c   3 May 2011 09:54:44 -0000
@@ -47,7 +47,7 @@ const char    *fmt_timeframe(time_t t);
 const char     *fmt_timeframe_core(time_t t);
 const char     *log_id(u_int32_t );
 const char     *log_adv_rtr(u_int32_t);
-void            show_database_head(struct in_addr, u_int8_t);
+void            show_database_head(struct in_addr, char *, u_int8_t);
 int             show_database_msg(struct imsg *);
 char           *print_ls_type(u_int8_t);
 void            show_db_hdr_msg_detail(struct lsa_hdr *);
@@ -183,6 +183,9 @@ main(int argc, char *argv[])
        case SHOW_DBASBR:
                imsg_compose(ibuf, IMSG_CTL_SHOW_DB_ASBR, 0, 0, -1, NULL, 0);
                break;
+       case SHOW_DBOPAQ:
+               imsg_compose(ibuf, IMSG_CTL_SHOW_DB_OPAQ, 0, 0, -1, NULL, 0);
+               break;
        case SHOW_RIB:
                printf("%-20s %-17s %-12s %-9s %-7s %-8s\n", "Destination",
                    "Nexthop", "Path Type", "Type", "Cost", "Uptime");
@@ -283,6 +286,7 @@ main(int argc, char *argv[])
                        case SHOW_DBRTR:
                        case SHOW_DBSUM:
                        case SHOW_DBASBR:
+                       case SHOW_DBOPAQ:
                                done = show_db_msg_detail(&imsg);
                                break;
                        case SHOW_RIB:
@@ -586,9 +590,10 @@ mask2prefixlen(in_addr_t ina)
 }
 
 void
-show_database_head(struct in_addr aid, u_int8_t type)
+show_database_head(struct in_addr aid, char *ifname, u_int8_t type)
 {
        char    *header, *format;
+       int      cleanup = 0;
 
        switch (type) {
        case LSA_TYPE_ROUTER:
@@ -608,24 +613,47 @@ show_database_head(struct in_addr aid, u
                if ((header = strdup("Type-5 AS External Link States")) == NULL)
                        err(1, NULL);
                break;
+       case LSA_TYPE_LINK_OPAQ:
+               format = "Type-9 Link Local Opaque Link States";
+               break;
+       case LSA_TYPE_AREA_OPAQ:
+               format = "Type-10 Area Local Opaque Link States";
+               break;
+       case LSA_TYPE_AS_OPAQ:
+               format = NULL;
+               if ((header = strdup("Type-11 AS Wide Opaque Link States")) ==
+                   NULL)
+                       err(1, NULL);
+               break;
        default:
-               errx(1, "unknown LSA type");
+               if (asprintf(&format, "LSA type %x", ntohs(type)) == -1)
+                       err(1, NULL);
+               cleanup = 1;
+               break;
        }
-       if (type != LSA_TYPE_EXTERNAL)
+       if (type == LSA_TYPE_LINK_OPAQ) {
+               if (asprintf(&header, "%s (Area %s Interface %s)", format,
+                   inet_ntoa(aid), ifname) == -1)
+                       err(1, NULL);
+       } else if (type != LSA_TYPE_EXTERNAL && type != LSA_TYPE_AS_OPAQ)
                if (asprintf(&header, "%s (Area %s)", format,
                    inet_ntoa(aid)) == -1)
                        err(1, NULL);
 
        printf("\n%-15s %s\n\n", "", header);
        free(header);
+       if (cleanup)
+               free(format);
 }
 
 int
 show_database_msg(struct imsg *imsg)
 {
        static struct in_addr    area_id;
+       static char              ifname[IF_NAMESIZE];
        static u_int8_t          lasttype;
        struct area             *area;
+       struct iface            *iface;
        struct lsa_hdr          *lsa;
 
        switch (imsg->hdr.type) {
@@ -633,7 +661,7 @@ show_database_msg(struct imsg *imsg)
        case IMSG_CTL_SHOW_DB_SELF:
                lsa = imsg->data;
                if (lsa->type != lasttype) {
-                       show_database_head(area_id, lsa->type);
+                       show_database_head(area_id, ifname, lsa->type);
                        printf("%-15s %-15s %-4s %-10s %-8s\n", "Link ID",
                            "Adv Router", "Age", "Seq#", "Checksum");
                }
@@ -648,6 +676,11 @@ show_database_msg(struct imsg *imsg)
                area_id = area->id;
                lasttype = 0;
                break;
+       case IMSG_CTL_IFACE:
+               iface = imsg->data;
+               strlcpy(ifname, iface->name, sizeof(ifname));
+               lasttype = 0;
+               break;
        case IMSG_CTL_END:
                printf("\n");
                return (1);
@@ -672,6 +705,12 @@ print_ls_type(u_int8_t type)
                return ("Summary (Router)");
        case LSA_TYPE_EXTERNAL:
                return ("AS External");
+       case LSA_TYPE_LINK_OPAQ:
+               return ("Type-9 Opaque");
+       case LSA_TYPE_AREA_OPAQ:
+               return ("Type-10 Opaque");
+       case LSA_TYPE_AS_OPAQ:
+               return ("Type-11 Opaque");
        default:
                return ("Unknown");
        }
@@ -703,6 +742,13 @@ show_db_hdr_msg_detail(struct lsa_hdr *l
                printf("Link State ID: %s (External Network Number)\n",
                     log_id(lsa->ls_id));
                break;
+       case LSA_TYPE_LINK_OPAQ:
+       case LSA_TYPE_AREA_OPAQ:
+       case LSA_TYPE_AS_OPAQ:
+               printf("Link State ID: %s Type %d ID %d\n", log_id(lsa->ls_id),
+                   LSA_24_GETHI(ntohl(lsa->ls_id)),
+                   LSA_24_GETLO(ntohl(lsa->ls_id)));
+               break;
        }
 
        printf("Advertising Router: %s\n", log_adv_rtr(lsa->adv_rtr));
@@ -744,9 +790,11 @@ int
 show_db_msg_detail(struct imsg *imsg)
 {
        static struct in_addr    area_id;
+       static char              ifname[IF_NAMESIZE];
        static u_int8_t          lasttype;
        struct in_addr           addr, data;
        struct area             *area;
+       struct iface            *iface;
        struct lsa              *lsa;
        struct lsa_rtr_link     *rtr_link;
        struct lsa_asext        *asext;
@@ -758,7 +806,7 @@ show_db_msg_detail(struct imsg *imsg)
        case IMSG_CTL_SHOW_DB_EXT:
                lsa = imsg->data;
                if (lsa->hdr.type != lasttype)
-                       show_database_head(area_id, lsa->hdr.type);
+                       show_database_head(area_id, ifname, lsa->hdr.type);
                show_db_hdr_msg_detail(&lsa->hdr);
                addr.s_addr = lsa->data.asext.mask;
                printf("Network Mask: %s\n", inet_ntoa(addr));
@@ -781,7 +829,7 @@ show_db_msg_detail(struct imsg *imsg)
        case IMSG_CTL_SHOW_DB_NET:
                lsa = imsg->data;
                if (lsa->hdr.type != lasttype)
-                       show_database_head(area_id, lsa->hdr.type);
+                       show_database_head(area_id, ifname, lsa->hdr.type);
                show_db_hdr_msg_detail(&lsa->hdr);
                addr.s_addr = lsa->data.net.mask;
                printf("Network Mask: %s\n", inet_ntoa(addr));
@@ -802,7 +850,7 @@ show_db_msg_detail(struct imsg *imsg)
        case IMSG_CTL_SHOW_DB_RTR:
                lsa = imsg->data;
                if (lsa->hdr.type != lasttype)
-                       show_database_head(area_id, lsa->hdr.type);
+                       show_database_head(area_id, ifname, lsa->hdr.type);
                show_db_hdr_msg_detail(&lsa->hdr);
                printf("Flags: %s\n", print_ospf_flags(lsa->data.rtr.flags));
                nlinks = ntohs(lsa->data.rtr.nlinks);
@@ -859,7 +907,7 @@ show_db_msg_detail(struct imsg *imsg)
        case IMSG_CTL_SHOW_DB_ASBR:
                lsa = imsg->data;
                if (lsa->hdr.type != lasttype)
-                       show_database_head(area_id, lsa->hdr.type);
+                       show_database_head(area_id, ifname, lsa->hdr.type);
                show_db_hdr_msg_detail(&lsa->hdr);
                addr.s_addr = lsa->data.sum.mask;
                printf("Network Mask: %s\n", inet_ntoa(addr));
@@ -867,11 +915,24 @@ show_db_msg_detail(struct imsg *imsg)
                    LSA_METRIC_MASK);
                lasttype = lsa->hdr.type;
                break;
+       case IMSG_CTL_SHOW_DB_OPAQ:
+               lsa = imsg->data;
+               if (lsa->hdr.type != lasttype)
+                       show_database_head(area_id, ifname, lsa->hdr.type);
+               show_db_hdr_msg_detail(&lsa->hdr);
+               /* XXX should we hexdump the data? */
+               lasttype = lsa->hdr.type;
+               break;
        case IMSG_CTL_AREA:
                area = imsg->data;
                area_id = area->id;
                lasttype = 0;
                break;
+       case IMSG_CTL_IFACE:
+               iface = imsg->data;
+               strlcpy(ifname, iface->name, sizeof(ifname));
+               lasttype = 0;
+               break;
        case IMSG_CTL_END:
                return (1);
        default:
@@ -914,12 +975,15 @@ print_ospf_options(u_int8_t opts)
 {
        static char     optbuf[32];
 
-       snprintf(optbuf, sizeof(optbuf), "*|*|%s|%s|%s|%s|%s|*",
+       snprintf(optbuf, sizeof(optbuf), "%s|%s|%s|%s|%s|%s|%s|%s",
+           opts & OSPF_OPTION_DN ? "DN" : "-",
+           opts & OSPF_OPTION_O ? "O" : "-",
            opts & OSPF_OPTION_DC ? "DC" : "-",
            opts & OSPF_OPTION_EA ? "EA" : "-",
            opts & OSPF_OPTION_NP ? "N/P" : "-",
            opts & OSPF_OPTION_MC ? "MC" : "-",
-           opts & OSPF_OPTION_E ? "E" : "-");
+           opts & OSPF_OPTION_E ? "E" : "-",
+           opts & OSPF_OPTION_MT ? "MT" : "-");
        return (optbuf);
 }
 
Index: ospfctl/parser.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfctl/parser.c,v
retrieving revision 1.19
diff -u -p -r1.19 parser.c
--- ospfctl/parser.c    4 Sep 2010 21:31:04 -0000       1.19
+++ ospfctl/parser.c    2 May 2011 11:58:14 -0000
@@ -102,6 +102,7 @@ static const struct token t_show_db[] = 
        {KEYWORD,       "router",               SHOW_DBRTR,     NULL},
        {KEYWORD,       "self-originated",      SHOW_DBSELF,    NULL},
        {KEYWORD,       "summary",              SHOW_DBSUM,     NULL},
+       {KEYWORD,       "opaque",               SHOW_DBOPAQ,    NULL},
        {ENDTOKEN,      "",                     NONE,           NULL}
 };
 
Index: ospfctl/parser.h
===================================================================
RCS file: /cvs/src/usr.sbin/ospfctl/parser.h,v
retrieving revision 1.12
diff -u -p -r1.12 parser.h
--- ospfctl/parser.h    4 Sep 2010 21:31:04 -0000       1.12
+++ ospfctl/parser.h    2 May 2011 11:58:06 -0000
@@ -46,6 +46,7 @@ enum actions {
        SHOW_DBSELF,
        SHOW_DBSUM,
        SHOW_DBASBR,
+       SHOW_DBOPAQ,
        SHOW_RIB,
        SHOW_RIB_DTAIL,
        SHOW_FIB,
Index: ospfd/control.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/control.c,v
retrieving revision 1.34
diff -u -p -r1.34 control.c
--- ospfd/control.c     2 Sep 2010 14:03:22 -0000       1.34
+++ ospfd/control.c     2 May 2011 11:55:25 -0000
@@ -253,6 +253,7 @@ control_dispatch_imsg(int fd, short even
                case IMSG_CTL_SHOW_DB_SELF:
                case IMSG_CTL_SHOW_DB_SUM:
                case IMSG_CTL_SHOW_DB_ASBR:
+               case IMSG_CTL_SHOW_DB_OPAQ:
                case IMSG_CTL_SHOW_RIB:
                case IMSG_CTL_SHOW_SUM:
                        c->iev.ibuf.pid = imsg.hdr.pid;
Index: ospfd/database.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/database.c,v
retrieving revision 1.28
diff -u -p -r1.28 database.c
@@ -138,7 +138,8 @@ send_db_description(struct nbr *nbr)
                fatalx("send_db_description: unknown interface type");
        }
 
-       dd_hdr.opts = area_ospf_options(nbr->iface->area);
+       /* XXX button or not for opaque LSA? */
+       dd_hdr.opts = area_ospf_options(nbr->iface->area) | OSPF_OPTION_O;
        dd_hdr.bits = bits;
        dd_hdr.dd_seq_num = htonl(nbr->dd_seq_num);
 
@@ -211,6 +212,13 @@ recv_db_description(struct nbr *nbr, cha
        case NBR_STA_XSTRT:
                if (dupe)
                        return;
+               nbr->capa_options = dd_hdr.opts;
+               if ((nbr->capa_options & nbr->options) != nbr->options) {
+                       log_warnx("recv_db_description: neighbor ID %s "
+                           "sent inconsistent options %x vs. %x",
+                           inet_ntoa(nbr->id), nbr->capa_options,
+                           nbr->options);
+               }
                /*
                 * check bits: either I,M,MS or only M
                 */
Index: ospfd/interface.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/interface.c,v
retrieving revision 1.70
diff -u -p -r1.70 interface.c
--- ospfd/interface.c   3 Jul 2010 04:44:52 -0000       1.70
+++ ospfd/interface.c   1 May 2011 21:59:27 -0000
@@ -167,6 +167,7 @@ if_new(struct kif *kif, struct kif_addr 
        LIST_INIT(&iface->nbr_list);
        TAILQ_INIT(&iface->ls_ack_list);
        TAILQ_INIT(&iface->auth_md_list);
+       RB_INIT(&iface->lsa_tree);
 
        iface->crypt_seq_num = arc4random() & 0x0fffffff;
 
Index: ospfd/neighbor.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/neighbor.c,v
retrieving revision 1.42
diff -u -p -r1.42 neighbor.c
--- ospfd/neighbor.c    24 Mar 2011 08:35:59 -0000      1.42
+++ ospfd/neighbor.c    3 May 2011 09:57:17 -0000
@@ -313,6 +313,7 @@ nbr_new(u_int32_t nbr_id, struct iface *
        bzero(&rn, sizeof(rn));
        rn.id.s_addr = nbr->id.s_addr;
        rn.area_id.s_addr = nbr->iface->area->id.s_addr;
+       rn.ifindex = nbr->iface->ifindex;
        rn.state = nbr->state;
        rn.self = self;
        ospfe_imsg_compose_rde(IMSG_NEIGHBOR_UP, nbr->peerid, 0, &rn,
@@ -519,6 +520,8 @@ nbr_act_snapshot(struct nbr *nbr)
 {
        stop_db_tx_timer(nbr);
 
+       ospfe_imsg_compose_rde(IMSG_NEIGHBOR_CAPA, nbr->peerid, 0,
+           &nbr->capa_options, sizeof(nbr->capa_options));
        ospfe_imsg_compose_rde(IMSG_DB_SNAPSHOT, nbr->peerid, 0, NULL, 0);
 
        return (0);
@@ -677,7 +680,7 @@ nbr_to_ctl(struct nbr *nbr)
        nctl.state_chng_cnt = nbr->stats.sta_chng;
 
        nctl.priority = nbr->priority;
-       nctl.options = nbr->options;
+       nctl.options = nbr->options | nbr->capa_options;
 
        gettimeofday(&now, NULL);
        if (evtimer_pending(&nbr->inactivity_timer, &tv)) {
Index: ospfd/ospf.h
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/ospf.h,v
retrieving revision 1.20
diff -u -p -r1.20 ospf.h
--- ospfd/ospf.h        25 Mar 2011 08:52:21 -0000      1.20
+++ ospfd/ospf.h        27 Apr 2011 09:38:37 -0000
@@ -81,11 +81,14 @@
 #define MAX_SIMPLE_AUTH_LEN    8
 
 /* OSPF compatibility flags */
+#define OSPF_OPTION_MT         0x01
 #define OSPF_OPTION_E          0x02
 #define OSPF_OPTION_MC         0x04
 #define OSPF_OPTION_NP         0x08
 #define OSPF_OPTION_EA         0x10
 #define OSPF_OPTION_DC         0x20
+#define OSPF_OPTION_O          0x40    /* only on DD options */
+#define OSPF_OPTION_DN         0x80    /* only on LSA options */
 
 /* OSPF packet types */
 #define PACKET_TYPE_HELLO      1
@@ -177,6 +180,9 @@ struct ls_upd_hdr {
 #define LSA_TYPE_SUM_NETWORK   3
 #define LSA_TYPE_SUM_ROUTER    4
 #define        LSA_TYPE_EXTERNAL       5
+#define        LSA_TYPE_LINK_OPAQ      9
+#define        LSA_TYPE_AREA_OPAQ      10
+#define        LSA_TYPE_AS_OPAQ        11
 
 #define LINK_TYPE_POINTTOPOINT 1
 #define LINK_TYPE_TRANSIT_NET  2
@@ -186,6 +192,18 @@ struct ls_upd_hdr {
 /* LSA headers */
 #define LSA_METRIC_MASK                0x00ffffff      /* only for sum & 
as-ext */
 #define LSA_ASEXT_E_FLAG       0x80000000
+
+/* for some reason they thought 24bit types are fun, make them less a hazard */
+#define LSA_24_MASK 0xffffff
+#define LSA_24_GETHI(x)                \
+       ((x) >> 24)
+#define LSA_24_GETLO(x)                \
+       ((x) & LSA_24_MASK)
+#define LSA_24_SETHI(x, y)     \
+       ((x) = ((x) & LSA_24_MASK) | (((y) & 0xff) << 24))
+#define LSA_24_SETLO(x, y)     \
+       ((x) = ((y) & LSA_24_MASK) | ((x) & ~LSA_24_MASK))
+
 
 #define OSPF_RTR_B             0x01
 #define OSPF_RTR_E             0x02
Index: ospfd/ospfd.h
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/ospfd.h,v
retrieving revision 1.89
diff -u -p -r1.89 ospfd.h
--- ospfd/ospfd.h       12 Jan 2011 15:07:46 -0000      1.89
+++ ospfd/ospfd.h       2 May 2011 11:54:43 -0000
@@ -80,6 +80,7 @@ enum imsg_type {
        IMSG_CTL_SHOW_DB_SELF,
        IMSG_CTL_SHOW_DB_SUM,
        IMSG_CTL_SHOW_DB_ASBR,
+       IMSG_CTL_SHOW_DB_OPAQ,
        IMSG_CTL_SHOW_NBR,
        IMSG_CTL_SHOW_RIB,
        IMSG_CTL_SHOW_SUM,
@@ -88,6 +89,7 @@ enum imsg_type {
        IMSG_CTL_FIB_DECOUPLE,
        IMSG_CTL_FIB_RELOAD,
        IMSG_CTL_AREA,
+       IMSG_CTL_IFACE,
        IMSG_CTL_KROUTE,
        IMSG_CTL_KROUTE_ADDR,
        IMSG_CTL_IFINFO,
@@ -99,6 +101,7 @@ enum imsg_type {
        IMSG_NEIGHBOR_UP,
        IMSG_NEIGHBOR_DOWN,
        IMSG_NEIGHBOR_CHANGE,
+       IMSG_NEIGHBOR_CAPA,
        IMSG_NETWORK_ADD,
        IMSG_NETWORK_DEL,
        IMSG_DD,
@@ -310,6 +313,7 @@ struct iface {
        LIST_HEAD(, nbr)         nbr_list;
        struct auth_md_head      auth_md_list;
        struct lsa_head          ls_ack_list;
+       struct lsa_tree          lsa_tree;
 
        char                     name[IF_NAMESIZE];
        char                     demote_group[IFNAMSIZ];
Index: ospfd/ospfe.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/ospfe.c,v
retrieving revision 1.81
diff -u -p -r1.81 ospfe.c
--- ospfd/ospfe.c       2 May 2011 09:22:23 -0000       1.81
+++ ospfd/ospfe.c       2 May 2011 12:46:36 -0000
@@ -375,6 +375,7 @@ ospfe_dispatch_main(int fd, short event,
                        LIST_INIT(&niface->nbr_list);
                        TAILQ_INIT(&niface->ls_ack_list);
                        TAILQ_INIT(&niface->auth_md_list);
+                       RB_INIT(&niface->lsa_tree);
 
                        niface->area = narea;
                        LIST_INSERT_HEAD(&narea->iface_list, niface, entry);
@@ -544,6 +545,12 @@ ospfe_dispatch_rde(int fd, short event, 
                                                &lsa_hdr, imsg.data);
                                    }
                                }
+                       } else if (lsa_hdr.type == LSA_TYPE_LINK_OPAQ) {
+                               /*
+                                * Flood on interface only
+                                */
+                               noack += lsa_flood(nbr->iface, nbr,
+                                   &lsa_hdr, imsg.data);
                        } else {
                                /*
                                 * Flood on all area interfaces. For
@@ -676,6 +683,7 @@ ospfe_dispatch_rde(int fd, short event, 
                                }
                        break;
                case IMSG_CTL_AREA:
+               case IMSG_CTL_IFACE:
                case IMSG_CTL_END:
                case IMSG_CTL_SHOW_DATABASE:
                case IMSG_CTL_SHOW_DB_EXT:
@@ -684,6 +692,7 @@ ospfe_dispatch_rde(int fd, short event, 
                case IMSG_CTL_SHOW_DB_SELF:
                case IMSG_CTL_SHOW_DB_SUM:
                case IMSG_CTL_SHOW_DB_ASBR:
+               case IMSG_CTL_SHOW_DB_OPAQ:
                case IMSG_CTL_SHOW_RIB:
                case IMSG_CTL_SHOW_SUM:
                case IMSG_CTL_SHOW_SUM_AREA:
Index: ospfd/ospfe.h
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/ospfe.h,v
retrieving revision 1.43
diff -u -p -r1.43 ospfe.h
--- ospfd/ospfe.h       25 Mar 2011 08:52:21 -0000      1.43
+++ ospfd/ospfe.h       20 Apr 2011 10:32:26 -0000
@@ -88,6 +88,7 @@ struct nbr {
        int                      state;
        u_int8_t                 priority;
        u_int8_t                 options;
+       u_int8_t                 capa_options;
        u_int8_t                 last_rx_options;
        u_int8_t                 last_rx_bits;
        u_int8_t                 dd_master;
Index: ospfd/rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/rde.c,v
retrieving revision 1.93
diff -u -p -r1.93 rde.c
--- ospfd/rde.c 2 May 2011 11:17:03 -0000       1.93
+++ ospfd/rde.c 2 May 2011 11:56:41 -0000
@@ -42,6 +42,7 @@ void           rde_sig_handler(int sig, short, v
 void            rde_shutdown(void);
 void            rde_dispatch_imsg(int, short, void *);
 void            rde_dispatch_parent(int, short, void *);
+void            rde_dump_area(struct area *, int, pid_t);
 
 void            rde_send_summary(pid_t);
 void            rde_send_summary_area(struct area *, pid_t);
@@ -61,7 +62,6 @@ void           rde_asext_get(struct kroute *);
 void            rde_asext_put(struct kroute *);
 void            rde_asext_free(void);
 struct lsa     *orig_asext_lsa(struct kroute *, u_int32_t, u_int16_t);
-
 struct lsa     *orig_sum_lsa(struct rt_node *, struct area *, u_int8_t, int);
 
 struct ospfd_conf      *rdeconf = NULL, *nconf = NULL;
@@ -305,12 +305,20 @@ rde_dispatch_imsg(int fd, short event, v
                        if (nbr->state & NBR_STA_FULL)
                                rde_req_list_free(nbr);
                        break;
+               case IMSG_NEIGHBOR_CAPA:
+                       if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(u_int8_t))
+                               fatalx("invalid size of OE request");
+                       nbr = rde_nbr_find(imsg.hdr.peerid);
+                       if (nbr == NULL)
+                               break;
+                       nbr->capa_options = *(u_int8_t *)imsg.data;
+                       break;
                case IMSG_DB_SNAPSHOT:
                        nbr = rde_nbr_find(imsg.hdr.peerid);
                        if (nbr == NULL)
                                break;
 
-                       lsa_snap(nbr->area, imsg.hdr.peerid);
+                       lsa_snap(nbr);
 
                        imsg_compose_event(iev_ospfe, IMSG_DB_END, 
imsg.hdr.peerid,
                            0, -1, NULL, 0);
@@ -332,7 +340,7 @@ rde_dispatch_imsg(int fd, short event, v
                                        error = 1;
                                        break;
                                }
-                               v = lsa_find(nbr->area, lsa_hdr.type,
+                               v = lsa_find(nbr->iface, lsa_hdr.type,
                                    lsa_hdr.ls_id, lsa_hdr.adv_rtr);
                                if (v == NULL)
                                        db_hdr = NULL;
@@ -373,7 +381,7 @@ rde_dispatch_imsg(int fd, short event, v
                                memcpy(&req_hdr, buf, sizeof(req_hdr));
                                buf += sizeof(req_hdr);
 
-                               if ((v = lsa_find(nbr->area,
+                               if ((v = lsa_find(nbr->iface,
                                    ntohl(req_hdr.type), req_hdr.ls_id,
                                    req_hdr.adv_rtr)) == NULL) {
                                        log_debug("rde_dispatch_imsg: "
@@ -408,7 +416,7 @@ rde_dispatch_imsg(int fd, short event, v
                                break;
                        }
 
-                       v = lsa_find(nbr->area, lsa->hdr.type, lsa->hdr.ls_id,
+                       v = lsa_find(nbr->iface, lsa->hdr.type, lsa->hdr.ls_id,
                            lsa->hdr.adv_rtr);
                        if (v == NULL)
                                db_hdr = NULL;
@@ -504,7 +512,7 @@ rde_dispatch_imsg(int fd, short event, v
                        if (rde_nbr_loading(nbr->area))
                                break;
 
-                       v = lsa_find(nbr->area, lsa_hdr.type, lsa_hdr.ls_id,
+                       v = lsa_find(nbr->iface, lsa_hdr.type, lsa_hdr.ls_id,
                            lsa_hdr.adv_rtr);
                        if (v == NULL)
                                db_hdr = NULL;
@@ -524,6 +532,7 @@ rde_dispatch_imsg(int fd, short event, v
                case IMSG_CTL_SHOW_DB_SELF:
                case IMSG_CTL_SHOW_DB_SUM:
                case IMSG_CTL_SHOW_DB_ASBR:
+               case IMSG_CTL_SHOW_DB_OPAQ:
                        if (imsg.hdr.len != IMSG_HEADER_SIZE &&
                            imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(aid)) {
                                log_warnx("rde_dispatch_imsg: wrong imsg len");
@@ -531,10 +540,7 @@ rde_dispatch_imsg(int fd, short event, v
                        }
                        if (imsg.hdr.len == IMSG_HEADER_SIZE) {
                                LIST_FOREACH(area, &rdeconf->area_list, entry) {
-                                       imsg_compose_event(iev_ospfe,
-                                           IMSG_CTL_AREA, 0, imsg.hdr.pid, -1,
-                                           area, sizeof(*area));
-                                       lsa_dump(&area->lsa_tree, imsg.hdr.type,
+                                       rde_dump_area(area, imsg.hdr.type,
                                            imsg.hdr.pid);
                                }
                                lsa_dump(&asext_tree, imsg.hdr.type,
@@ -542,10 +548,7 @@ rde_dispatch_imsg(int fd, short event, v
                        } else {
                                memcpy(&aid, imsg.data, sizeof(aid));
                                if ((area = area_find(rdeconf, aid)) != NULL) {
-                                       imsg_compose_event(iev_ospfe,
-                                           IMSG_CTL_AREA, 0, imsg.hdr.pid, -1,
-                                           area, sizeof(*area));
-                                       lsa_dump(&area->lsa_tree, imsg.hdr.type,
+                                       rde_dump_area(area, imsg.hdr.type,
                                            imsg.hdr.pid);
                                        if (!area->stub)
                                                lsa_dump(&asext_tree,
@@ -686,6 +689,7 @@ rde_dispatch_parent(int fd, short event,
                        LIST_INIT(&niface->nbr_list);
                        TAILQ_INIT(&niface->ls_ack_list);
                        TAILQ_INIT(&niface->auth_md_list);
+                       RB_INIT(&niface->lsa_tree);
 
                        niface->area = narea;
                        LIST_INSERT_HEAD(&narea->iface_list, niface, entry);
@@ -711,6 +715,26 @@ rde_dispatch_parent(int fd, short event,
        }
 }
 
+void
+rde_dump_area(struct area *area, int imsg_type, pid_t pid)
+{
+       struct iface    *iface;
+
+       /* dump header */
+       imsg_compose_event(iev_ospfe, IMSG_CTL_AREA, 0, pid, -1,
+           area, sizeof(*area));
+
+       /* dump link local lsa */
+       LIST_FOREACH(iface, &area->iface_list, entry) {
+               imsg_compose_event(iev_ospfe, IMSG_CTL_IFACE,
+                   0, pid, -1, iface, sizeof(*iface));
+               lsa_dump(&iface->lsa_tree, imsg_type, pid);
+       }
+
+       /* dump area lsa */
+       lsa_dump(&area->lsa_tree, imsg_type, pid);
+}
+
 u_int32_t
 rde_router_id(void)
 {
@@ -903,18 +927,27 @@ rde_nbr_new(u_int32_t peerid, struct rde
        struct rde_nbr_head     *head;
        struct rde_nbr          *nbr;
        struct area             *area;
+       struct iface            *iface;
 
        if (rde_nbr_find(peerid))
                return (NULL);
        if ((area = area_find(rdeconf, new->area_id)) == NULL)
                fatalx("rde_nbr_new: unknown area");
 
+       LIST_FOREACH(iface, &area->iface_list, entry) {
+               if (iface->ifindex == new->ifindex)
+                       break;
+       }
+       if (iface == NULL)
+               fatalx("rde_nbr_new: unknown interface");
+
        if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
                fatal("rde_nbr_new");
 
        memcpy(nbr, new, sizeof(*nbr));
        nbr->peerid = peerid;
        nbr->area = area;
+       nbr->iface = iface;
 
        TAILQ_INIT(&nbr->req_list);
 
@@ -1335,12 +1368,13 @@ rde_summary_update(struct rt_node *rte, 
                fatalx("rde_summary_update: unknown route type");
 
        /* update lsa but only if it was changed */
-       v = lsa_find(area, type, rte->prefix.s_addr, rde_router_id());
+       v = lsa_find_area(area, type, rte->prefix.s_addr, rde_router_id());
        lsa = orig_sum_lsa(rte, area, type, rte->invalid);
        lsa_merge(rde_nbr_self(area), lsa, v);
 
        if (v == NULL)
-               v = lsa_find(area, type, rte->prefix.s_addr, rde_router_id());
+               v = lsa_find_area(area, type, rte->prefix.s_addr,
+                   rde_router_id());
 
        /* suppressed/deleted routes are not found in the second lsa_find */
        if (v)
Index: ospfd/rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/rde.h,v
retrieving revision 1.37
diff -u -p -r1.37 rde.h
--- ospfd/rde.h 2 May 2011 11:45:55 -0000       1.37
+++ ospfd/rde.h 2 May 2011 11:46:09 -0000
@@ -41,6 +41,7 @@ struct vertex {
        struct event             ev;
        struct area             *area;
        struct lsa              *lsa;
+       struct lsa_tree         *lsa_tree;
        time_t                   changed;
        time_t                   stamp;
        u_int32_t                cost;
@@ -67,9 +68,12 @@ struct rde_nbr {
        struct in_addr                   area_id;
        TAILQ_HEAD(, rde_req_entry)      req_list;
        struct area                     *area;
+       struct iface                    *iface;
        u_int32_t                        peerid;        /* unique ID in DB */
        int                              state;
-       int                              self;
+       unsigned int                     ifindex;
+       u_int8_t                         self;
+       u_int8_t                         capa_options;
 };
 
 struct rt_nexthop {
@@ -133,10 +137,11 @@ int                lsa_self(struct rde_nbr *, struct 
 int             lsa_add(struct rde_nbr *, struct lsa *);
 void            lsa_del(struct rde_nbr *, struct lsa_hdr *);
 void            lsa_age(struct vertex *);
-struct vertex  *lsa_find(struct area *, u_int8_t, u_int32_t, u_int32_t);
+struct vertex  *lsa_find(struct iface *, u_int8_t, u_int32_t, u_int32_t);
+struct vertex  *lsa_find_area(struct area *, u_int8_t, u_int32_t, u_int32_t);
 struct vertex  *lsa_find_net(struct area *area, u_int32_t);
 u_int16_t       lsa_num_links(struct vertex *);
-void            lsa_snap(struct area *, u_int32_t);
+void            lsa_snap(struct rde_nbr *);
 void            lsa_dump(struct lsa_tree *, int, pid_t);
 void            lsa_merge(struct rde_nbr *, struct lsa *, struct vertex *);
 void            lsa_remove_invalid_sums(struct area *);
Index: ospfd/rde_lsdb.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/rde_lsdb.c,v
retrieving revision 1.46
diff -u -p -r1.46 rde_lsdb.c
--- ospfd/rde_lsdb.c    2 May 2011 11:45:55 -0000       1.46
+++ ospfd/rde_lsdb.c    2 May 2011 12:01:06 -0000
@@ -27,9 +27,11 @@
 #include "rde.h"
 #include "log.h"
 
-struct vertex  *vertex_get(struct lsa *, struct rde_nbr *);
+struct vertex  *vertex_get(struct lsa *, struct rde_nbr *, struct lsa_tree *);
 
 int             lsa_router_check(struct lsa *, u_int16_t);
+struct vertex  *lsa_find_tree(struct lsa_tree *, u_int16_t, u_int32_t,
+                   u_int32_t);
 void            lsa_timeout(int, short, void *);
 void            lsa_refresh(struct vertex *);
 int             lsa_equal(struct lsa *, struct lsa *);
@@ -49,20 +51,20 @@ lsa_compare(struct vertex *a, struct ver
                return (-1);
        if (a->type > b->type)
                return (1);
-       if (a->ls_id < b->ls_id)
-               return (-1);
-       if (a->ls_id > b->ls_id)
-               return (1);
        if (a->adv_rtr < b->adv_rtr)
                return (-1);
        if (a->adv_rtr > b->adv_rtr)
                return (1);
+       if (a->ls_id < b->ls_id)
+               return (-1);
+       if (a->ls_id > b->ls_id)
+               return (1);
        return (0);
 }
 
 
 struct vertex *
-vertex_get(struct lsa *lsa, struct rde_nbr *nbr)
+vertex_get(struct lsa *lsa, struct rde_nbr *nbr, struct lsa_tree *tree)
 {
        struct vertex   *v;
        struct timespec  tp;
@@ -79,6 +81,7 @@ vertex_get(struct lsa *lsa, struct rde_n
        v->ls_id = ntohl(lsa->hdr.ls_id);
        v->adv_rtr = ntohl(lsa->hdr.adv_rtr);
        v->type = lsa->hdr.type;
+       v->lsa_tree = tree;
 
        if (!nbr->self)
                v->flooded = 1; /* XXX fix me */
@@ -92,10 +95,7 @@ vertex_get(struct lsa *lsa, struct rde_n
 void
 vertex_free(struct vertex *v)
 {
-       if (v->type == LSA_TYPE_EXTERNAL)
-               RB_REMOVE(lsa_tree, &asext_tree, v);
-       else
-               RB_REMOVE(lsa_tree, &v->area->lsa_tree, v);
+       RB_REMOVE(lsa_tree, v->lsa_tree, v);
 
        (void)evtimer_del(&v->ev);
        vertex_nexthop_clear(v);
@@ -255,13 +255,24 @@ lsa_check(struct rde_nbr *nbr, struct ls
                if (area->stub)
                        return (0);
                break;
+       case LSA_TYPE_LINK_OPAQ:
+       case LSA_TYPE_AREA_OPAQ:
+       case LSA_TYPE_AS_OPAQ:
+               if (len % sizeof(u_int32_t)) {
+                       log_warnx("lsa_check: bad opaque LSA packet");
+                       return (0);
+               }
+               /* Type-11 Opaque-LSA are silently discarded in stub areas */
+               if (lsa->hdr.type == LSA_TYPE_AS_OPAQ && area->stub)
+                       return (0);
+               break;
        default:
                log_warnx("lsa_check: unknown type %u", lsa->hdr.type);
                return (0);
        }
 
        /* MaxAge handling */
-       if (lsa->hdr.age == htons(MAX_AGE) && !nbr->self && lsa_find(area,
+       if (lsa->hdr.age == htons(MAX_AGE) && !nbr->self && lsa_find(nbr->iface,
            lsa->hdr.type, lsa->hdr.ls_id, lsa->hdr.adv_rtr) == NULL &&
            !rde_nbr_loading(area)) {
                /*
@@ -372,12 +383,15 @@ lsa_add(struct rde_nbr *nbr, struct lsa 
        struct vertex   *new, *old;
        struct timeval   tv, now, res;
 
-       if (lsa->hdr.type == LSA_TYPE_EXTERNAL)
+       if (lsa->hdr.type == LSA_TYPE_EXTERNAL ||
+           lsa->hdr.type == LSA_TYPE_AS_OPAQ)
                tree = &asext_tree;
+       else if (lsa->hdr.type == LSA_TYPE_LINK_OPAQ)
+               tree = &nbr->iface->lsa_tree;
        else
                tree = &nbr->area->lsa_tree;
 
-       new = vertex_get(lsa, nbr);
+       new = vertex_get(lsa, nbr, tree);
        old = RB_INSERT(lsa_tree, tree, new);
 
        if (old != NULL) {
@@ -396,14 +410,16 @@ lsa_add(struct rde_nbr *nbr, struct lsa 
                        return (1);
                }
                if (!lsa_equal(new->lsa, old->lsa)) {
-                       if (lsa->hdr.type != LSA_TYPE_EXTERNAL)
+                       if (lsa->hdr.type != LSA_TYPE_EXTERNAL &&
+                           lsa->hdr.type != LSA_TYPE_AS_OPAQ)
                                nbr->area->dirty = 1;
                        start_spf_timer();
                }
                vertex_free(old);
                RB_INSERT(lsa_tree, tree, new);
        } else {
-               if (lsa->hdr.type != LSA_TYPE_EXTERNAL)
+               if (lsa->hdr.type != LSA_TYPE_EXTERNAL &&
+                   lsa->hdr.type != LSA_TYPE_AS_OPAQ)
                        nbr->area->dirty = 1;
                start_spf_timer();
        }
@@ -427,7 +443,7 @@ lsa_del(struct rde_nbr *nbr, struct lsa_
        struct vertex   *v;
        struct timeval   tv;
 
-       v = lsa_find(nbr->area, lsa->type, lsa->ls_id, lsa->adv_rtr);
+       v = lsa_find(nbr->iface, lsa->type, lsa->ls_id, lsa->adv_rtr);
        if (v == NULL)
                return;
 
@@ -469,21 +485,39 @@ lsa_age(struct vertex *v)
 }
 
 struct vertex *
-lsa_find(struct area *area, u_int8_t type, u_int32_t ls_id, u_int32_t adv_rtr)
+lsa_find(struct iface *iface, u_int8_t type, u_int32_t ls_id, u_int32_t 
adv_rtr)
+{
+       struct lsa_tree *tree;
+
+       if (type == LSA_TYPE_EXTERNAL ||
+           type == LSA_TYPE_AS_OPAQ)
+               tree = &asext_tree;
+       else if (type == LSA_TYPE_LINK_OPAQ)
+               tree = &iface->lsa_tree;
+       else
+               tree = &iface->area->lsa_tree;
+
+       return lsa_find_tree(tree, type, ls_id, adv_rtr);
+}
+
+struct vertex *
+lsa_find_area(struct area *area, u_int8_t type, u_int32_t ls_id,
+    u_int32_t adv_rtr)
+{
+       return lsa_find_tree(&area->lsa_tree, type, ls_id, adv_rtr);
+}
+
+struct vertex *
+lsa_find_tree(struct lsa_tree *tree, u_int16_t type, u_int32_t ls_id,
+    u_int32_t adv_rtr)
 {
        struct vertex    key;
        struct vertex   *v;
-       struct lsa_tree *tree;
 
        key.ls_id = ntohl(ls_id);
        key.adv_rtr = ntohl(adv_rtr);
        key.type = type;
 
-       if (type == LSA_TYPE_EXTERNAL)
-               tree = &asext_tree;
-       else
-               tree = &area->lsa_tree;
-
        v = RB_FIND(lsa_tree, tree, &key);
 
        /* LSA that are deleted are not findable */
@@ -532,26 +566,40 @@ lsa_num_links(struct vertex *v)
 }
 
 void
-lsa_snap(struct area *area, u_int32_t peerid)
+lsa_snap(struct rde_nbr *nbr)
 {
-       struct lsa_tree *tree = &area->lsa_tree;
+       struct lsa_tree *tree = &nbr->area->lsa_tree;
        struct vertex   *v;
 
        do {
                RB_FOREACH(v, lsa_tree, tree) {
                        if (v->deleted)
                                continue;
+                       switch (v->type) {
+                       case LSA_TYPE_LINK_OPAQ:
+                       case LSA_TYPE_AREA_OPAQ:
+                       case LSA_TYPE_AS_OPAQ:
+                               if (nbr->capa_options & OSPF_OPTION_O)
+                                       break;
+                               continue;
+                       }
                        lsa_age(v);
                        if (ntohs(v->lsa->hdr.age) >= MAX_AGE)
-                               rde_imsg_compose_ospfe(IMSG_LS_UPD, peerid,
+                               rde_imsg_compose_ospfe(IMSG_LS_UPD, nbr->peerid,
                                    0, &v->lsa->hdr, ntohs(v->lsa->hdr.len));
                        else
-                               rde_imsg_compose_ospfe(IMSG_DB_SNAPSHOT, peerid,
-                                   0, &v->lsa->hdr, sizeof(struct lsa_hdr));
+                               rde_imsg_compose_ospfe(IMSG_DB_SNAPSHOT,
+                                   nbr->peerid, 0, &v->lsa->hdr,
+                                   sizeof(struct lsa_hdr));
                }
-               if (tree != &area->lsa_tree || area->stub)
+               if (tree == &asext_tree)
                        break;
-               tree = &asext_tree;
+               if (tree == &nbr->area->lsa_tree)
+                       tree = &nbr->iface->lsa_tree;
+               else if (nbr->area->stub)
+                       break;
+               else
+                       tree = &asext_tree;
        } while (1);
 }
 
@@ -566,9 +614,7 @@ lsa_dump(struct lsa_tree *tree, int imsg
                lsa_age(v);
                switch (imsg_type) {
                case IMSG_CTL_SHOW_DATABASE:
-                       rde_imsg_compose_ospfe(IMSG_CTL_SHOW_DATABASE, 0, pid,
-                           &v->lsa->hdr, ntohs(v->lsa->hdr.len));
-                       continue;
+                       break;
                case IMSG_CTL_SHOW_DB_SELF:
                        if (v->lsa->hdr.adv_rtr == rde_router_id())
                                break;
@@ -593,6 +639,12 @@ lsa_dump(struct lsa_tree *tree, int imsg
                        if (v->type == LSA_TYPE_SUM_ROUTER)
                                break;
                        continue;
+               case IMSG_CTL_SHOW_DB_OPAQ:
+                       if (v->type == LSA_TYPE_LINK_OPAQ ||
+                           v->type == LSA_TYPE_AREA_OPAQ ||
+                           v->type == LSA_TYPE_AS_OPAQ)
+                               break;
+                       continue;
                default:
                        log_warnx("lsa_dump: unknown imsg type");
                        return;
@@ -618,7 +670,8 @@ lsa_timeout(int fd, short event, void *b
                        v->deleted = 0;
 
                        /* schedule recalculation of the RIB */
-                       if (v->lsa->hdr.type != LSA_TYPE_EXTERNAL)
+                       if (v->type != LSA_TYPE_EXTERNAL &&
+                           v->type != LSA_TYPE_AS_OPAQ)
                                v->area->dirty = 1;
                        start_spf_timer();
 
@@ -713,7 +766,8 @@ lsa_merge(struct rde_nbr *nbr, struct ls
        free(v->lsa);
        v->lsa = lsa;
        start_spf_timer();
-       if (v->type != LSA_TYPE_EXTERNAL)
+       if (v->type != LSA_TYPE_EXTERNAL &&
+           v->type != LSA_TYPE_AS_OPAQ)
                nbr->area->dirty = 1;
 
        /* set correct timeout for reflooding the LSA */
@@ -774,13 +828,13 @@ lsa_generate_stub_sums(struct area *area
                        rn.cost = r->metric & LSA_METRIC_MASK;
 
                        /* update lsa but only if it was changed */
-                       v = lsa_find(area, LSA_TYPE_SUM_NETWORK,
+                       v = lsa_find_area(area, LSA_TYPE_SUM_NETWORK,
                            rn.prefix.s_addr, rde_router_id());
                        lsa = orig_sum_lsa(&rn, area, LSA_TYPE_SUM_NETWORK, 0);
                        lsa_merge(rde_nbr_self(area), lsa, v);
 
                        if (v == NULL)
-                               v = lsa_find(area, LSA_TYPE_SUM_NETWORK,
+                               v = lsa_find_area(area, LSA_TYPE_SUM_NETWORK,
                                    rn.prefix.s_addr, rde_router_id());
 
                        /*
@@ -817,4 +871,3 @@ lsa_equal(struct lsa *a, struct lsa *b)
 
        return (1);
 }
-
Index: ospfd/rde_spf.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/rde_spf.c,v
retrieving revision 1.71
diff -u -p -r1.71 rde_spf.c
--- ospfd/rde_spf.c     2 May 2011 11:45:55 -0000       1.71
+++ ospfd/rde_spf.c     2 May 2011 11:46:54 -0000
@@ -63,8 +63,8 @@ spf_calc(struct area *area)
        cand_list_clr();
 
        /* initialize SPF tree */
-       if ((v = spf_root = lsa_find(area, LSA_TYPE_ROUTER, rde_router_id(),
-           rde_router_id())) == NULL)
+       if ((v = spf_root = lsa_find_area(area, LSA_TYPE_ROUTER,
+           rde_router_id(), rde_router_id())) == NULL)
                /* empty area because no interface is active */
                return;
 
@@ -86,7 +86,7 @@ spf_calc(struct area *area)
                                case LINK_TYPE_POINTTOPOINT:
                                case LINK_TYPE_VIRTUAL:
                                        /* find router LSA */
-                                       w = lsa_find(area, LSA_TYPE_ROUTER,
+                                       w = lsa_find_area(area, LSA_TYPE_ROUTER,
                                            rtr_link->id, rtr_link->id);
                                        break;
                                case LINK_TYPE_TRANSIT_NET:
@@ -100,7 +100,7 @@ spf_calc(struct area *area)
                        case LSA_TYPE_NETWORK:
                                net_link = get_net_link(v, i);
                                /* find router LSA */
-                               w = lsa_find(area, LSA_TYPE_ROUTER,
+                               w = lsa_find_area(area, LSA_TYPE_ROUTER,
                                    net_link->att_rtr, net_link->att_rtr);
                                break;
                        default:
@@ -231,7 +231,7 @@ rt_calc(struct vertex *v, struct area *a
 
                /* TODO type 3 area address range check */
 
-               if ((w = lsa_find(area, LSA_TYPE_ROUTER,
+               if ((w = lsa_find_area(area, LSA_TYPE_ROUTER,
                    htonl(v->adv_rtr),
                    htonl(v->adv_rtr))) == NULL)
                        return;

Reply via email to