1 /* $OpenBSD: lsack.c,v 1.10 2023/03/08 04:43:14 guenther 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
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "ospf6d.h"
29 #include "ospf6.h"
30 #include "log.h"
31 #include "ospfe.h"
32
33 int send_ls_ack(struct iface *, struct in6_addr, struct ibuf *);
34 struct ibuf *prepare_ls_ack(struct iface *);
35 void start_ls_ack_tx_timer_now(struct iface *);
36
37 /* link state acknowledgement packet handling */
38 struct ibuf *
prepare_ls_ack(struct iface * iface)39 prepare_ls_ack(struct iface *iface)
40 {
41 struct ibuf *buf;
42
43 if ((buf = ibuf_open(iface->mtu - sizeof(struct ip6_hdr))) == NULL) {
44 log_warn("prepare_ls_ack");
45 return (NULL);
46 }
47
48 /* OSPF header */
49 if (gen_ospf_hdr(buf, iface, PACKET_TYPE_LS_ACK)) {
50 log_warn("prepare_ls_ack");
51 ibuf_free(buf);
52 return (NULL);
53 }
54
55 return (buf);
56 }
57
58 int
send_ls_ack(struct iface * iface,struct in6_addr addr,struct ibuf * buf)59 send_ls_ack(struct iface *iface, struct in6_addr addr, struct ibuf *buf)
60 {
61 /* calculate checksum */
62 if (upd_ospf_hdr(buf, iface)) {
63 log_warn("send_ls_ack");
64 return (-1);
65 }
66
67 if (send_packet(iface, buf, &addr) == -1) {
68 log_warn("send_ls_ack");
69 return (-1);
70 }
71 return (0);
72 }
73
74 int
send_direct_ack(struct iface * iface,struct in6_addr addr,void * d,size_t len)75 send_direct_ack(struct iface *iface, struct in6_addr addr, void *d, size_t len)
76 {
77 struct ibuf *buf;
78 int ret;
79
80 if ((buf = prepare_ls_ack(iface)) == NULL)
81 return (-1);
82
83 /* LS ack(s) */
84 if (ibuf_add(buf, d, len)) {
85 log_warn("send_direct_ack");
86 ibuf_free(buf);
87 return (-1);
88 }
89
90 ret = send_ls_ack(iface, addr, buf);
91 ibuf_free(buf);
92 return (ret);
93 }
94
95 void
recv_ls_ack(struct nbr * nbr,char * buf,u_int16_t len)96 recv_ls_ack(struct nbr *nbr, char *buf, u_int16_t len)
97 {
98 struct lsa_hdr lsa_hdr;
99
100 switch (nbr->state) {
101 case NBR_STA_DOWN:
102 case NBR_STA_ATTEMPT:
103 case NBR_STA_INIT:
104 case NBR_STA_2_WAY:
105 case NBR_STA_XSTRT:
106 case NBR_STA_SNAP:
107 log_debug("recv_ls_ack: packet ignored in state %s, "
108 "neighbor ID %s (%s)", nbr_state_name(nbr->state),
109 inet_ntoa(nbr->id), nbr->iface->name);
110 break;
111 case NBR_STA_XCHNG:
112 case NBR_STA_LOAD:
113 case NBR_STA_FULL:
114 while (len >= sizeof(lsa_hdr)) {
115 memcpy(&lsa_hdr, buf, sizeof(lsa_hdr));
116
117 if (lsa_hdr_check(nbr, &lsa_hdr)) {
118 /* try both list in case of DROTHER */
119 if (nbr->iface->state & IF_STA_DROTHER)
120 (void)ls_retrans_list_del(
121 nbr->iface->self, &lsa_hdr);
122 (void)ls_retrans_list_del(nbr, &lsa_hdr);
123 }
124
125 buf += sizeof(lsa_hdr);
126 len -= sizeof(lsa_hdr);
127 }
128 if (len > 0) {
129 log_warnx("recv_ls_ack: bad packet size, "
130 "neighbor ID %s (%s)", inet_ntoa(nbr->id),
131 nbr->iface->name);
132 return;
133 }
134 break;
135 default:
136 fatalx("recv_ls_ack: unknown neighbor state");
137 }
138 }
139
140 int
lsa_hdr_check(struct nbr * nbr,struct lsa_hdr * lsa_hdr)141 lsa_hdr_check(struct nbr *nbr, struct lsa_hdr *lsa_hdr)
142 {
143 /* invalid age */
144 if ((ntohs(lsa_hdr->age) < 1) || (ntohs(lsa_hdr->age) > MAX_AGE)) {
145 log_debug("lsa_hdr_check: invalid age, neighbor ID %s (%s)",
146 inet_ntoa(nbr->id), nbr->iface->name);
147 return (0);
148 }
149
150 /* invalid type */
151 switch (ntohs(lsa_hdr->type)) {
152 case LSA_TYPE_LINK:
153 case LSA_TYPE_ROUTER:
154 case LSA_TYPE_NETWORK:
155 case LSA_TYPE_INTER_A_PREFIX:
156 case LSA_TYPE_INTER_A_ROUTER:
157 case LSA_TYPE_INTRA_A_PREFIX:
158 case LSA_TYPE_EXTERNAL:
159 break;
160 default:
161 log_debug("lsa_hdr_check: invalid LSA type %d, "
162 "neighbor ID %s (%s)",
163 lsa_hdr->type, inet_ntoa(nbr->id), nbr->iface->name);
164 return (0);
165 }
166
167 /* invalid sequence number */
168 if (ntohl(lsa_hdr->seq_num) == RESV_SEQ_NUM) {
169 log_debug("ls_hdr_check: invalid seq num, "
170 "neighbor ID %s (%s)", inet_ntoa(nbr->id),
171 nbr->iface->name);
172 return (0);
173 }
174
175 return (1);
176 }
177
178 /* link state ack list */
179 void
ls_ack_list_add(struct iface * iface,struct lsa_hdr * lsa)180 ls_ack_list_add(struct iface *iface, struct lsa_hdr *lsa)
181 {
182 struct lsa_entry *le;
183
184 if (lsa == NULL)
185 fatalx("ls_ack_list_add: no LSA header");
186
187 if ((le = calloc(1, sizeof(*le))) == NULL)
188 fatal("ls_ack_list_add");
189
190 if (ls_ack_list_empty(iface))
191 start_ls_ack_tx_timer(iface);
192
193 TAILQ_INSERT_TAIL(&iface->ls_ack_list, le, entry);
194 le->le_lsa = lsa;
195 iface->ls_ack_cnt++;
196
197 /* reschedule now if we have enough for a full packet */
198 if (iface->ls_ack_cnt >
199 ((iface->mtu - PACKET_HDR) / sizeof(struct lsa_hdr))) {
200 start_ls_ack_tx_timer_now(iface);
201 }
202 }
203
204 void
ls_ack_list_free(struct iface * iface,struct lsa_entry * le)205 ls_ack_list_free(struct iface *iface, struct lsa_entry *le)
206 {
207 TAILQ_REMOVE(&iface->ls_ack_list, le, entry);
208 free(le->le_lsa);
209 free(le);
210
211 iface->ls_ack_cnt--;
212 }
213
214 void
ls_ack_list_clr(struct iface * iface)215 ls_ack_list_clr(struct iface *iface)
216 {
217 struct lsa_entry *le;
218
219 while ((le = TAILQ_FIRST(&iface->ls_ack_list)) != NULL) {
220 TAILQ_REMOVE(&iface->ls_ack_list, le, entry);
221 free(le->le_lsa);
222 free(le);
223 }
224 iface->ls_ack_cnt = 0;
225 }
226
227 int
ls_ack_list_empty(struct iface * iface)228 ls_ack_list_empty(struct iface *iface)
229 {
230 return (TAILQ_EMPTY(&iface->ls_ack_list));
231 }
232
233 /* timers */
234 void
ls_ack_tx_timer(int fd,short event,void * arg)235 ls_ack_tx_timer(int fd, short event, void *arg)
236 {
237 struct in6_addr addr;
238 struct iface *iface = arg;
239 struct lsa_entry *le, *nle;
240 struct nbr *nbr;
241 struct ibuf *buf;
242 int cnt;
243
244 while (!ls_ack_list_empty(iface)) {
245 if ((buf = prepare_ls_ack(iface)) == NULL)
246 fatal("ls_ack_tx_timer");
247 cnt = 0;
248
249 for (le = TAILQ_FIRST(&iface->ls_ack_list); le != NULL;
250 le = nle) {
251 nle = TAILQ_NEXT(le, entry);
252 if (ibuf_left(buf) < sizeof(struct lsa_hdr))
253 break;
254 if (ibuf_add(buf, le->le_lsa, sizeof(struct lsa_hdr)))
255 break;
256 ls_ack_list_free(iface, le);
257 cnt++;
258 }
259 if (cnt == 0) {
260 log_warnx("ls_ack_tx_timer: lost in space");
261 ibuf_free(buf);
262 return;
263 }
264
265 /* send LS ack(s) but first set correct destination */
266 switch (iface->type) {
267 case IF_TYPE_POINTOPOINT:
268 inet_pton(AF_INET6, AllSPFRouters, &addr);
269 send_ls_ack(iface, addr, buf);
270 break;
271 case IF_TYPE_BROADCAST:
272 if (iface->state & IF_STA_DRORBDR)
273 inet_pton(AF_INET6, AllSPFRouters, &addr);
274 else
275 inet_pton(AF_INET6, AllDRouters, &addr);
276 send_ls_ack(iface, addr, buf);
277 break;
278 case IF_TYPE_NBMA:
279 case IF_TYPE_POINTOMULTIPOINT:
280 case IF_TYPE_VIRTUALLINK:
281 LIST_FOREACH(nbr, &iface->nbr_list, entry) {
282 if (nbr == iface->self)
283 continue;
284 if (!(nbr->state & NBR_STA_FLOOD))
285 continue;
286 send_ls_ack(iface, nbr->addr, buf);
287 }
288 break;
289 default:
290 fatalx("lsa_ack_tx_timer: unknown interface type");
291 }
292 ibuf_free(buf);
293 }
294 }
295
296 void
start_ls_ack_tx_timer(struct iface * iface)297 start_ls_ack_tx_timer(struct iface *iface)
298 {
299 struct timeval tv;
300
301 timerclear(&tv);
302 tv.tv_sec = iface->rxmt_interval / 2;
303
304 if (evtimer_add(&iface->lsack_tx_timer, &tv) == -1)
305 fatal("start_ls_ack_tx_timer");
306 }
307
308 void
start_ls_ack_tx_timer_now(struct iface * iface)309 start_ls_ack_tx_timer_now(struct iface *iface)
310 {
311 struct timeval tv;
312
313 timerclear(&tv);
314 if (evtimer_add(&iface->lsack_tx_timer, &tv) == -1)
315 fatal("start_ls_ack_tx_timer_now");
316 }
317
318 void
stop_ls_ack_tx_timer(struct iface * iface)319 stop_ls_ack_tx_timer(struct iface *iface)
320 {
321 if (evtimer_del(&iface->lsack_tx_timer) == -1)
322 fatal("stop_ls_ack_tx_timer");
323 }
324