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

Line Branch Exec Source
1
/*	$OpenBSD: labelmapping.c,v 1.68 2017/03/04 00:15:35 renato Exp $ */
2
3
/*
4
 * Copyright (c) 2014, 2015 Renato Westphal <renato@openbsd.org>
5
 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
#include <sys/types.h>
21
#include <sys/socket.h>
22
#include <arpa/inet.h>
23
#include <netmpls/mpls.h>
24
#include <limits.h>
25
#include <stdlib.h>
26
#include <string.h>
27
28
#include "ldpd.h"
29
#include "ldpe.h"
30
#include "log.h"
31
32
static void	 enqueue_pdu(struct nbr *, struct ibuf *, uint16_t);
33
static int	 gen_label_tlv(struct ibuf *, uint32_t);
34
static int	 tlv_decode_label(struct nbr *, struct ldp_msg *, char *,
35
		    uint16_t, uint32_t *);
36
static int	 gen_reqid_tlv(struct ibuf *, uint32_t);
37
static void	 log_msg_mapping(int, uint16_t, struct nbr *, struct map *);
38
39
static void
40
enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size)
41
{
42
	struct ldp_hdr		*ldp_hdr;
43
44
	ldp_hdr = ibuf_seek(buf, 0, sizeof(struct ldp_hdr));
45
	ldp_hdr->length = htons(size);
46
	evbuf_enqueue(&nbr->tcp->wbuf, buf);
47
}
48
49
/* Generic function that handles all Label Message types */
50
void
51
send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
52
{
53
	struct ibuf		*buf = NULL;
54
	struct mapping_entry	*me;
55
	uint16_t		 msg_size, size = 0;
56
	int			 first = 1;
57
	int			 err = 0;
58
59
	/* nothing to send */
60
	if (TAILQ_EMPTY(mh))
61
		return;
62
63
	while ((me = TAILQ_FIRST(mh)) != NULL) {
64
		/* generate pdu */
65
		if (first) {
66
			if ((buf = ibuf_open(nbr->max_pdu_len +
67
			    LDP_HDR_DEAD_LEN)) == NULL)
68
				fatal(__func__);
69
70
			/* real size will be set up later */
71
			err |= gen_ldp_hdr(buf, 0);
72
73
			size = LDP_HDR_PDU_LEN;
74
			first = 0;
75
		}
76
77
		/* calculate size */
78
		msg_size = LDP_MSG_SIZE;
79
		msg_size += len_fec_tlv(&me->map);
80
		if (me->map.label != NO_LABEL)
81
			msg_size += LABEL_TLV_SIZE;
82
		if (me->map.flags & F_MAP_REQ_ID)
83
			msg_size += REQID_TLV_SIZE;
84
		if (me->map.flags & F_MAP_STATUS)
85
			msg_size += STATUS_SIZE;
86
87
		/* maximum pdu length exceeded, we need a new ldp pdu */
88
		if (size + msg_size > nbr->max_pdu_len) {
89
			enqueue_pdu(nbr, buf, size);
90
			first = 1;
91
			continue;
92
		}
93
94
		size += msg_size;
95
96
		/* append message and tlvs */
97
		err |= gen_msg_hdr(buf, type, msg_size);
98
		err |= gen_fec_tlv(buf, &me->map);
99
		if (me->map.label != NO_LABEL)
100
			err |= gen_label_tlv(buf, me->map.label);
101
		if (me->map.flags & F_MAP_REQ_ID)
102
			err |= gen_reqid_tlv(buf, me->map.requestid);
103
	    	if (me->map.flags & F_MAP_PW_STATUS)
104
			err |= gen_pw_status_tlv(buf, me->map.pw_status);
105
		if (me->map.flags & F_MAP_STATUS)
106
			err |= gen_status_tlv(buf, me->map.st.status_code,
107
			    me->map.st.msg_id, me->map.st.msg_type);
108
		if (err) {
109
			ibuf_free(buf);
110
			mapping_list_clr(mh);
111
			return;
112
		}
113
114
		log_msg_mapping(1, type, nbr, &me->map);
115
116
		TAILQ_REMOVE(mh, me, entry);
117
		free(me);
118
	}
119
120
	enqueue_pdu(nbr, buf, size);
121
122
	nbr_fsm(nbr, NBR_EVT_PDU_SENT);
123
}
124
125
/* Generic function that handles all Label Message types */
126
int
127
recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
128
{
129
	struct ldp_msg		 msg;
130
	struct tlv		 ft;
131
	uint32_t		 label = NO_LABEL, reqid = 0;
132
	uint32_t		 pw_status = 0;
133
	uint8_t			 flags = 0;
134
	int			 feclen, lbllen, tlen;
135
	struct mapping_entry	*me;
136
	struct mapping_head	 mh;
137
	struct map		 map;
138
139
	memcpy(&msg, buf, sizeof(msg));
140
	buf += LDP_MSG_SIZE;
141
	len -= LDP_MSG_SIZE;
142
143
	/* FEC TLV */
144
	if (len < sizeof(ft)) {
145
		session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
146
		return (-1);
147
	}
148
149
	memcpy(&ft, buf, sizeof(ft));
150
	if (ntohs(ft.type) != TLV_TYPE_FEC) {
151
		send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
152
		return (-1);
153
	}
154
	feclen = ntohs(ft.length);
155
	if (feclen > len - TLV_HDR_SIZE) {
156
		session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
157
		return (-1);
158
	}
159
160
	buf += TLV_HDR_SIZE;	/* just advance to the end of the fec header */
161
	len -= TLV_HDR_SIZE;
162
163
	TAILQ_INIT(&mh);
164
	do {
165
		memset(&map, 0, sizeof(map));
166
		map.msg_id = msg.id;
167
168
		if ((tlen = tlv_decode_fec_elm(nbr, &msg, buf, feclen,
169
		    &map)) == -1)
170
			goto err;
171
		if (map.type == MAP_TYPE_PWID &&
172
		    !(map.flags & F_MAP_PW_ID) &&
173
		    type != MSG_TYPE_LABELWITHDRAW &&
174
		    type != MSG_TYPE_LABELRELEASE) {
175
			send_notification(nbr->tcp, S_MISS_MSG, msg.id,
176
			    msg.type);
177
			return (-1);
178
		}
179
180
		/*
181
		 * The Wildcard FEC Element can be used only in the
182
		 * Label Withdraw and Label Release messages.
183
		 */
184
		if (map.type == MAP_TYPE_WILDCARD) {
185
			switch (type) {
186
			case MSG_TYPE_LABELMAPPING:
187
			case MSG_TYPE_LABELREQUEST:
188
			case MSG_TYPE_LABELABORTREQ:
189
				session_shutdown(nbr, S_UNKNOWN_FEC, msg.id,
190
				    msg.type);
191
				goto err;
192
			default:
193
				break;
194
			}
195
		}
196
197
		/*
198
		 * RFC 5561 - Section 4:
199
		 * "An LDP implementation that supports the Typed Wildcard
200
		 * FEC Element MUST support its use in Label Request, Label
201
		 * Withdraw, and Label Release messages".
202
		 */
203
		if (map.type == MAP_TYPE_TYPED_WCARD) {
204
			switch (type) {
205
			case MSG_TYPE_LABELMAPPING:
206
			case MSG_TYPE_LABELABORTREQ:
207
				session_shutdown(nbr, S_UNKNOWN_FEC, msg.id,
208
				    msg.type);
209
				goto err;
210
			default:
211
				break;
212
			}
213
		}
214
215
		/*
216
		 * LDP supports the use of multiple FEC Elements per
217
		 * FEC for the Label Mapping message only.
218
		 */
219
		if (type != MSG_TYPE_LABELMAPPING &&
220
		    tlen != feclen) {
221
			session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
222
			goto err;
223
		}
224
225
		mapping_list_add(&mh, &map);
226
227
		buf += tlen;
228
		len -= tlen;
229
		feclen -= tlen;
230
	} while (feclen > 0);
231
232
	/* Mandatory Label TLV */
233
	if (type == MSG_TYPE_LABELMAPPING) {
234
		lbllen = tlv_decode_label(nbr, &msg, buf, len, &label);
235
		if (lbllen == -1)
236
			goto err;
237
238
		buf += lbllen;
239
		len -= lbllen;
240
	}
241
242
	/* Optional Parameters */
243
	while (len > 0) {
244
		struct tlv 	tlv;
245
		uint16_t	tlv_type;
246
		uint16_t	tlv_len;
247
		uint32_t	reqbuf, labelbuf, statusbuf;
248
249
		if (len < sizeof(tlv)) {
250
			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
251
			goto err;
252
		}
253
254
		memcpy(&tlv, buf, TLV_HDR_SIZE);
255
		tlv_type = ntohs(tlv.type);
256
		tlv_len = ntohs(tlv.length);
257
		if (tlv_len + TLV_HDR_SIZE > len) {
258
			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
259
			goto err;
260
		}
261
		buf += TLV_HDR_SIZE;
262
		len -= TLV_HDR_SIZE;
263
264
		switch (tlv_type) {
265
		case TLV_TYPE_LABELREQUEST:
266
			switch (type) {
267
			case MSG_TYPE_LABELMAPPING:
268
			case MSG_TYPE_LABELREQUEST:
269
				if (tlv_len != REQID_TLV_LEN) {
270
					session_shutdown(nbr, S_BAD_TLV_LEN,
271
					    msg.id, msg.type);
272
					goto err;
273
				}
274
275
				flags |= F_MAP_REQ_ID;
276
				memcpy(&reqbuf, buf, sizeof(reqbuf));
277
				reqid = ntohl(reqbuf);
278
				break;
279
			default:
280
				/* ignore */
281
				break;
282
			}
283
			break;
284
		case TLV_TYPE_HOPCOUNT:
285
		case TLV_TYPE_PATHVECTOR:
286
			/* ignore */
287
			break;
288
		case TLV_TYPE_GENERICLABEL:
289
			switch (type) {
290
			case MSG_TYPE_LABELWITHDRAW:
291
			case MSG_TYPE_LABELRELEASE:
292
				if (tlv_len != LABEL_TLV_LEN) {
293
					session_shutdown(nbr, S_BAD_TLV_LEN,
294
					    msg.id, msg.type);
295
					goto err;
296
				}
297
298
				memcpy(&labelbuf, buf, sizeof(labelbuf));
299
				label = ntohl(labelbuf);
300
				break;
301
			default:
302
				/* ignore */
303
				break;
304
			}
305
			break;
306
		case TLV_TYPE_ATMLABEL:
307
		case TLV_TYPE_FRLABEL:
308
			switch (type) {
309
			case MSG_TYPE_LABELWITHDRAW:
310
			case MSG_TYPE_LABELRELEASE:
311
				/* unsupported */
312
				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
313
				    msg.type);
314
				goto err;
315
				break;
316
			default:
317
				/* ignore */
318
				break;
319
			}
320
			break;
321
		case TLV_TYPE_STATUS:
322
			if (tlv_len != STATUS_TLV_LEN) {
323
				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
324
				    msg.type);
325
				goto err;
326
			}
327
			/* ignore */
328
			break;
329
		case TLV_TYPE_PW_STATUS:
330
			switch (type) {
331
			case MSG_TYPE_LABELMAPPING:
332
				if (tlv_len != PW_STATUS_TLV_LEN) {
333
					session_shutdown(nbr, S_BAD_TLV_LEN,
334
					    msg.id, msg.type);
335
					goto err;
336
				}
337
338
				flags |= F_MAP_PW_STATUS;
339
				memcpy(&statusbuf, buf, sizeof(statusbuf));
340
				pw_status = ntohl(statusbuf);
341
				break;
342
			default:
343
				/* ignore */
344
				break;
345
			}
346
			break;
347
		default:
348
			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
349
				send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
350
				    msg.id, msg.type, tlv_type, tlv_len, buf);
351
			/* ignore unknown tlv */
352
			break;
353
		}
354
		buf += tlv_len;
355
		len -= tlv_len;
356
	}
357
358
	/* notify lde about the received message. */
359
	while ((me = TAILQ_FIRST(&mh)) != NULL) {
360
		int imsg_type = IMSG_NONE;
361
362
		me->map.flags |= flags;
363
		switch (me->map.type) {
364
		case MAP_TYPE_PREFIX:
365
			switch (me->map.fec.prefix.af) {
366
			case AF_INET:
367
				if (label == MPLS_LABEL_IPV6NULL) {
368
					session_shutdown(nbr, S_BAD_TLV_VAL,
369
					    msg.id, msg.type);
370
					goto err;
371
				}
372
				if (!nbr->v4_enabled)
373
					goto next;
374
				break;
375
			case AF_INET6:
376
				if (label == MPLS_LABEL_IPV4NULL) {
377
					session_shutdown(nbr, S_BAD_TLV_VAL,
378
					    msg.id, msg.type);
379
					goto err;
380
				}
381
				if (!nbr->v6_enabled)
382
					goto next;
383
				break;
384
			default:
385
				fatalx("recv_labelmessage: unknown af");
386
			}
387
			break;
388
		case MAP_TYPE_PWID:
389
			if (label <= MPLS_LABEL_RESERVED_MAX) {
390
				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
391
				    msg.type);
392
				goto err;
393
			}
394
			if (me->map.flags & F_MAP_PW_STATUS)
395
				me->map.pw_status = pw_status;
396
			break;
397
		default:
398
			break;
399
		}
400
		me->map.label = label;
401
		if (me->map.flags & F_MAP_REQ_ID)
402
			me->map.requestid = reqid;
403
404
		log_msg_mapping(0, type, nbr, &me->map);
405
406
		switch (type) {
407
		case MSG_TYPE_LABELMAPPING:
408
			imsg_type = IMSG_LABEL_MAPPING;
409
			break;
410
		case MSG_TYPE_LABELREQUEST:
411
			imsg_type = IMSG_LABEL_REQUEST;
412
			break;
413
		case MSG_TYPE_LABELWITHDRAW:
414
			imsg_type = IMSG_LABEL_WITHDRAW;
415
			break;
416
		case MSG_TYPE_LABELRELEASE:
417
			imsg_type = IMSG_LABEL_RELEASE;
418
			break;
419
		case MSG_TYPE_LABELABORTREQ:
420
			imsg_type = IMSG_LABEL_ABORT;
421
			break;
422
		default:
423
			break;
424
		}
425
426
		ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map,
427
		    sizeof(struct map));
428
429
 next:
430
		TAILQ_REMOVE(&mh, me, entry);
431
		free(me);
432
	}
433
434
	return (0);
435
436
 err:
437
	mapping_list_clr(&mh);
438
439
	return (-1);
440
}
441
442
/* Other TLV related functions */
443
static int
444
gen_label_tlv(struct ibuf *buf, uint32_t label)
445
{
446
	struct label_tlv	lt;
447
448
	lt.type = htons(TLV_TYPE_GENERICLABEL);
449
	lt.length = htons(LABEL_TLV_LEN);
450
	lt.label = htonl(label);
451
452
	return (ibuf_add(buf, &lt, sizeof(lt)));
453
}
454
455
static int
456
tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf,
457
    uint16_t len, uint32_t *label)
458
{
459
	struct label_tlv lt;
460
461
	if (len < sizeof(lt)) {
462
		session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type);
463
		return (-1);
464
	}
465
	memcpy(&lt, buf, sizeof(lt));
466
467
	if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) {
468
		send_notification(nbr->tcp, S_MISS_MSG, msg->id, msg->type);
469
		return (-1);
470
	}
471
472
	switch (htons(lt.type)) {
473
	case TLV_TYPE_GENERICLABEL:
474
		if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) {
475
			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
476
			    msg->type);
477
			return (-1);
478
		}
479
480
		*label = ntohl(lt.label);
481
		if (*label > MPLS_LABEL_MAX ||
482
		    (*label <= MPLS_LABEL_RESERVED_MAX &&
483
		     *label != MPLS_LABEL_IPV4NULL &&
484
		     *label != MPLS_LABEL_IPV6NULL &&
485
		     *label != MPLS_LABEL_IMPLNULL)) {
486
			session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
487
			    msg->type);
488
			return (-1);
489
		}
490
		break;
491
	case TLV_TYPE_ATMLABEL:
492
	case TLV_TYPE_FRLABEL:
493
	default:
494
		/* unsupported */
495
		session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type);
496
		return (-1);
497
	}
498
499
	return (sizeof(lt));
500
}
501
502
static int
503
gen_reqid_tlv(struct ibuf *buf, uint32_t reqid)
504
{
505
	struct reqid_tlv	rt;
506
507
	rt.type = htons(TLV_TYPE_LABELREQUEST);
508
	rt.length = htons(REQID_TLV_LEN);
509
	rt.reqid = htonl(reqid);
510
511
	return (ibuf_add(buf, &rt, sizeof(rt)));
512
}
513
514
int
515
gen_pw_status_tlv(struct ibuf *buf, uint32_t status)
516
{
517
	struct pw_status_tlv	st;
518
519
	st.type = htons(TLV_TYPE_PW_STATUS);
520
	st.length = htons(PW_STATUS_TLV_LEN);
521
	st.value = htonl(status);
522
523
	return (ibuf_add(buf, &st, sizeof(st)));
524
}
525
526
uint16_t
527
len_fec_tlv(struct map *map)
528
{
529
	uint16_t	 len = TLV_HDR_SIZE;
530
531
	switch (map->type) {
532
	case MAP_TYPE_WILDCARD:
533
		len += FEC_ELM_WCARD_LEN;
534
		break;
535
	case MAP_TYPE_PREFIX:
536
		len += FEC_ELM_PREFIX_MIN_LEN +
537
		    PREFIX_SIZE(map->fec.prefix.prefixlen);
538
		break;
539
	case MAP_TYPE_PWID:
540
		len += FEC_PWID_ELM_MIN_LEN;
541
		if (map->flags & F_MAP_PW_ID)
542
			len += PW_STATUS_TLV_LEN;
543
		if (map->flags & F_MAP_PW_IFMTU)
544
			len += FEC_SUBTLV_IFMTU_SIZE;
545
    		if (map->flags & F_MAP_PW_STATUS)
546
			len += PW_STATUS_TLV_SIZE;
547
		break;
548
	case MAP_TYPE_TYPED_WCARD:
549
		len += FEC_ELM_TWCARD_MIN_LEN;
550
		switch (map->fec.twcard.type) {
551
		case MAP_TYPE_PREFIX:
552
		case MAP_TYPE_PWID:
553
			len += sizeof(uint16_t);
554
			break;
555
		default:
556
			fatalx("len_fec_tlv: unexpected fec type");
557
		}
558
		break;
559
	default:
560
		fatalx("len_fec_tlv: unexpected fec type");
561
	}
562
563
	return (len);
564
}
565
566
int
567
gen_fec_tlv(struct ibuf *buf, struct map *map)
568
{
569
	struct tlv	ft;
570
	uint16_t	family, len, pw_type, ifmtu;
571
	uint8_t		pw_len = 0, twcard_len;
572
	uint32_t	group_id, pwid;
573
	int		err = 0;
574
575
	ft.type = htons(TLV_TYPE_FEC);
576
577
	switch (map->type) {
578
	case MAP_TYPE_WILDCARD:
579
		ft.length = htons(sizeof(uint8_t));
580
		err |= ibuf_add(buf, &ft, sizeof(ft));
581
		err |= ibuf_add(buf, &map->type, sizeof(map->type));
582
		break;
583
	case MAP_TYPE_PREFIX:
584
		len = PREFIX_SIZE(map->fec.prefix.prefixlen);
585
		ft.length = htons(sizeof(map->type) + sizeof(family) +
586
		    sizeof(map->fec.prefix.prefixlen) + len);
587
		err |= ibuf_add(buf, &ft, sizeof(ft));
588
		err |= ibuf_add(buf, &map->type, sizeof(map->type));
589
		switch (map->fec.prefix.af) {
590
		case AF_INET:
591
			family = htons(AF_IPV4);
592
			break;
593
		case AF_INET6:
594
			family = htons(AF_IPV6);
595
			break;
596
		default:
597
			fatalx("gen_fec_tlv: unknown af");
598
			break;
599
		}
600
		err |= ibuf_add(buf, &family, sizeof(family));
601
		err |= ibuf_add(buf, &map->fec.prefix.prefixlen,
602
		    sizeof(map->fec.prefix.prefixlen));
603
		if (len)
604
			err |= ibuf_add(buf, &map->fec.prefix.prefix, len);
605
		break;
606
	case MAP_TYPE_PWID:
607
		if (map->flags & F_MAP_PW_ID)
608
			pw_len += FEC_PWID_SIZE;
609
		if (map->flags & F_MAP_PW_IFMTU)
610
			pw_len += FEC_SUBTLV_IFMTU_SIZE;
611
612
		len = FEC_PWID_ELM_MIN_LEN + pw_len;
613
614
		ft.length = htons(len);
615
		err |= ibuf_add(buf, &ft, sizeof(ft));
616
617
		err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
618
		pw_type = map->fec.pwid.type;
619
		if (map->flags & F_MAP_PW_CWORD)
620
			pw_type |= CONTROL_WORD_FLAG;
621
		pw_type = htons(pw_type);
622
		err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
623
		err |= ibuf_add(buf, &pw_len, sizeof(uint8_t));
624
		group_id = htonl(map->fec.pwid.group_id);
625
		err |= ibuf_add(buf, &group_id, sizeof(uint32_t));
626
		if (map->flags & F_MAP_PW_ID) {
627
			pwid = htonl(map->fec.pwid.pwid);
628
			err |= ibuf_add(buf, &pwid, sizeof(uint32_t));
629
		}
630
		if (map->flags & F_MAP_PW_IFMTU) {
631
			struct subtlv 	stlv;
632
633
			stlv.type = SUBTLV_IFMTU;
634
			stlv.length = FEC_SUBTLV_IFMTU_SIZE;
635
			err |= ibuf_add(buf, &stlv, sizeof(uint16_t));
636
637
			ifmtu = htons(map->fec.pwid.ifmtu);
638
			err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t));
639
		}
640
		break;
641
	case MAP_TYPE_TYPED_WCARD:
642
		len = FEC_ELM_TWCARD_MIN_LEN;
643
		switch (map->fec.twcard.type) {
644
		case MAP_TYPE_PREFIX:
645
		case MAP_TYPE_PWID:
646
			len += sizeof(uint16_t);
647
			break;
648
		default:
649
			fatalx("gen_fec_tlv: unexpected fec type");
650
		}
651
		ft.length = htons(len);
652
		err |= ibuf_add(buf, &ft, sizeof(ft));
653
		err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
654
		err |= ibuf_add(buf, &map->fec.twcard.type, sizeof(uint8_t));
655
656
		switch (map->fec.twcard.type) {
657
		case MAP_TYPE_PREFIX:
658
			twcard_len = sizeof(uint16_t);
659
			err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
660
661
			switch (map->fec.twcard.u.prefix_af) {
662
			case AF_INET:
663
				family = htons(AF_IPV4);
664
				break;
665
			case AF_INET6:
666
				family = htons(AF_IPV6);
667
				break;
668
			default:
669
				fatalx("gen_fec_tlv: unknown af");
670
				break;
671
			}
672
673
			err |= ibuf_add(buf, &family, sizeof(uint16_t));
674
			break;
675
		case MAP_TYPE_PWID:
676
			twcard_len = sizeof(uint16_t);
677
			err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
678
			pw_type = htons(map->fec.twcard.u.pw_type);
679
			err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
680
			break;
681
		default:
682
			fatalx("gen_fec_tlv: unexpected fec type");
683
		}
684
		break;
685
	default:
686
		break;
687
	}
688
689
	return (err);
690
}
691
692
int
693
tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
694
    uint16_t len, struct map *map)
695
{
696
	uint16_t	off = 0;
697
	uint8_t		pw_len, twcard_len;
698
699
	map->type = *buf;
700
	off += sizeof(uint8_t);
701
702
	switch (map->type) {
703
	case MAP_TYPE_WILDCARD:
704
		if (len == FEC_ELM_WCARD_LEN)
705
			return (off);
706
		else {
707
			session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
708
			    msg->type);
709
			return (-1);
710
		}
711
		break;
712
	case MAP_TYPE_PREFIX:
713
		if (len < FEC_ELM_PREFIX_MIN_LEN) {
714
			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
715
			    msg->type);
716
			return (-1);
717
		}
718
719
		/* Address Family */
720
		memcpy(&map->fec.prefix.af, buf + off,
721
		    sizeof(map->fec.prefix.af));
722
		off += sizeof(map->fec.prefix.af);
723
		map->fec.prefix.af = ntohs(map->fec.prefix.af);
724
		switch (map->fec.prefix.af) {
725
		case AF_IPV4:
726
			map->fec.prefix.af = AF_INET;
727
			break;
728
		case AF_IPV6:
729
			map->fec.prefix.af = AF_INET6;
730
			break;
731
		default:
732
			send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id,
733
			    msg->type);
734
			return (-1);
735
		}
736
737
		/* Prefix Length */
738
		map->fec.prefix.prefixlen = buf[off];
739
		off += sizeof(uint8_t);
740
		if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) {
741
			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
742
			    msg->type);
743
			return (-1);
744
		}
745
746
		/* Prefix */
747
		memset(&map->fec.prefix.prefix, 0,
748
		    sizeof(map->fec.prefix.prefix));
749
		memcpy(&map->fec.prefix.prefix, buf + off,
750
		    PREFIX_SIZE(map->fec.prefix.prefixlen));
751
752
		/* Just in case... */
753
		ldp_applymask(map->fec.prefix.af, &map->fec.prefix.prefix,
754
		    &map->fec.prefix.prefix, map->fec.prefix.prefixlen);
755
756
		return (off + PREFIX_SIZE(map->fec.prefix.prefixlen));
757
	case MAP_TYPE_PWID:
758
		if (len < FEC_PWID_ELM_MIN_LEN) {
759
			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
760
			    msg->type);
761
			return (-1);
762
		}
763
764
		/* PW type */
765
		memcpy(&map->fec.pwid.type, buf + off, sizeof(uint16_t));
766
		map->fec.pwid.type = ntohs(map->fec.pwid.type);
767
		if (map->fec.pwid.type & CONTROL_WORD_FLAG) {
768
			map->flags |= F_MAP_PW_CWORD;
769
			map->fec.pwid.type &= ~CONTROL_WORD_FLAG;
770
		}
771
		off += sizeof(uint16_t);
772
773
		/* PW info Length */
774
		pw_len = buf[off];
775
		off += sizeof(uint8_t);
776
777
		if (len != FEC_PWID_ELM_MIN_LEN + pw_len) {
778
			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
779
			    msg->type);
780
			return (-1);
781
		}
782
783
		/* Group ID */
784
		memcpy(&map->fec.pwid.group_id, buf + off, sizeof(uint32_t));
785
		map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id);
786
		off += sizeof(uint32_t);
787
788
		/* PW ID */
789
		if (pw_len == 0)
790
			return (off);
791
792
		if (pw_len < sizeof(uint32_t)) {
793
			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
794
			    msg->type);
795
			return (-1);
796
		}
797
798
		memcpy(&map->fec.pwid.pwid, buf + off, sizeof(uint32_t));
799
		map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid);
800
		map->flags |= F_MAP_PW_ID;
801
		off += sizeof(uint32_t);
802
		pw_len -= sizeof(uint32_t);
803
804
		/* Optional Interface Parameter Sub-TLVs */
805
		while (pw_len > 0) {
806
			struct subtlv 	stlv;
807
808
			if (pw_len < sizeof(stlv)) {
809
				session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
810
				    msg->type);
811
				return (-1);
812
			}
813
814
			memcpy(&stlv, buf + off, sizeof(stlv));
815
			if (stlv.length > pw_len) {
816
				session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
817
				    msg->type);
818
				return (-1);
819
			}
820
821
			switch (stlv.type) {
822
			case SUBTLV_IFMTU:
823
				if (stlv.length != FEC_SUBTLV_IFMTU_SIZE) {
824
					session_shutdown(nbr, S_BAD_TLV_LEN,
825
					    msg->id, msg->type);
826
					return (-1);
827
				}
828
				memcpy(&map->fec.pwid.ifmtu, buf + off +
829
				    SUBTLV_HDR_SIZE, sizeof(uint16_t));
830
				map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu);
831
				map->flags |= F_MAP_PW_IFMTU;
832
				break;
833
			default:
834
				/* ignore */
835
				break;
836
			}
837
			off += stlv.length;
838
			pw_len -= stlv.length;
839
		}
840
841
		return (off);
842
	case MAP_TYPE_TYPED_WCARD:
843
		if (len < FEC_ELM_TWCARD_MIN_LEN) {
844
			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
845
			    msg->type);
846
			return (-1);
847
		}
848
849
		memcpy(&map->fec.twcard.type, buf + off, sizeof(uint8_t));
850
		off += sizeof(uint8_t);
851
		memcpy(&twcard_len, buf + off, sizeof(uint8_t));
852
		off += sizeof(uint8_t);
853
		if (len != FEC_ELM_TWCARD_MIN_LEN + twcard_len) {
854
			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
855
			    msg->type);
856
			return (-1);
857
		}
858
859
		switch (map->fec.twcard.type) {
860
		case MAP_TYPE_PREFIX:
861
			if (twcard_len != sizeof(uint16_t)) {
862
				session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
863
				    msg->type);
864
				return (-1);
865
			}
866
867
			memcpy(&map->fec.twcard.u.prefix_af, buf + off,
868
			    sizeof(uint16_t));
869
			map->fec.twcard.u.prefix_af =
870
			    ntohs(map->fec.twcard.u.prefix_af);
871
			off += sizeof(uint16_t);
872
873
			switch (map->fec.twcard.u.prefix_af) {
874
			case AF_IPV4:
875
				map->fec.twcard.u.prefix_af = AF_INET;
876
				break;
877
			case AF_IPV6:
878
				map->fec.twcard.u.prefix_af = AF_INET6;
879
				break;
880
			default:
881
				session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
882
				    msg->type);
883
				return (-1);
884
			}
885
			break;
886
		case MAP_TYPE_PWID:
887
			if (twcard_len != sizeof(uint16_t)) {
888
				session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
889
				    msg->type);
890
				return (-1);
891
			}
892
893
			memcpy(&map->fec.twcard.u.pw_type, buf + off,
894
			    sizeof(uint16_t));
895
			map->fec.twcard.u.pw_type =
896
			    ntohs(map->fec.twcard.u.pw_type);
897
			/* ignore the reserved bit as per RFC 6667 */
898
			map->fec.twcard.u.pw_type &= ~PW_TWCARD_RESERVED_BIT;
899
			off += sizeof(uint16_t);
900
			break;
901
		default:
902
			send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id,
903
			    msg->type);
904
			return (-1);
905
		}
906
907
		return (off);
908
	default:
909
		send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type);
910
		break;
911
	}
912
913
	return (-1);
914
}
915
916
static void
917
log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map)
918
{
919
	log_debug("msg-%s: %s: lsr-id %s, fec %s, label %s",
920
	    (out) ? "out" : "in", msg_name(msg_type), inet_ntoa(nbr->id),
921
	    log_map(map), log_label(map->label));
922
}