1/*	$OpenBSD: lsreq.c,v 1.15 2023/07/03 09:51:38 claudio 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/socket.h>
21#include <netinet/in.h>
22#include <netinet/ip6.h>
23#include <arpa/inet.h>
24#include <stdlib.h>
25
26#include "ospf6d.h"
27#include "ospf6.h"
28#include "log.h"
29#include "ospfe.h"
30
31/* link state request packet handling */
32int
33send_ls_req(struct nbr *nbr)
34{
35	struct in6_addr		 dst;
36	struct ls_req_hdr	 ls_req_hdr;
37	struct lsa_entry	*le, *nle;
38	struct ibuf		*buf;
39
40	if ((buf = ibuf_open(nbr->iface->mtu - sizeof(struct ip6_hdr))) == NULL)
41		fatal("send_ls_req");
42
43	switch (nbr->iface->type) {
44	case IF_TYPE_POINTOPOINT:
45		inet_pton(AF_INET6, AllSPFRouters, &dst);
46		break;
47	case IF_TYPE_BROADCAST:
48	case IF_TYPE_NBMA:
49	case IF_TYPE_POINTOMULTIPOINT:
50	case IF_TYPE_VIRTUALLINK:
51		dst = nbr->addr;
52		break;
53	default:
54		fatalx("send_ls_req: unknown interface type");
55	}
56
57	/* OSPF header */
58	if (gen_ospf_hdr(buf, nbr->iface, PACKET_TYPE_LS_REQUEST))
59		goto fail;
60
61	/* LSA header(s) */
62	for (le = TAILQ_FIRST(&nbr->ls_req_list);
63	    le != NULL && sizeof(ls_req_hdr) < ibuf_left(buf);
64	    le = nle) {
65		nbr->ls_req = nle = TAILQ_NEXT(le, entry);
66		ls_req_hdr.zero = 0;
67		ls_req_hdr.type = le->le_lsa->type;
68		ls_req_hdr.ls_id = le->le_lsa->ls_id;
69		ls_req_hdr.adv_rtr = le->le_lsa->adv_rtr;
70		if (ibuf_add(buf, &ls_req_hdr, sizeof(ls_req_hdr)))
71			goto fail;
72	}
73
74	/* calculate checksum */
75	if (upd_ospf_hdr(buf, nbr->iface))
76		goto fail;
77
78	if (send_packet(nbr->iface, buf, &dst) == -1)
79		goto fail;
80
81	ibuf_free(buf);
82	return (0);
83fail:
84	log_warn("send_ls_req");
85	ibuf_free(buf);
86	return (-1);
87}
88
89void
90recv_ls_req(struct nbr *nbr, char *buf, u_int16_t len)
91{
92	switch (nbr->state) {
93	case NBR_STA_DOWN:
94	case NBR_STA_ATTEMPT:
95	case NBR_STA_INIT:
96	case NBR_STA_2_WAY:
97	case NBR_STA_XSTRT:
98	case NBR_STA_SNAP:
99		log_debug("recv_ls_req: packet ignored in state %s, "
100		    "neighbor ID %s (%s)", nbr_state_name(nbr->state),
101		    inet_ntoa(nbr->id), nbr->iface->name);
102		break;
103	case NBR_STA_XCHNG:
104	case NBR_STA_LOAD:
105	case NBR_STA_FULL:
106		ospfe_imsg_compose_rde(IMSG_LS_REQ, nbr->peerid, 0, buf, len);
107		break;
108	default:
109		fatalx("recv_ls_req: unknown neighbor state");
110	}
111}
112
113/* link state request list */
114void
115ls_req_list_add(struct nbr *nbr, struct lsa_hdr *lsa)
116{
117	struct lsa_entry	*le;
118
119	if (lsa == NULL)
120		fatalx("ls_req_list_add: no LSA header");
121
122	if ((le = calloc(1, sizeof(*le))) == NULL)
123		fatal("ls_req_list_add");
124
125	TAILQ_INSERT_TAIL(&nbr->ls_req_list, le, entry);
126	le->le_lsa = lsa;
127	nbr->ls_req_cnt++;
128}
129
130struct lsa_entry *
131ls_req_list_get(struct nbr *nbr, struct lsa_hdr *lsa_hdr)
132{
133	struct lsa_entry	*le;
134
135	TAILQ_FOREACH(le, &nbr->ls_req_list, entry) {
136		if ((lsa_hdr->type == le->le_lsa->type) &&
137		    (lsa_hdr->ls_id == le->le_lsa->ls_id) &&
138		    (lsa_hdr->adv_rtr == le->le_lsa->adv_rtr))
139			return (le);
140	}
141	return (NULL);
142}
143
144void
145ls_req_list_free(struct nbr *nbr, struct lsa_entry *le)
146{
147	if (nbr->ls_req == le) {
148		nbr->ls_req = TAILQ_NEXT(le, entry);
149	}
150
151	TAILQ_REMOVE(&nbr->ls_req_list, le, entry);
152	free(le->le_lsa);
153	free(le);
154	nbr->ls_req_cnt--;
155
156	/* received all requested LSA(s), send a new LS req */
157	if (nbr->ls_req != NULL &&
158	    nbr->ls_req == TAILQ_FIRST(&nbr->ls_req_list)) {
159		start_ls_req_tx_timer(nbr);
160	}
161
162	/* we might not have received all DDs and are still in XCHNG */
163	if (ls_req_list_empty(nbr) && nbr->dd_pending == 0 &&
164	    nbr->state != NBR_STA_XCHNG)
165		nbr_fsm(nbr, NBR_EVT_LOAD_DONE);
166}
167
168void
169ls_req_list_clr(struct nbr *nbr)
170{
171	struct lsa_entry	*le;
172
173	while ((le = TAILQ_FIRST(&nbr->ls_req_list)) != NULL) {
174		TAILQ_REMOVE(&nbr->ls_req_list, le, entry);
175		free(le->le_lsa);
176		free(le);
177	}
178
179	nbr->ls_req_cnt = 0;
180	nbr->ls_req = NULL;
181}
182
183int
184ls_req_list_empty(struct nbr *nbr)
185{
186	return (TAILQ_EMPTY(&nbr->ls_req_list));
187}
188
189/* timers */
190void
191ls_req_tx_timer(int fd, short event, void *arg)
192{
193	struct nbr	*nbr = arg;
194	struct timeval	 tv;
195
196	switch (nbr->state) {
197	case NBR_STA_DOWN:
198	case NBR_STA_ATTEMPT:
199	case NBR_STA_INIT:
200	case NBR_STA_2_WAY:
201	case NBR_STA_SNAP:
202	case NBR_STA_XSTRT:
203	case NBR_STA_XCHNG:
204		return;
205	case NBR_STA_LOAD:
206		send_ls_req(nbr);
207		break;
208	case NBR_STA_FULL:
209		return;
210	default:
211		log_debug("ls_req_tx_timer: unknown neighbor state, "
212		    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
213		    nbr->iface->name);
214		break;
215	}
216
217	/* reschedule lsreq_tx_timer */
218	if (nbr->state == NBR_STA_LOAD) {
219		timerclear(&tv);
220		tv.tv_sec = nbr->iface->rxmt_interval;
221		if (evtimer_add(&nbr->lsreq_tx_timer, &tv) == -1)
222			fatal("ls_req_tx_timer");
223	}
224}
225
226void
227start_ls_req_tx_timer(struct nbr *nbr)
228{
229	struct timeval tv;
230
231	if (nbr == nbr->iface->self)
232		return;
233
234	timerclear(&tv);
235	if (evtimer_add(&nbr->lsreq_tx_timer, &tv) == -1)
236		fatal("start_ls_req_tx_timer");
237}
238
239void
240stop_ls_req_tx_timer(struct nbr *nbr)
241{
242	if (nbr == nbr->iface->self)
243		return;
244
245	if (evtimer_del(&nbr->lsreq_tx_timer) == -1)
246		fatal("stop_ls_req_tx_timer");
247}
248