1/*
2 * Copyright (C) 2002 Yasuhiro Ohara
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING.  If not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22#include "ospf6d.h"
23
24static int intra_index;
25#define IS_OSPF6_DUMP_INTRA (ospf6_dump_is_on (intra_index))
26
27#define ADD    0
28#define REMOVE 1
29
30static void
31ospf6_intra_route_calculate (int type, struct ospf6_lsa *lsa,
32                             struct ospf6_route_req *topo_entry)
33{
34  struct ospf6_intra_area_prefix_lsa *intra_prefix;
35  char *start, *end;
36  struct ospf6_prefix *ospf6_prefix;
37  struct ospf6_route_req request;
38  struct ospf6_area *area;
39
40  intra_prefix = OSPF6_LSA_HEADER_END (lsa->header);
41
42  area = lsa->scope;
43  assert (area);
44
45  start = (char *) (intra_prefix + 1);
46  end = (char *) lsa->header + ntohs (lsa->header->length);
47  for (ospf6_prefix = (struct ospf6_prefix *) start;
48       (char *) ospf6_prefix < end;
49       ospf6_prefix = OSPF6_NEXT_PREFIX (ospf6_prefix))
50    {
51      memset (&request, 0, sizeof (request));
52
53      request.route.type = OSPF6_DEST_TYPE_NETWORK;
54      request.route.prefix.family = AF_INET6;
55      request.route.prefix.prefixlen = ospf6_prefix->prefix_length;
56      ospf6_prefix_in6_addr (ospf6_prefix, &request.route.prefix.u.prefix6);
57
58      request.path.type = OSPF6_PATH_TYPE_INTRA;
59      request.path.area_id = area->area_id;
60      request.path.origin.type = lsa->header->type;
61      request.path.origin.id = lsa->header->id;
62      request.path.origin.adv_router = lsa->header->adv_router;
63      request.path.cost = topo_entry->path.cost +
64                          ntohs (ospf6_prefix->prefix_metric);
65      request.path.capability[0] = topo_entry->path.capability[0];
66      request.path.capability[1] = topo_entry->path.capability[1];
67      request.path.capability[2] = topo_entry->path.capability[2];
68
69      memcpy (&request.nexthop.address, &topo_entry->nexthop.address,
70              sizeof (request.nexthop.address));
71      request.nexthop.ifindex = topo_entry->nexthop.ifindex;
72
73      if (type == ADD)
74        ospf6_route_add (&request, area->route_table);
75      else if (type == REMOVE)
76        ospf6_route_remove (&request, area->route_table);
77      else
78        assert (0);
79    }
80}
81
82int
83ospf6_intra_prefix_database_hook_remove (void *data)
84{
85  struct ospf6_lsa *lsa = data;
86  struct ospf6_area *area;
87  struct ospf6_intra_area_prefix_lsa *iap;
88  struct prefix_ls prefix_ls;
89  struct ospf6_route_req topo_entry;
90
91  if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTRA_PREFIX))
92    return 0;
93
94  area = (struct ospf6_area *) lsa->scope;
95  assert (area);
96
97  if (IS_OSPF6_DUMP_INTRA)
98    zlog_info ("INTRA: area %s remove: %s", area->str, lsa->str);
99
100  iap = OSPF6_LSA_HEADER_END (lsa->header);
101  memset (&prefix_ls, 0, sizeof (prefix_ls));
102  prefix_ls.prefixlen = 64;
103  prefix_ls.adv_router.s_addr = iap->refer_advrtr;
104  prefix_ls.id.s_addr = iap->refer_lsid;
105
106  if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
107      iap->refer_lsid != htonl (0))
108    {
109      zlog_warn ("SPF: Malformed ID %lu of Router reference in %s",
110                 (u_long) ntohl (iap->refer_lsid), lsa->str);
111      prefix_ls.id.s_addr = htonl (0);
112    }
113
114  ospf6_route_lookup (&topo_entry, (struct prefix *) &prefix_ls,
115                      area->table_topology);
116
117  while (iap->refer_lstype == topo_entry.path.origin.type &&
118         iap->refer_lsid == topo_entry.path.origin.id &&
119         iap->refer_advrtr == topo_entry.path.origin.adv_router)
120    {
121      ospf6_intra_route_calculate (REMOVE, lsa, &topo_entry);
122      ospf6_route_next (&topo_entry);
123    }
124  return 0;
125}
126
127int
128ospf6_intra_prefix_database_hook_add (void *data)
129{
130  struct ospf6_lsa *lsa = data;
131  struct ospf6_area *area;
132  struct ospf6_intra_area_prefix_lsa *iap;
133  struct prefix_ls prefix_ls;
134  struct ospf6_route_req topo_entry;
135
136  if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTRA_PREFIX))
137    return 0;
138
139  area = (struct ospf6_area *) lsa->scope;
140  assert (area);
141
142  if (IS_LSA_MAXAGE (lsa))
143    {
144      ospf6_intra_prefix_database_hook_remove (lsa);
145      return 0;
146    }
147
148  if (IS_OSPF6_DUMP_INTRA)
149    zlog_info ("INTRA: area %s add: %s", area->str, lsa->str);
150
151  iap = OSPF6_LSA_HEADER_END (lsa->header);
152
153  memset (&prefix_ls, 0, sizeof (struct prefix_ls));
154  prefix_ls.prefixlen = 64;
155  prefix_ls.adv_router.s_addr = iap->refer_advrtr;
156  prefix_ls.id.s_addr = iap->refer_lsid;
157
158  if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
159      iap->refer_lsid != htonl (0))
160    {
161      zlog_warn ("INTRA: Malformed ID %lu of Router reference in %s",
162                 (u_long) ntohl (iap->refer_lsid), lsa->str);
163      prefix_ls.id.s_addr = htonl (0);
164    }
165
166  ospf6_route_lookup (&topo_entry, (struct prefix *) &prefix_ls,
167                      area->table_topology);
168
169  while (iap->refer_lstype == topo_entry.path.origin.type &&
170         iap->refer_lsid == topo_entry.path.origin.id &&
171         iap->refer_advrtr == topo_entry.path.origin.adv_router)
172    {
173      ospf6_intra_route_calculate (ADD, lsa, &topo_entry);
174      ospf6_route_next (&topo_entry);
175    }
176  return 0;
177}
178
179void
180ospf6_intra_topology_add (void *data)
181{
182  struct ospf6_route_req *topo_entry = data;
183  struct ospf6_area *area;
184  struct ospf6_intra_area_prefix_lsa *iap;
185  struct ospf6_lsdb_node node;
186
187  area = ospf6_area_lookup (topo_entry->path.area_id, ospf6);
188  if (! area)
189    return;
190
191  if (topo_entry->route.type == OSPF6_DEST_TYPE_ROUTER &&
192      (CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ||
193       CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_E)))
194    ospf6_route_add (topo_entry, ospf6->topology_table);
195
196  for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
197                        area->lsdb);
198       ! ospf6_lsdb_is_end (&node);
199       ospf6_lsdb_next (&node))
200    {
201      if (IS_OSPF6_DUMP_INTRA)
202        zlog_info ("INTRA: topology hook: Examining %s (%p)",
203                   node.lsa->str, node.lsa);
204
205      if (IS_LSA_MAXAGE (node.lsa))
206        continue;
207
208      iap = OSPF6_LSA_HEADER_END (node.lsa->header);
209
210      if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
211          iap->refer_lsid != htonl (0))
212        {
213          zlog_warn ("INTRA: Malformed ID %lu of Router reference in %s",
214                     (u_long) ntohl (iap->refer_lsid), node.lsa->str);
215        }
216
217      if (iap->refer_lstype != topo_entry->path.origin.type ||
218          iap->refer_lsid != topo_entry->path.origin.id ||
219          iap->refer_advrtr != topo_entry->path.origin.adv_router)
220        continue;
221
222      ospf6_intra_route_calculate (ADD, node.lsa, topo_entry);
223    }
224}
225
226void
227ospf6_intra_topology_remove (void *data)
228{
229  struct ospf6_route_req *topo_entry = data;
230  struct ospf6_area *area;
231  struct ospf6_intra_area_prefix_lsa *iap;
232  struct ospf6_lsdb_node node;
233
234  area = ospf6_area_lookup (topo_entry->path.area_id, ospf6);
235  if (! area)
236    return;
237
238  if (topo_entry->route.type == OSPF6_DEST_TYPE_ROUTER &&
239      (CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ||
240       CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_E)))
241    ospf6_route_remove (topo_entry, ospf6->topology_table);
242
243  for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
244                        area->lsdb);
245       ! ospf6_lsdb_is_end (&node);
246       ospf6_lsdb_next (&node))
247    {
248      if (IS_LSA_MAXAGE (node.lsa))
249        continue;
250
251      iap = OSPF6_LSA_HEADER_END (node.lsa->header);
252
253      if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
254          iap->refer_lsid != htonl (0))
255        zlog_warn ("SPF: Malformed ID %lu of Router reference in %s",
256                   (u_long) ntohl (iap->refer_lsid), node.lsa->str);
257
258      if (iap->refer_lstype != topo_entry->path.origin.type ||
259          iap->refer_lsid != topo_entry->path.origin.id ||
260          iap->refer_advrtr != topo_entry->path.origin.adv_router)
261        continue;
262
263      ospf6_intra_route_calculate (REMOVE, node.lsa, topo_entry);
264    }
265}
266
267
268/*****************************************/
269/* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */
270/*****************************************/
271
272#define CONTINUE_IF_ADDRESS_LINKLOCAL(addr)\
273  if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6))\
274    {\
275      char buf[64];\
276      prefix2str (addr, buf, sizeof (buf));\
277      if (IS_OSPF6_DUMP_PREFIX)\
278        zlog_info ("  Filter out Linklocal: %s", buf);\
279      continue;\
280    }
281
282#define CONTINUE_IF_ADDRESS_UNSPECIFIED(addr)\
283  if (IN6_IS_ADDR_UNSPECIFIED (&(addr)->u.prefix6))\
284    {\
285      char buf[64];\
286      prefix2str (addr, buf, sizeof (buf));\
287      if (IS_OSPF6_DUMP_PREFIX)\
288        zlog_info ("  Filter out Unspecified: %s", buf);\
289      continue;\
290    }
291
292#define CONTINUE_IF_ADDRESS_LOOPBACK(addr)\
293  if (IN6_IS_ADDR_LOOPBACK (&(addr)->u.prefix6))\
294    {\
295      char buf[64];\
296      prefix2str (addr, buf, sizeof (buf));\
297      if (IS_OSPF6_DUMP_PREFIX)\
298        zlog_info ("  Filter out Loopback: %s", buf);\
299      continue;\
300    }
301
302#define CONTINUE_IF_ADDRESS_V4COMPAT(addr)\
303  if (IN6_IS_ADDR_V4COMPAT (&(addr)->u.prefix6))\
304    {\
305      char buf[64];\
306      prefix2str (addr, buf, sizeof (buf));\
307      if (IS_OSPF6_DUMP_PREFIX)\
308        zlog_info ("  Filter out V4Compat: %s", buf);\
309      continue;\
310    }
311
312#define CONTINUE_IF_ADDRESS_V4MAPPED(addr)\
313  if (IN6_IS_ADDR_V4MAPPED (&(addr)->u.prefix6))\
314    {\
315      char buf[64];\
316      prefix2str (addr, buf, sizeof (buf));\
317      if (IS_OSPF6_DUMP_PREFIX)\
318        zlog_info ("  Filter out V4Mapped: %s", buf);\
319      continue;\
320    }
321
322
323int
324ospf6_lsa_intra_prefix_show (struct vty *vty, struct ospf6_lsa *lsa)
325{
326  struct ospf6_intra_area_prefix_lsa *iap_lsa;
327  struct ospf6_prefix *prefix;
328  unsigned short prefixnum;
329  char buf[128], type[32], id[32], adv_router[32];
330  struct in6_addr in6;
331  char *start, *end, *current;
332
333  assert (lsa->header);
334  iap_lsa = (struct ospf6_intra_area_prefix_lsa *) (lsa->header + 1);
335
336  prefixnum = ntohs (iap_lsa->prefix_number);
337  ospf6_lsa_type_string (iap_lsa->refer_lstype, type, sizeof (type));
338  inet_ntop (AF_INET, &iap_lsa->refer_lsid, id, sizeof (id));
339  inet_ntop (AF_INET, &iap_lsa->refer_advrtr, adv_router,
340             sizeof (adv_router));
341
342  vty_out (vty, "     Number of Prefix: %d%s", prefixnum, VTY_NEWLINE);
343  vty_out (vty, "     Referenced LS Type: %s%s", type, VTY_NEWLINE);
344  vty_out (vty, "     Referenced LS ID: %s%s", id, VTY_NEWLINE);
345  vty_out (vty, "     Referenced Advertising Router: %s%s", adv_router,
346           VTY_NEWLINE);
347
348  start = (char *) lsa->header + sizeof (struct ospf6_lsa_header)
349          + sizeof (struct ospf6_intra_area_prefix_lsa);
350  end = (char *) lsa->header + ntohs (lsa->header->length);
351
352  for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix))
353    {
354      prefix = (struct ospf6_prefix *) current;
355      if (current + OSPF6_PREFIX_SIZE (prefix) > end)
356        {
357          vty_out (vty, "    Trailing %d byte garbage ... Malformed%s",
358                   end - current, VTY_NEWLINE);
359          return -1;
360        }
361
362      ospf6_prefix_options_str (prefix->prefix_options, buf, sizeof (buf));
363      vty_out (vty, "     Prefix Options: %s%s", buf, VTY_NEWLINE);
364
365      ospf6_prefix_in6_addr (prefix, &in6);
366      inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
367      vty_out (vty, "     Prefix: %s/%d%s",
368               buf, prefix->prefix_length, VTY_NEWLINE);
369    }
370
371  return 0;
372}
373
374void
375ospf6_lsa_intra_prefix_update_transit (char *ifname)
376{
377  char buffer [MAXLSASIZE];
378  u_int16_t size;
379  struct ospf6_lsa *old;
380  struct interface *ifp;
381  struct ospf6_interface *o6i;
382  struct ospf6_neighbor *o6n;
383
384  struct ospf6_intra_area_prefix_lsa *iap;
385  struct ospf6_lsdb_node n;
386  listnode node;
387  char *start, *end, *current;
388  struct ospf6_prefix *prefix, *dup, *src, *dst;
389  struct ospf6_link_lsa *link;
390  char buf[128];
391  int count, prefix_num;
392
393  list adv_list;
394
395  ifp = if_lookup_by_name (ifname);
396  if (! ifp)
397    {
398      zlog_warn ("Update Intra-Prefix (Transit): No such Interface: %s",
399                  ifname);
400      return;
401    }
402
403  o6i = (struct ospf6_interface *) ifp->info;
404  if (! o6i || ! o6i->area)
405    {
406      zlog_warn ("Update Intra-Prefix (Transit): Interface not enabled: %s",
407                  ifname);
408      return;
409    }
410
411  /* find previous LSA */
412  old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
413                           htonl (o6i->if_id), ospf6->router_id,
414                           o6i->area);
415
416  /* Don't originate Network-LSA if not DR */
417  if (o6i->state != IFS_DR)
418    {
419      if (old)
420        {
421          if (IS_OSPF6_DUMP_PREFIX)
422            zlog_info ("Update Intra-Prefix (Transit): %s not DR",
423                       o6i->interface->name);
424          ospf6_lsa_premature_aging (old);
425        }
426      return;
427    }
428
429  /* If none of neighbor is adjacent to us */
430  count = 0;
431  o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
432  if (count == 0)
433    {
434      if (IS_OSPF6_DUMP_PREFIX)
435        zlog_info ("Update Intra-Prefix (Transit): %s is Stub",
436                   o6i->interface->name);
437      if (old)
438        ospf6_lsa_premature_aging (old);
439      return;
440    }
441
442  if (IS_OSPF6_DUMP_PREFIX)
443    zlog_info ("Update Intra-Prefix (Transit): Interface %s",
444               o6i->interface->name);
445
446  adv_list = list_new ();
447
448  /* foreach Link-LSA associated with this Link */
449  for (ospf6_lsdb_type (&n, htons (OSPF6_LSA_TYPE_LINK), o6i->lsdb);
450       ! ospf6_lsdb_is_end (&n); ospf6_lsdb_next (&n))
451    {
452      if (IS_LSA_MAXAGE (n.lsa))
453        continue;
454
455      if (IS_OSPF6_DUMP_PREFIX)
456        zlog_info ("Update Intra-Prefix (Transit): Checking %s",
457                    n.lsa->str);
458
459      /* Check status of the advertising router */
460      if (n.lsa->header->adv_router != o6i->area->ospf6->router_id)
461        {
462          o6n = ospf6_neighbor_lookup (n.lsa->header->adv_router, o6i);
463          if (! o6n)
464            {
465              if (IS_OSPF6_DUMP_PREFIX)
466                zlog_info ("Update Intra-Prefix (Transit): neighbor not found");
467              continue;
468            }
469
470          if (o6n->state != NBS_FULL)
471            {
472              if (IS_OSPF6_DUMP_PREFIX)
473                zlog_info ("Update Intra-Prefix (Transit): %s not FULL",
474                           o6n->str);
475              continue;
476            }
477        }
478
479      /* For each Prefix in this Link-LSA */
480      link = (struct ospf6_link_lsa *) (n.lsa->header + 1);
481      prefix_num = ntohl (link->llsa_prefix_num);
482
483      if (IS_OSPF6_DUMP_PREFIX)
484        zlog_info ("  Prefix #%d", prefix_num);
485
486      start = (char *) (link + 1);
487      end = (char *) (n.lsa->header) + ntohs (n.lsa->header->length);
488      prefix = (struct ospf6_prefix *) start;
489      for (current = start; current < end;
490           current += OSPF6_PREFIX_SIZE (prefix))
491        {
492          prefix = (struct ospf6_prefix *) current;
493          ospf6_prefix_string (prefix, buf, sizeof (buf));
494
495          /* Check duplicate prefix */
496          dup = ospf6_prefix_lookup (adv_list, prefix);
497          if (dup)
498            {
499              if (IS_OSPF6_DUMP_PREFIX)
500                zlog_info ("  Duplicate %s", buf);
501              dup->prefix_options |= prefix->prefix_options;
502              continue;
503            }
504
505          if (prefix_num <= 0)
506            {
507              zlog_warn ("  Wong prefix number ...");
508              break;
509            }
510
511          if (IS_OSPF6_DUMP_PREFIX)
512            zlog_info ("  Prefix %s", buf);
513
514          /* copy prefix to advertise list */
515          ospf6_prefix_add (adv_list, prefix);
516
517          prefix_num --;
518        }
519    }
520
521  /* if no prefix to advertise, return */
522  if (listcount (adv_list) == 0)
523    {
524      if (IS_OSPF6_DUMP_PREFIX)
525        zlog_info ("  No Prefix to advertise");
526      if (old)
527        ospf6_lsa_premature_aging (old);
528      return;
529    }
530
531  /* prepare buffer */
532  memset (buffer, 0, sizeof (buffer));
533  size = sizeof (struct ospf6_intra_area_prefix_lsa);
534  iap = (struct ospf6_intra_area_prefix_lsa *) buffer;
535
536  /* Set Referenced LSA field */
537  iap->refer_lstype = htons (OSPF6_LSA_TYPE_NETWORK);
538  iap->refer_lsid = htonl (o6i->if_id);
539  iap->refer_advrtr = o6i->area->ospf6->router_id;
540
541  dst = (struct ospf6_prefix *) (iap + 1);
542  for (node = listhead (adv_list); node; nextnode (node))
543    {
544      src = (struct ospf6_prefix *) getdata (node);
545
546      memcpy (dst, src, OSPF6_PREFIX_SIZE (src));
547
548      size += OSPF6_PREFIX_SIZE (dst);
549      dst = OSPF6_NEXT_PREFIX (dst);
550    }
551  iap->prefix_number = htons (listcount (adv_list));
552
553  while ((node = listhead (adv_list)) != NULL)
554    {
555      prefix = getdata (node);
556      ospf6_prefix_delete (prefix);
557      listnode_delete (adv_list, prefix);
558    }
559  list_delete (adv_list);
560
561  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
562                       htonl (o6i->if_id), ospf6->router_id,
563                       buffer, size, o6i->area);
564}
565
566void
567ospf6_lsa_intra_prefix_update_stub (u_int32_t area_id)
568{
569  char buffer [MAXLSASIZE];
570  u_int16_t size;
571  struct ospf6_lsa *old;
572  struct ospf6_area *o6a;
573  int count;
574
575  struct ospf6_intra_area_prefix_lsa *iap;
576  listnode i,j;
577  struct ospf6_interface *o6i = NULL;
578  struct ospf6_prefix *prefix, *dst, *src;
579  struct connected *c;
580  char buf[128];
581
582  list adv_list;
583  listnode node;
584  char prefix_buf[sizeof (struct ospf6_prefix) + sizeof (struct in6_addr)];
585
586  o6a = ospf6_area_lookup (area_id, ospf6);
587  if (! o6a)
588    {
589      char tmp[16];
590      inet_ntop (AF_INET, &area_id, tmp, sizeof (tmp));
591      zlog_warn ("Update Intra-Prefix (Stub): No such area: %s", tmp);
592      return;
593    }
594  else if (IS_OSPF6_DUMP_PREFIX)
595    {
596      zlog_info ("Update Intra-Prefix (Stub): area: %s", o6a->str);
597    }
598
599  /* find previous LSA */
600  old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
601                           htonl (0), ospf6->router_id,
602                           o6a); /* xxx, ls-id */
603
604  adv_list = list_new ();
605
606  /* Examin for each interface */
607  for (i = listhead (o6a->if_list); i; nextnode (i))
608    {
609      o6i = (struct ospf6_interface *) getdata (i);
610
611      if (o6i->state == IFS_DOWN)
612        {
613          if (IS_OSPF6_DUMP_PREFIX)
614            zlog_info ("    Interface %s: down", o6i->interface->name);
615          continue;
616        }
617
618      count = 0;
619      o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
620      if (o6i->state != IFS_LOOPBACK && o6i->state != IFS_PTOP &&
621          count != 0)
622        {
623          /* This interface's prefix will be included in DR's */
624          if (IS_OSPF6_DUMP_PREFIX)
625            zlog_info ("    Interface %s: not stub", o6i->interface->name);
626          continue;
627        }
628
629      if (IS_OSPF6_DUMP_PREFIX)
630        zlog_info ("    Interface %s:", o6i->interface->name);
631
632      /* copy foreach address prefix */
633      for (j = listhead (o6i->interface->connected); j; nextnode (j))
634        {
635          c = (struct connected *) getdata (j);
636
637          /* filter prefix not IPv6 */
638          if (c->address->family != AF_INET6)
639            continue;
640
641          /* for log */
642          prefix2str (c->address, buf, sizeof (buf));
643
644          CONTINUE_IF_ADDRESS_LINKLOCAL (c->address);
645          CONTINUE_IF_ADDRESS_UNSPECIFIED (c->address);
646          CONTINUE_IF_ADDRESS_LOOPBACK (c->address);
647          CONTINUE_IF_ADDRESS_V4COMPAT (c->address);
648          CONTINUE_IF_ADDRESS_V4MAPPED (c->address);
649
650          /* filter prefix specified by configuration */
651          if (o6i->plist_name)
652            {
653              struct prefix_list *plist;
654              enum prefix_list_type result = PREFIX_PERMIT;
655
656              plist = prefix_list_lookup (AFI_IP6, o6i->plist_name);
657              if (plist)
658                result = prefix_list_apply (plist, c->address);
659              else
660                zlog_warn ("Update Intra-Prefix (Stub): "
661                           "Prefix list \"%s\" not found",
662                           o6i->plist_name);
663
664              if (result == PREFIX_DENY)
665                {
666                  if (IS_OSPF6_DUMP_PREFIX)
667                    zlog_info ("    %s: Filtered by %s",
668                               buf, o6i->plist_name);
669                  continue;
670                }
671            }
672
673          /* initialize buffer for ospf6 prefix */
674          memset (prefix_buf, 0, sizeof (prefix_buf));
675          prefix = (struct ospf6_prefix *) prefix_buf;
676
677          /* set ospf6 prefix according to its state */
678          /* xxx, virtual links */
679          if (! CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX) &&
680              (o6i->state == IFS_LOOPBACK || o6i->state == IFS_PTOP
681              /* xxx, PoinToMultiPoint I/F type */ ))
682            {
683              prefix->prefix_length = 128;
684              prefix->prefix_options = OSPF6_PREFIX_OPTION_LA;
685              prefix->prefix_metric = htons (0);
686              memcpy (prefix + 1, &c->address->u.prefix6,
687                      OSPF6_PREFIX_SPACE (prefix->prefix_length));
688            }
689          else
690            {
691              struct prefix_ipv6 prefix_ipv6;
692              /* apply mask */
693              prefix_copy ((struct prefix *) &prefix_ipv6, c->address);
694              apply_mask_ipv6 (&prefix_ipv6);
695
696              prefix->prefix_length = prefix_ipv6.prefixlen;
697              prefix->prefix_options = 0;  /* xxx, no options yet */
698              prefix->prefix_metric = htons (o6i->cost);
699              memcpy (prefix + 1, &prefix_ipv6.prefix,
700                      OSPF6_PREFIX_SPACE (prefix->prefix_length));
701            }
702
703          ospf6_prefix_string (prefix, buf, sizeof (buf));
704          if (IS_OSPF6_DUMP_PREFIX)
705            zlog_info ("    Advertise %s", buf);
706
707          /* check in the prefix to advertising prefix list */
708          ospf6_prefix_add (adv_list, prefix);
709        }
710    }
711
712  /* If no prefix to advertise */
713  if (listcount (adv_list) == 0)
714    {
715      if (IS_OSPF6_DUMP_PREFIX)
716        zlog_info ("    No prefix to advertise");
717      if (old)
718        ospf6_lsa_premature_aging (old);
719      return;
720    }
721
722  /* prepare buffer */
723  memset (buffer, 0, sizeof (buffer));
724  size = sizeof (struct ospf6_intra_area_prefix_lsa);
725  iap = (struct ospf6_intra_area_prefix_lsa *) buffer;
726
727  /* Set Referenced LSA field */
728  iap->refer_lstype = htons (OSPF6_LSA_TYPE_ROUTER);
729  iap->refer_lsid = htonl (0);
730  iap->refer_advrtr = o6a->ospf6->router_id;
731
732  dst = (struct ospf6_prefix *) (iap + 1);
733  for (node = listhead (adv_list); node; nextnode (node))
734    {
735      src = (struct ospf6_prefix *) getdata (node);
736
737      memcpy (dst, src, OSPF6_PREFIX_SIZE (src));
738
739      size += OSPF6_PREFIX_SIZE (dst);
740      dst = OSPF6_NEXT_PREFIX (dst);
741    }
742  iap->prefix_number = htons (listcount (adv_list));
743
744  while ((node = listhead (adv_list)) != NULL)
745    {
746      prefix = getdata (node);
747      ospf6_prefix_delete (prefix);
748      listnode_delete (adv_list, prefix);
749    }
750  list_delete (adv_list);
751
752  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
753                       htonl (0) /* xxx */, ospf6->router_id,
754                       buffer, size, o6a);
755}
756
757int
758ospf6_lsa_intra_prefix_hook_interface (void *interface)
759{
760  struct ospf6_interface *o6i = interface;
761  if (o6i->area)
762    {
763      ospf6_lsa_intra_prefix_update_transit (o6i->interface->name);
764      ospf6_lsa_intra_prefix_update_stub (o6i->area->area_id);
765    }
766  return 0;
767}
768
769int
770ospf6_lsa_intra_prefix_hook_neighbor (void *neighbor)
771{
772  struct ospf6_neighbor *o6n = neighbor;
773  if (o6n->ospf6_interface->area)
774    {
775      ospf6_lsa_intra_prefix_update_transit (o6n->ospf6_interface->interface->name);
776      ospf6_lsa_intra_prefix_update_stub (o6n->ospf6_interface->area->area_id);
777    }
778  return 0;
779}
780
781int
782ospf6_intra_prefix_link_database_hook (void *new)
783{
784  struct ospf6_lsa *lsa = new;
785  struct ospf6_interface *o6i;
786
787  if (lsa->header->type != htons (OSPF6_LSA_TYPE_LINK))
788    return 0;
789
790  o6i = lsa->scope;
791  if (o6i->state != IFS_DR)
792    return 0;
793
794  ospf6_lsa_intra_prefix_update_transit (o6i->interface->name);
795  ospf6_lsa_intra_prefix_update_stub (o6i->area->area_id);
796  return 0;
797}
798
799int
800ospf6_lsa_intra_prefix_refresh (void *old)
801{
802  struct ospf6_lsa *lsa = old;
803  struct ospf6_interface *o6i;
804  struct ospf6_area *o6a;
805  u_int32_t id;
806
807  id = ntohl (lsa->header->id);
808  if (id)
809    {
810      o6i = ospf6_interface_lookup_by_index (id);
811      if (o6i)
812        ospf6_lsa_intra_prefix_update_transit (o6i->interface->name);
813      else
814        ospf6_lsa_premature_aging (lsa);
815    }
816  else
817    {
818      o6a = lsa->scope;
819      ospf6_lsa_intra_prefix_update_stub (o6a->area_id);
820    }
821
822  return 0;
823}
824
825void
826ospf6_intra_prefix_register ()
827{
828  struct ospf6_lsa_slot slot, *sp;
829  struct ospf6_hook hook;
830
831  memset (&slot, 0, sizeof (struct ospf6_lsa_slot));
832  slot.type              = htons (OSPF6_LSA_TYPE_INTRA_PREFIX);
833  slot.name              = "Intra-Prefix";
834  slot.func_show         = ospf6_lsa_intra_prefix_show;
835  slot.func_refresh      = ospf6_lsa_intra_prefix_refresh;
836  ospf6_lsa_slot_register (&slot);
837
838  memset (&hook, 0, sizeof (hook));
839  hook.name = "OriginateIntraPrefix";
840  hook.hook_add = ospf6_lsa_intra_prefix_hook_interface;
841  hook.hook_change = ospf6_lsa_intra_prefix_hook_interface;
842  hook.hook_remove = NULL; /* XXX */
843  ospf6_hook_register (&hook, &interface_hook);
844
845  memset (&hook, 0, sizeof (hook));
846  hook.name = "OriginateIntraPrefix";
847  hook.hook_add = ospf6_lsa_intra_prefix_hook_neighbor;
848  hook.hook_change = ospf6_lsa_intra_prefix_hook_neighbor;
849  hook.hook_remove = ospf6_lsa_intra_prefix_hook_neighbor;
850  ospf6_hook_register (&hook, &neighbor_hook);
851
852  sp = ospf6_lsa_slot_get (htons (OSPF6_LSA_TYPE_INTRA_PREFIX));
853  hook.name = "CalculateIntraPrefix";
854  hook.hook_add = ospf6_intra_prefix_database_hook_add;
855  hook.hook_change = ospf6_intra_prefix_database_hook_add;
856  hook.hook_remove = ospf6_intra_prefix_database_hook_remove;
857  ospf6_hook_register (&hook, &sp->database_hook);
858}
859
860void
861ospf6_intra_database_hook_intra_prefix (struct ospf6_lsa *old,
862                                        struct ospf6_lsa *new)
863{
864  if (old)
865    ospf6_intra_prefix_database_hook_remove (old);
866  if (new && ! IS_LSA_MAXAGE (new))
867    ospf6_intra_prefix_database_hook_add (new);
868}
869
870void
871ospf6_intra_database_hook_link (struct ospf6_lsa *old,
872                                struct ospf6_lsa *new)
873{
874  ospf6_intra_prefix_link_database_hook (new);
875  ospf6_spf_database_hook (old, new);
876}
877
878void
879ospf6_intra_init ()
880{
881  ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTRA_PREFIX & OSPF6_LSTYPE_CODE_MASK].hook =
882    ospf6_intra_database_hook_intra_prefix;
883  ospf6_lsdb_hook[OSPF6_LSA_TYPE_LINK & OSPF6_LSTYPE_CODE_MASK].hook =
884    ospf6_intra_database_hook_link;
885
886  intra_index = ospf6_dump_install ("intra-area", "Intra-area calculation\n");
887  ospf6_intra_prefix_register ();
888}
889
890
891