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