GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ldpd/init.c Lines: 0 209 0.0 %
Date: 2017-11-07 Branches: 0 78 0.0 %

Line Branch Exec Source
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
}