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 */
32 int
send_ls_req(struct nbr * nbr)33 send_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);
83 fail:
84 log_warn("send_ls_req");
85 ibuf_free(buf);
86 return (-1);
87 }
88
89 void
recv_ls_req(struct nbr * nbr,char * buf,u_int16_t len)90 recv_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 */
114 void
ls_req_list_add(struct nbr * nbr,struct lsa_hdr * lsa)115 ls_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
130 struct lsa_entry *
ls_req_list_get(struct nbr * nbr,struct lsa_hdr * lsa_hdr)131 ls_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
144 void
ls_req_list_free(struct nbr * nbr,struct lsa_entry * le)145 ls_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
168 void
ls_req_list_clr(struct nbr * nbr)169 ls_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
183 int
ls_req_list_empty(struct nbr * nbr)184 ls_req_list_empty(struct nbr *nbr)
185 {
186 return (TAILQ_EMPTY(&nbr->ls_req_list));
187 }
188
189 /* timers */
190 void
ls_req_tx_timer(int fd,short event,void * arg)191 ls_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
226 void
start_ls_req_tx_timer(struct nbr * nbr)227 start_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
239 void
stop_ls_req_tx_timer(struct nbr * nbr)240 stop_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