xref: /openbsd/usr.sbin/ldpd/init.c (revision d415bd75)
1 /*	$OpenBSD: init.c,v 1.37 2017/03/04 00:15:35 renato Exp $ */
2 
3 /*
4  * Copyright (c) 2009 Michele Marchetto <michele@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 <arpa/inet.h>
21 #include <string.h>
22 
23 #include "ldpd.h"
24 #include "ldpe.h"
25 #include "log.h"
26 
27 static int	gen_init_prms_tlv(struct ibuf *, struct nbr *);
28 static int	gen_cap_dynamic_tlv(struct ibuf *);
29 static int	gen_cap_twcard_tlv(struct ibuf *, int);
30 static int	gen_cap_unotif_tlv(struct ibuf *, int);
31 
32 void
33 send_init(struct nbr *nbr)
34 {
35 	struct ibuf		*buf;
36 	uint16_t		 size;
37 	int			 err = 0;
38 
39 	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
40 
41 	size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE +
42 	    CAP_TLV_DYNAMIC_SIZE + CAP_TLV_TWCARD_SIZE + CAP_TLV_UNOTIF_SIZE;
43 	if ((buf = ibuf_open(size)) == NULL)
44 		fatal(__func__);
45 
46 	err |= gen_ldp_hdr(buf, size);
47 	size -= LDP_HDR_SIZE;
48 	err |= gen_msg_hdr(buf, MSG_TYPE_INIT, size);
49 	err |= gen_init_prms_tlv(buf, nbr);
50 	err |= gen_cap_dynamic_tlv(buf);
51 	err |= gen_cap_twcard_tlv(buf, 1);
52 	err |= gen_cap_unotif_tlv(buf, 1);
53 	if (err) {
54 		ibuf_free(buf);
55 		return;
56 	}
57 
58 	evbuf_enqueue(&nbr->tcp->wbuf, buf);
59 }
60 
61 int
62 recv_init(struct nbr *nbr, char *buf, uint16_t len)
63 {
64 	struct ldp_msg		msg;
65 	struct sess_prms_tlv	sess;
66 	uint16_t		max_pdu_len;
67 	int			caps_rcvd = 0;
68 
69 	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
70 
71 	memcpy(&msg, buf, sizeof(msg));
72 	buf += LDP_MSG_SIZE;
73 	len -= LDP_MSG_SIZE;
74 
75 	if (len < SESS_PRMS_SIZE) {
76 		session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
77 		return (-1);
78 	}
79 	memcpy(&sess, buf, sizeof(sess));
80 	if (ntohs(sess.length) != SESS_PRMS_LEN) {
81 		session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
82 		return (-1);
83 	}
84 	if (ntohs(sess.proto_version) != LDP_VERSION) {
85 		session_shutdown(nbr, S_BAD_PROTO_VER, msg.id, msg.type);
86 		return (-1);
87 	}
88 	if (ntohs(sess.keepalive_time) < MIN_KEEPALIVE) {
89 		session_shutdown(nbr, S_KEEPALIVE_BAD, msg.id, msg.type);
90 		return (-1);
91 	}
92 	if (sess.lsr_id != leconf->rtr_id.s_addr ||
93 	    ntohs(sess.lspace_id) != 0) {
94 		session_shutdown(nbr, S_NO_HELLO, msg.id, msg.type);
95 		return (-1);
96 	}
97 
98 	buf += SESS_PRMS_SIZE;
99 	len -= SESS_PRMS_SIZE;
100 
101 	/* Optional Parameters */
102 	while (len > 0) {
103 		struct tlv 	tlv;
104 		uint16_t	tlv_type;
105 		uint16_t	tlv_len;
106 
107 		if (len < sizeof(tlv)) {
108 			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
109 			return (-1);
110 		}
111 
112 		memcpy(&tlv, buf, TLV_HDR_SIZE);
113 		tlv_type = ntohs(tlv.type);
114 		tlv_len = ntohs(tlv.length);
115 		if (tlv_len + TLV_HDR_SIZE > len) {
116 			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
117 			return (-1);
118 		}
119 		buf += TLV_HDR_SIZE;
120 		len -= TLV_HDR_SIZE;
121 
122 		/*
123 		 * RFC 5561 - Section 6:
124 		 * "The S-bit of a Capability Parameter in an Initialization
125 		 * message MUST be 1 and SHOULD be ignored on receipt".
126 		 */
127 		switch (tlv_type) {
128 		case TLV_TYPE_ATMSESSIONPAR:
129 			session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
130 			return (-1);
131 		case TLV_TYPE_FRSESSION:
132 			session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
133 			return (-1);
134 		case TLV_TYPE_DYNAMIC_CAP:
135 			if (tlv_len != CAP_TLV_DYNAMIC_LEN) {
136 				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
137 				    msg.type);
138 				return (-1);
139 			}
140 
141 			if (caps_rcvd & F_CAP_TLV_RCVD_DYNAMIC) {
142 				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
143 				    msg.type);
144 				return (-1);
145 			}
146 			caps_rcvd |= F_CAP_TLV_RCVD_DYNAMIC;
147 
148 			nbr->flags |= F_NBR_CAP_DYNAMIC;
149 
150 			log_debug("%s: lsr-id %s announced the Dynamic "
151 			    "Capability Announcement capability", __func__,
152 			    inet_ntoa(nbr->id));
153 			break;
154 		case TLV_TYPE_TWCARD_CAP:
155 			if (tlv_len != CAP_TLV_TWCARD_LEN) {
156 				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
157 				    msg.type);
158 				return (-1);
159 			}
160 
161 			if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) {
162 				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
163 				    msg.type);
164 				return (-1);
165 			}
166 			caps_rcvd |= F_CAP_TLV_RCVD_TWCARD;
167 
168 			nbr->flags |= F_NBR_CAP_TWCARD;
169 
170 			log_debug("%s: lsr-id %s announced the Typed Wildcard "
171 			    "FEC capability", __func__, inet_ntoa(nbr->id));
172 			break;
173 		case TLV_TYPE_UNOTIF_CAP:
174 			if (tlv_len != CAP_TLV_UNOTIF_LEN) {
175 				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
176 				    msg.type);
177 				return (-1);
178 			}
179 
180 			if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) {
181 				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
182 				    msg.type);
183 				return (-1);
184 			}
185 			caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF;
186 
187 			nbr->flags |= F_NBR_CAP_UNOTIF;
188 
189 			log_debug("%s: lsr-id %s announced the Unrecognized "
190 			    "Notification capability", __func__,
191 			    inet_ntoa(nbr->id));
192 			break;
193 		default:
194 			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
195 				send_notification_rtlvs(nbr, S_UNSSUPORTDCAP,
196 				    msg.id, msg.type, tlv_type, tlv_len, buf);
197 			/* ignore unknown tlv */
198 			break;
199 		}
200 		buf += tlv_len;
201 		len -= tlv_len;
202 	}
203 
204 	nbr->keepalive = min(nbr_get_keepalive(nbr->af, nbr->id),
205 	    ntohs(sess.keepalive_time));
206 
207 	max_pdu_len = ntohs(sess.max_pdu_len);
208 	/*
209 	 * RFC 5036 - Section 3.5.3:
210 	 * "A value of 255 or less specifies the default maximum length of
211 	 * 4096 octets".
212 	 */
213 	if (max_pdu_len <= 255)
214 		max_pdu_len = LDP_MAX_LEN;
215 	nbr->max_pdu_len = min(max_pdu_len, LDP_MAX_LEN);
216 
217 	nbr_fsm(nbr, NBR_EVT_INIT_RCVD);
218 
219 	return (0);
220 }
221 
222 void
223 send_capability(struct nbr *nbr, uint16_t capability, int enable)
224 {
225 	struct ibuf		*buf;
226 	uint16_t		 size;
227 	int			 err = 0;
228 
229 	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
230 
231 	size = LDP_HDR_SIZE + LDP_MSG_SIZE + CAP_TLV_DYNAMIC_SIZE;
232 	if ((buf = ibuf_open(size)) == NULL)
233 		fatal(__func__);
234 
235 	err |= gen_ldp_hdr(buf, size);
236 	size -= LDP_HDR_SIZE;
237 	err |= gen_msg_hdr(buf, MSG_TYPE_CAPABILITY, size);
238 
239 	switch (capability) {
240 	case TLV_TYPE_TWCARD_CAP:
241 		err |= gen_cap_twcard_tlv(buf, enable);
242 		break;
243 	case TLV_TYPE_UNOTIF_CAP:
244 		err |= gen_cap_unotif_tlv(buf, enable);
245 		break;
246 	case TLV_TYPE_DYNAMIC_CAP:
247 		/*
248 		 * RFC 5561 - Section 9:
249 		 * "An LDP speaker MUST NOT include the Dynamic Capability
250 		 * Announcement Parameter in Capability messages sent to
251 		 * its peers".
252 		 */
253 		/* FALLTHROUGH */
254 	default:
255 		fatalx("send_capability: unsupported capability");
256 	}
257 
258 	if (err) {
259 		ibuf_free(buf);
260 		return;
261 	}
262 
263 	evbuf_enqueue(&nbr->tcp->wbuf, buf);
264 	nbr_fsm(nbr, NBR_EVT_PDU_SENT);
265 }
266 
267 int
268 recv_capability(struct nbr *nbr, char *buf, uint16_t len)
269 {
270 	struct ldp_msg	 msg;
271 	int		 enable = 0;
272 	int		 caps_rcvd = 0;
273 
274 	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
275 
276 	memcpy(&msg, buf, sizeof(msg));
277 	buf += LDP_MSG_SIZE;
278 	len -= LDP_MSG_SIZE;
279 
280 	/* Optional Parameters */
281 	while (len > 0) {
282 		struct tlv 	 tlv;
283 		uint16_t	 tlv_type;
284 		uint16_t	 tlv_len;
285 		uint8_t		 reserved;
286 
287 		if (len < sizeof(tlv)) {
288 			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
289 			return (-1);
290 		}
291 
292 		memcpy(&tlv, buf, TLV_HDR_SIZE);
293 		tlv_type = ntohs(tlv.type);
294 		tlv_len = ntohs(tlv.length);
295 		if (tlv_len + TLV_HDR_SIZE > len) {
296 			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
297 			return (-1);
298 		}
299 		buf += TLV_HDR_SIZE;
300 		len -= TLV_HDR_SIZE;
301 
302 		switch (tlv_type) {
303 		case TLV_TYPE_TWCARD_CAP:
304 			if (tlv_len != CAP_TLV_TWCARD_LEN) {
305 				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
306 				    msg.type);
307 				return (-1);
308 			}
309 
310 			if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) {
311 				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
312 				    msg.type);
313 				return (-1);
314 			}
315 			caps_rcvd |= F_CAP_TLV_RCVD_TWCARD;
316 
317 			memcpy(&reserved, buf, sizeof(reserved));
318 			enable = reserved & STATE_BIT;
319 			if (enable)
320 				nbr->flags |= F_NBR_CAP_TWCARD;
321 			else
322 				nbr->flags &= ~F_NBR_CAP_TWCARD;
323 
324 			log_debug("%s: lsr-id %s %s the Typed Wildcard FEC "
325 			    "capability", __func__, inet_ntoa(nbr->id),
326 			    (enable) ? "announced" : "withdrew");
327 			break;
328 		case TLV_TYPE_UNOTIF_CAP:
329 			if (tlv_len != CAP_TLV_UNOTIF_LEN) {
330 				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
331 				    msg.type);
332 				return (-1);
333 			}
334 
335 			if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) {
336 				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
337 				    msg.type);
338 				return (-1);
339 			}
340 			caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF;
341 
342 			memcpy(&reserved, buf, sizeof(reserved));
343 			enable = reserved & STATE_BIT;
344 			if (enable)
345 				nbr->flags |= F_NBR_CAP_UNOTIF;
346 			else
347 				nbr->flags &= ~F_NBR_CAP_UNOTIF;
348 
349 			log_debug("%s: lsr-id %s %s the Unrecognized "
350 			    "Notification capability", __func__,
351 			    inet_ntoa(nbr->id), (enable) ? "announced" :
352 			    "withdrew");
353 			break;
354 		case TLV_TYPE_DYNAMIC_CAP:
355 			/*
356 		 	 * RFC 5561 - Section 9:
357 			 * "An LDP speaker that receives a Capability message
358 			 * from a peer that includes the Dynamic Capability
359 			 * Announcement Parameter SHOULD silently ignore the
360 			 * parameter and process any other Capability Parameters
361 			 * in the message".
362 			 */
363 			/* FALLTHROUGH */
364 		default:
365 			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
366 				send_notification_rtlvs(nbr, S_UNSSUPORTDCAP,
367 				    msg.id, msg.type, tlv_type, tlv_len, buf);
368 			/* ignore unknown tlv */
369 			break;
370 		}
371 		buf += tlv_len;
372 		len -= tlv_len;
373 	}
374 
375 	nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
376 
377 	return (0);
378 }
379 
380 static int
381 gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr)
382 {
383 	struct sess_prms_tlv	parms;
384 
385 	memset(&parms, 0, sizeof(parms));
386 	parms.type = htons(TLV_TYPE_COMMONSESSION);
387 	parms.length = htons(SESS_PRMS_LEN);
388 	parms.proto_version = htons(LDP_VERSION);
389 	parms.keepalive_time = htons(nbr_get_keepalive(nbr->af, nbr->id));
390 	parms.reserved = 0;
391 	parms.pvlim = 0;
392 	parms.max_pdu_len = 0;
393 	parms.lsr_id = nbr->id.s_addr;
394 	parms.lspace_id = 0;
395 
396 	return (ibuf_add(buf, &parms, SESS_PRMS_SIZE));
397 }
398 
399 static int
400 gen_cap_dynamic_tlv(struct ibuf *buf)
401 {
402 	struct capability_tlv	cap;
403 
404 	memset(&cap, 0, sizeof(cap));
405 	cap.type = htons(TLV_TYPE_DYNAMIC_CAP);
406 	cap.length = htons(CAP_TLV_DYNAMIC_LEN);
407 	/* the S-bit is always 1 for the Dynamic Capability Announcement */
408 	cap.reserved = STATE_BIT;
409 
410 	return (ibuf_add(buf, &cap, CAP_TLV_DYNAMIC_SIZE));
411 }
412 
413 static int
414 gen_cap_twcard_tlv(struct ibuf *buf, int enable)
415 {
416 	struct capability_tlv	cap;
417 
418 	memset(&cap, 0, sizeof(cap));
419 	cap.type = htons(TLV_TYPE_TWCARD_CAP);
420 	cap.length = htons(CAP_TLV_TWCARD_LEN);
421 	if (enable)
422 		cap.reserved = STATE_BIT;
423 
424 	return (ibuf_add(buf, &cap, CAP_TLV_TWCARD_SIZE));
425 }
426 
427 static int
428 gen_cap_unotif_tlv(struct ibuf *buf, int enable)
429 {
430 	struct capability_tlv	cap;
431 
432 	memset(&cap, 0, sizeof(cap));
433 	cap.type = htons(TLV_TYPE_UNOTIF_CAP);
434 	cap.length = htons(CAP_TLV_UNOTIF_LEN);
435 	if (enable)
436 		cap.reserved = STATE_BIT;
437 
438 	return (ibuf_add(buf, &cap, CAP_TLV_UNOTIF_SIZE));
439 }
440