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