1/*	$OpenBSD: area.c,v 1.5 2019/12/23 07:33:49 denis Exp $ */
2
3/*
4 * Copyright (c) 2004, 2005, 2007 Esben Norby <norby@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/tree.h>
21
22#include <err.h>
23#include <stdlib.h>
24
25#include "ospf6.h"
26#include "ospf6d.h"
27#include "ospfe.h"
28#include "rde.h"
29#include "log.h"
30
31struct area *
32area_new(void)
33{
34	struct area *area = NULL;
35
36	if ((area = calloc(1, sizeof(*area))) == NULL)
37		errx(1, "area_new: calloc");
38
39	LIST_INIT(&area->iface_list);
40	LIST_INIT(&area->nbr_list);
41	RB_INIT(&area->lsa_tree);
42
43	return (area);
44}
45
46int
47area_del(struct area *area)
48{
49	struct iface	*iface = NULL;
50	struct vertex	*v, *nv;
51	struct rde_nbr	*n;
52
53	/* area is removed so neutralize the demotion done by the area */
54	if (area->active == 0)
55		ospfe_demote_area(area, 1);
56
57	/* clean lists */
58	while ((iface = LIST_FIRST(&area->iface_list)) != NULL) {
59		LIST_REMOVE(iface, entry);
60		if_del(iface);
61	}
62
63	while ((n = LIST_FIRST(&area->nbr_list)) != NULL)
64		rde_nbr_del(n);
65
66	for (v = RB_MIN(lsa_tree, &area->lsa_tree); v != NULL; v = nv) {
67		nv = RB_NEXT(lsa_tree, &area->lsa_tree, v);
68		vertex_free(v);
69	}
70
71	free(area);
72
73	return (0);
74}
75
76struct area *
77area_find(struct ospfd_conf *conf, struct in_addr area_id)
78{
79	struct area	*area;
80
81	LIST_FOREACH(area, &conf->area_list, entry) {
82		if (area->id.s_addr == area_id.s_addr) {
83			return (area);
84		}
85	}
86
87	return (NULL);
88}
89
90void
91area_track(struct area *area)
92{
93	int		 old = area->active;
94	struct iface	*iface;
95
96	area->active = 0;
97	LIST_FOREACH(iface, &area->iface_list, entry) {
98		if (iface->state & IF_STA_DOWN)
99			continue;
100		area->active = 1;
101		break;
102	}
103
104	if (area->active != old) {
105		ospfe_imsg_compose_rde(IMSG_AREA_CHANGE, area->id.s_addr, 0,
106		    &area->active, sizeof(area->active));
107		ospfe_demote_area(area, old == 0);
108	}
109}
110
111int
112area_border_router(struct ospfd_conf *conf)
113{
114	struct area	*area;
115	int		 active = 0;
116
117	LIST_FOREACH(area, &conf->area_list, entry)
118		if (area->active)
119			active++;
120
121	return (active > 1);
122}
123
124u_int32_t
125area_ospf_options(struct area *area)
126{
127	u_int32_t	opt = OSPF_OPTION_V6 | OSPF_OPTION_R;
128
129	if (area && !area->stub)
130		opt |= OSPF_OPTION_E;
131
132	return (opt);
133}
134