1*bf2cf305Sclaudio /* $OpenBSD: lsreq.c,v 1.15 2023/07/03 09:51:38 claudio Exp $ */
2a1a4e97bSnorby
3a1a4e97bSnorby /*
4a1a4e97bSnorby * Copyright (c) 2004, 2005, 2007 Esben Norby <norby@openbsd.org>
5a1a4e97bSnorby *
6a1a4e97bSnorby * Permission to use, copy, modify, and distribute this software for any
7a1a4e97bSnorby * purpose with or without fee is hereby granted, provided that the above
8a1a4e97bSnorby * copyright notice and this permission notice appear in all copies.
9a1a4e97bSnorby *
10a1a4e97bSnorby * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11a1a4e97bSnorby * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12a1a4e97bSnorby * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13a1a4e97bSnorby * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14a1a4e97bSnorby * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15a1a4e97bSnorby * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16a1a4e97bSnorby * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a1a4e97bSnorby */
18a1a4e97bSnorby
19a1a4e97bSnorby #include <sys/types.h>
20a1a4e97bSnorby #include <sys/socket.h>
21a1a4e97bSnorby #include <netinet/in.h>
22df59d22fSclaudio #include <netinet/ip6.h>
23a1a4e97bSnorby #include <arpa/inet.h>
24a1a4e97bSnorby #include <stdlib.h>
25a1a4e97bSnorby
26a1a4e97bSnorby #include "ospf6d.h"
27a1a4e97bSnorby #include "ospf6.h"
28a1a4e97bSnorby #include "log.h"
29a1a4e97bSnorby #include "ospfe.h"
30a1a4e97bSnorby
31a1a4e97bSnorby /* link state request packet handling */
32a1a4e97bSnorby int
send_ls_req(struct nbr * nbr)33a1a4e97bSnorby send_ls_req(struct nbr *nbr)
34a1a4e97bSnorby {
3552bf80cbSclaudio struct in6_addr dst;
36a1a4e97bSnorby struct ls_req_hdr ls_req_hdr;
37a1a4e97bSnorby struct lsa_entry *le, *nle;
38e39620e5Snicm struct ibuf *buf;
39a1a4e97bSnorby
40df59d22fSclaudio if ((buf = ibuf_open(nbr->iface->mtu - sizeof(struct ip6_hdr))) == NULL)
41a1a4e97bSnorby fatal("send_ls_req");
42a1a4e97bSnorby
43a1a4e97bSnorby switch (nbr->iface->type) {
44a1a4e97bSnorby case IF_TYPE_POINTOPOINT:
4552bf80cbSclaudio inet_pton(AF_INET6, AllSPFRouters, &dst);
46a1a4e97bSnorby break;
47a1a4e97bSnorby case IF_TYPE_BROADCAST:
48a1a4e97bSnorby case IF_TYPE_NBMA:
49a1a4e97bSnorby case IF_TYPE_POINTOMULTIPOINT:
50a1a4e97bSnorby case IF_TYPE_VIRTUALLINK:
5152bf80cbSclaudio dst = nbr->addr;
52a1a4e97bSnorby break;
53a1a4e97bSnorby default:
54a1a4e97bSnorby fatalx("send_ls_req: unknown interface type");
55a1a4e97bSnorby }
56a1a4e97bSnorby
57a1a4e97bSnorby /* OSPF header */
58a1a4e97bSnorby if (gen_ospf_hdr(buf, nbr->iface, PACKET_TYPE_LS_REQUEST))
59a1a4e97bSnorby goto fail;
60a1a4e97bSnorby
610edf49a6Sbluhm /* LSA header(s) */
62*bf2cf305Sclaudio for (le = TAILQ_FIRST(&nbr->ls_req_list);
63*bf2cf305Sclaudio le != NULL && sizeof(ls_req_hdr) < ibuf_left(buf);
64*bf2cf305Sclaudio le = nle) {
65a1a4e97bSnorby nbr->ls_req = nle = TAILQ_NEXT(le, entry);
6617817b50Sclaudio ls_req_hdr.zero = 0;
6717817b50Sclaudio ls_req_hdr.type = le->le_lsa->type;
68a1a4e97bSnorby ls_req_hdr.ls_id = le->le_lsa->ls_id;
69a1a4e97bSnorby ls_req_hdr.adv_rtr = le->le_lsa->adv_rtr;
70e39620e5Snicm if (ibuf_add(buf, &ls_req_hdr, sizeof(ls_req_hdr)))
71a1a4e97bSnorby goto fail;
72a1a4e97bSnorby }
73a1a4e97bSnorby
74a1a4e97bSnorby /* calculate checksum */
75a1a4e97bSnorby if (upd_ospf_hdr(buf, nbr->iface))
76a1a4e97bSnorby goto fail;
77a1a4e97bSnorby
780a137951Sdenis if (send_packet(nbr->iface, buf, &dst) == -1)
790a137951Sdenis goto fail;
80a1a4e97bSnorby
81e39620e5Snicm ibuf_free(buf);
820a137951Sdenis return (0);
83a1a4e97bSnorby fail:
84a1a4e97bSnorby log_warn("send_ls_req");
85e39620e5Snicm ibuf_free(buf);
86a1a4e97bSnorby return (-1);
87a1a4e97bSnorby }
88a1a4e97bSnorby
89a1a4e97bSnorby void
recv_ls_req(struct nbr * nbr,char * buf,u_int16_t len)90a1a4e97bSnorby recv_ls_req(struct nbr *nbr, char *buf, u_int16_t len)
91a1a4e97bSnorby {
92a1a4e97bSnorby switch (nbr->state) {
93a1a4e97bSnorby case NBR_STA_DOWN:
94a1a4e97bSnorby case NBR_STA_ATTEMPT:
95a1a4e97bSnorby case NBR_STA_INIT:
96a1a4e97bSnorby case NBR_STA_2_WAY:
97a1a4e97bSnorby case NBR_STA_XSTRT:
98a1a4e97bSnorby case NBR_STA_SNAP:
99a1a4e97bSnorby log_debug("recv_ls_req: packet ignored in state %s, "
1009cc19ef1Ssthen "neighbor ID %s (%s)", nbr_state_name(nbr->state),
1019cc19ef1Ssthen inet_ntoa(nbr->id), nbr->iface->name);
102a1a4e97bSnorby break;
103a1a4e97bSnorby case NBR_STA_XCHNG:
104a1a4e97bSnorby case NBR_STA_LOAD:
105a1a4e97bSnorby case NBR_STA_FULL:
106980c654eSclaudio ospfe_imsg_compose_rde(IMSG_LS_REQ, nbr->peerid, 0, buf, len);
107a1a4e97bSnorby break;
108a1a4e97bSnorby default:
109a1a4e97bSnorby fatalx("recv_ls_req: unknown neighbor state");
110a1a4e97bSnorby }
111a1a4e97bSnorby }
112a1a4e97bSnorby
113a1a4e97bSnorby /* link state request list */
114a1a4e97bSnorby void
ls_req_list_add(struct nbr * nbr,struct lsa_hdr * lsa)115a1a4e97bSnorby ls_req_list_add(struct nbr *nbr, struct lsa_hdr *lsa)
116a1a4e97bSnorby {
117a1a4e97bSnorby struct lsa_entry *le;
118a1a4e97bSnorby
119a1a4e97bSnorby if (lsa == NULL)
120a1a4e97bSnorby fatalx("ls_req_list_add: no LSA header");
121a1a4e97bSnorby
122a1a4e97bSnorby if ((le = calloc(1, sizeof(*le))) == NULL)
123a1a4e97bSnorby fatal("ls_req_list_add");
124a1a4e97bSnorby
125a1a4e97bSnorby TAILQ_INSERT_TAIL(&nbr->ls_req_list, le, entry);
126a1a4e97bSnorby le->le_lsa = lsa;
127a1a4e97bSnorby nbr->ls_req_cnt++;
128a1a4e97bSnorby }
129a1a4e97bSnorby
130a1a4e97bSnorby struct lsa_entry *
ls_req_list_get(struct nbr * nbr,struct lsa_hdr * lsa_hdr)131a1a4e97bSnorby ls_req_list_get(struct nbr *nbr, struct lsa_hdr *lsa_hdr)
132a1a4e97bSnorby {
133a1a4e97bSnorby struct lsa_entry *le;
134a1a4e97bSnorby
135a1a4e97bSnorby TAILQ_FOREACH(le, &nbr->ls_req_list, entry) {
136a1a4e97bSnorby if ((lsa_hdr->type == le->le_lsa->type) &&
137a1a4e97bSnorby (lsa_hdr->ls_id == le->le_lsa->ls_id) &&
138a1a4e97bSnorby (lsa_hdr->adv_rtr == le->le_lsa->adv_rtr))
139a1a4e97bSnorby return (le);
140a1a4e97bSnorby }
141a1a4e97bSnorby return (NULL);
142a1a4e97bSnorby }
143a1a4e97bSnorby
144a1a4e97bSnorby void
ls_req_list_free(struct nbr * nbr,struct lsa_entry * le)145a1a4e97bSnorby ls_req_list_free(struct nbr *nbr, struct lsa_entry *le)
146a1a4e97bSnorby {
147a1a4e97bSnorby if (nbr->ls_req == le) {
148a1a4e97bSnorby nbr->ls_req = TAILQ_NEXT(le, entry);
149a1a4e97bSnorby }
150a1a4e97bSnorby
151a1a4e97bSnorby TAILQ_REMOVE(&nbr->ls_req_list, le, entry);
152a1a4e97bSnorby free(le->le_lsa);
153a1a4e97bSnorby free(le);
154a1a4e97bSnorby nbr->ls_req_cnt--;
155a1a4e97bSnorby
156a1a4e97bSnorby /* received all requested LSA(s), send a new LS req */
157a1a4e97bSnorby if (nbr->ls_req != NULL &&
158a1a4e97bSnorby nbr->ls_req == TAILQ_FIRST(&nbr->ls_req_list)) {
159a1a4e97bSnorby start_ls_req_tx_timer(nbr);
160a1a4e97bSnorby }
161a1a4e97bSnorby
1620a05e8afSsthen /* we might not have received all DDs and are still in XCHNG */
1630a05e8afSsthen if (ls_req_list_empty(nbr) && nbr->dd_pending == 0 &&
1640a05e8afSsthen nbr->state != NBR_STA_XCHNG)
165a1a4e97bSnorby nbr_fsm(nbr, NBR_EVT_LOAD_DONE);
166a1a4e97bSnorby }
167a1a4e97bSnorby
168a1a4e97bSnorby void
ls_req_list_clr(struct nbr * nbr)169a1a4e97bSnorby ls_req_list_clr(struct nbr *nbr)
170a1a4e97bSnorby {
171a1a4e97bSnorby struct lsa_entry *le;
172a1a4e97bSnorby
173a1a4e97bSnorby while ((le = TAILQ_FIRST(&nbr->ls_req_list)) != NULL) {
174a1a4e97bSnorby TAILQ_REMOVE(&nbr->ls_req_list, le, entry);
175a1a4e97bSnorby free(le->le_lsa);
176a1a4e97bSnorby free(le);
177a1a4e97bSnorby }
178a1a4e97bSnorby
179a1a4e97bSnorby nbr->ls_req_cnt = 0;
180a1a4e97bSnorby nbr->ls_req = NULL;
181a1a4e97bSnorby }
182a1a4e97bSnorby
183a1a4e97bSnorby int
ls_req_list_empty(struct nbr * nbr)184a1a4e97bSnorby ls_req_list_empty(struct nbr *nbr)
185a1a4e97bSnorby {
186a1a4e97bSnorby return (TAILQ_EMPTY(&nbr->ls_req_list));
187a1a4e97bSnorby }
188a1a4e97bSnorby
189a1a4e97bSnorby /* timers */
190a1a4e97bSnorby void
ls_req_tx_timer(int fd,short event,void * arg)191a1a4e97bSnorby ls_req_tx_timer(int fd, short event, void *arg)
192a1a4e97bSnorby {
193a1a4e97bSnorby struct nbr *nbr = arg;
194a1a4e97bSnorby struct timeval tv;
195a1a4e97bSnorby
196a1a4e97bSnorby switch (nbr->state) {
197a1a4e97bSnorby case NBR_STA_DOWN:
198a1a4e97bSnorby case NBR_STA_ATTEMPT:
199a1a4e97bSnorby case NBR_STA_INIT:
200a1a4e97bSnorby case NBR_STA_2_WAY:
201a1a4e97bSnorby case NBR_STA_SNAP:
202a1a4e97bSnorby case NBR_STA_XSTRT:
203a1a4e97bSnorby case NBR_STA_XCHNG:
204a1a4e97bSnorby return;
205a1a4e97bSnorby case NBR_STA_LOAD:
206a1a4e97bSnorby send_ls_req(nbr);
207a1a4e97bSnorby break;
208a1a4e97bSnorby case NBR_STA_FULL:
209a1a4e97bSnorby return;
210a1a4e97bSnorby default:
211a1a4e97bSnorby log_debug("ls_req_tx_timer: unknown neighbor state, "
2129cc19ef1Ssthen "neighbor ID %s (%s)", inet_ntoa(nbr->id),
2139cc19ef1Ssthen nbr->iface->name);
214a1a4e97bSnorby break;
215a1a4e97bSnorby }
216a1a4e97bSnorby
217a1a4e97bSnorby /* reschedule lsreq_tx_timer */
218a1a4e97bSnorby if (nbr->state == NBR_STA_LOAD) {
219a1a4e97bSnorby timerclear(&tv);
220a1a4e97bSnorby tv.tv_sec = nbr->iface->rxmt_interval;
221a1a4e97bSnorby if (evtimer_add(&nbr->lsreq_tx_timer, &tv) == -1)
222a1a4e97bSnorby fatal("ls_req_tx_timer");
223a1a4e97bSnorby }
224a1a4e97bSnorby }
225a1a4e97bSnorby
226a1a4e97bSnorby void
start_ls_req_tx_timer(struct nbr * nbr)227a1a4e97bSnorby start_ls_req_tx_timer(struct nbr *nbr)
228a1a4e97bSnorby {
229a1a4e97bSnorby struct timeval tv;
230a1a4e97bSnorby
231a1a4e97bSnorby if (nbr == nbr->iface->self)
232a1a4e97bSnorby return;
233a1a4e97bSnorby
234a1a4e97bSnorby timerclear(&tv);
235a1a4e97bSnorby if (evtimer_add(&nbr->lsreq_tx_timer, &tv) == -1)
236a1a4e97bSnorby fatal("start_ls_req_tx_timer");
237a1a4e97bSnorby }
238a1a4e97bSnorby
239a1a4e97bSnorby void
stop_ls_req_tx_timer(struct nbr * nbr)240a1a4e97bSnorby stop_ls_req_tx_timer(struct nbr *nbr)
241a1a4e97bSnorby {
242a1a4e97bSnorby if (nbr == nbr->iface->self)
243a1a4e97bSnorby return;
244a1a4e97bSnorby
245a1a4e97bSnorby if (evtimer_del(&nbr->lsreq_tx_timer) == -1)
246a1a4e97bSnorby fatal("stop_ls_req_tx_timer");
247a1a4e97bSnorby }
248