xref: /openbsd/usr.sbin/ldpd/labelmapping.c (revision 17df1aa7)
1 /*	$OpenBSD: labelmapping.c,v 1.8 2010/04/15 14:47:12 claudio 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 <sys/socket.h>
21 #include <sys/uio.h>
22 
23 #include <netinet/in.h>
24 #include <netinet/in_systm.h>
25 #include <netinet/ip.h>
26 #include <arpa/inet.h>
27 #include <net/if_dl.h>
28 #include <unistd.h>
29 
30 #include <errno.h>
31 #include <event.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "ldpd.h"
36 #include "ldp.h"
37 #include "log.h"
38 #include "ldpe.h"
39 
40 void		gen_fec_tlv(struct buf *, u_int32_t, u_int8_t);
41 void		gen_label_tlv(struct buf *, u_int32_t);
42 
43 u_int32_t	tlv_decode_label(struct label_tlv *);
44 u_int32_t	decode_fec_elm(char *);
45 int		decode_fec_len_elm(char *, u_int8_t);
46 int		validate_fec_elm(char *);
47 
48 /* Label Mapping Message */
49 void
50 send_labelmapping(struct nbr *nbr)
51 {
52 	struct buf		*buf;
53 	struct mapping_entry	*me;
54 	struct ldp_hdr		*ldp_hdr;
55 	u_int16_t		 tlv_size, size;
56 
57 	if (nbr->iface->passive)
58 		return;
59 
60 	log_debug("send_labelmapping: neighbor ID %s", inet_ntoa(nbr->id));
61 
62 	if ((buf = buf_open(LDP_MAX_LEN)) == NULL)
63 		fatal("send_labelmapping");
64 
65 	/* real size will be set up later */
66 	gen_ldp_hdr(buf, nbr->iface, 0);
67 
68 	size = LDP_HDR_SIZE - TLV_HDR_LEN;
69 
70 	TAILQ_FOREACH(me, &nbr->mapping_list, entry) {
71 		tlv_size = BASIC_LABEL_MAP_LEN + PREFIX_SIZE(me->prefixlen);
72 		size += tlv_size;
73 
74 		gen_msg_tlv(buf, MSG_TYPE_LABELMAPPING, tlv_size);
75 		gen_fec_tlv(buf, me->prefix, me->prefixlen);
76 		gen_label_tlv(buf, me->label);
77 	}
78 
79 	/* XXX: should we remove them first? */
80 	nbr_mapping_list_clr(nbr, &nbr->mapping_list);
81 
82 	ldp_hdr = buf_seek(buf, 0, sizeof(struct ldp_hdr));
83 	ldp_hdr->length = htons(size);
84 
85 	evbuf_enqueue(&nbr->wbuf, buf);
86 }
87 
88 int
89 recv_labelmapping(struct nbr *nbr, char *buf, u_int16_t len)
90 {
91 	struct ldp_msg		*lm;
92 	struct fec_tlv		*ft;
93 	struct label_tlv	*lt;
94 	struct map		 map;
95 	int			 feclen, addr_type;
96 
97 	log_debug("recv_labelmapping: neighbor ID %s", inet_ntoa(nbr->id));
98 
99 	if (nbr->state != NBR_STA_OPER)
100 		return (-1);
101 
102 	bzero(&map, sizeof(map));
103 	lm = (struct ldp_msg *)buf;
104 
105 	if ((len - TLV_HDR_LEN) < ntohs(lm->length)) {
106 		session_shutdown(nbr, S_BAD_MSG_LEN, lm->msgid, lm->type);
107 		return (-1);
108 	}
109 
110 	buf += sizeof(struct ldp_msg);
111 	len -= sizeof(struct ldp_msg);
112 
113 	ft = (struct fec_tlv *)buf;
114 	lt = (struct label_tlv *)(buf + TLV_HDR_LEN + ntohs(ft->length));
115 
116 	if (len < (sizeof(*ft) + LABEL_TLV_LEN)) {
117 		session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type);
118 		return (-1);
119 	}
120 
121 	feclen = ntohs(ft->length);
122 	if (len - TLV_HDR_LEN < feclen) {
123 		session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type);
124 		return (-1);
125 	}
126 
127 	map.label = tlv_decode_label(lt);
128 	if (map.label == NO_LABEL) {
129 		session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, lm->type);
130 		return (-1);
131 	}
132 
133 	buf += sizeof(struct fec_tlv);
134 	len -= sizeof(struct fec_tlv);
135 
136 	while (feclen >= FEC_ELM_MIN_LEN) {
137 		addr_type = validate_fec_elm(buf);
138 		if (addr_type < 0) {
139 			session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid,
140 			    lm->type);
141 			return (-1);
142 		}
143 
144 		map.prefix = decode_fec_elm(buf);
145 		map.prefixlen = decode_fec_len_elm(buf, addr_type);
146 		map.prefix &= prefixlen2mask(map.prefixlen);
147 
148 		ldpe_imsg_compose_lde(IMSG_LABEL_MAPPING, nbr->peerid, 0, &map,
149 		    sizeof(map));
150 
151 		buf += FEC_ELM_MIN_LEN + PREFIX_SIZE(map.prefixlen);
152 		feclen -= (FEC_ELM_MIN_LEN + PREFIX_SIZE(map.prefixlen));
153 	}
154 
155 	nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
156 
157 	return (ntohs(lm->length));
158 }
159 
160 /* Label Request Message */
161 void
162 send_labelrequest(struct nbr *nbr)
163 {
164 	struct buf		*buf;
165 	struct mapping_entry	*me;
166 	struct ldp_hdr		*ldp_hdr;
167 	u_int16_t		 tlv_size, size;
168 
169 	if (nbr->iface->passive)
170 		return;
171 
172 	log_debug("send_labelrequest: neighbor ID %s", inet_ntoa(nbr->id));
173 
174 	if ((buf = buf_open(LDP_MAX_LEN)) == NULL)
175 		fatal("send_labelrequest");
176 
177 	/* real size will be set up later */
178 	gen_ldp_hdr(buf, nbr->iface, 0);
179 
180 	size = LDP_HDR_SIZE - TLV_HDR_LEN;
181 
182 	TAILQ_FOREACH(me, &nbr->request_list, entry) {
183 		tlv_size = PREFIX_SIZE(me->prefixlen);
184 		size += tlv_size;
185 
186 		gen_msg_tlv(buf, MSG_TYPE_LABELREQUEST, tlv_size);
187 		gen_fec_tlv(buf, me->prefix, me->prefixlen);
188 	}
189 
190 	/* XXX: should we remove them first? */
191 	nbr_mapping_list_clr(nbr, &nbr->request_list);
192 
193 	ldp_hdr = buf_seek(buf, 0, sizeof(struct ldp_hdr));
194 	ldp_hdr->length = htons(size);
195 
196 	evbuf_enqueue(&nbr->wbuf, buf);
197 }
198 
199 int
200 recv_labelrequest(struct nbr *nbr, char *buf, u_int16_t len)
201 {
202 	struct ldp_msg	*lr;
203 	struct fec_tlv	*ft;
204 	struct map	 map;
205 	int		 feclen, addr_type;
206 
207 	log_debug("recv_labelrequest: neighbor ID %s", inet_ntoa(nbr->id));
208 
209 	if (nbr->state != NBR_STA_OPER)
210 		return (-1);
211 
212 	bzero(&map, sizeof(map));
213 	lr = (struct ldp_msg *)buf;
214 
215 	if ((len - TLV_HDR_LEN) < ntohs(lr->length)) {
216 		session_shutdown(nbr, S_BAD_MSG_LEN, lr->msgid, lr->type);
217 		return (-1);
218 	}
219 
220 	buf += sizeof(struct ldp_msg);
221 	len -= sizeof(struct ldp_msg);
222 
223 	ft = (struct fec_tlv *)buf;
224 
225 	if (len < sizeof(*ft) ||
226 	    (len - TLV_HDR_LEN) < ntohs(ft->length)) {
227 		session_shutdown(nbr, S_BAD_TLV_LEN, lr->msgid, lr->type);
228 		return (-1);
229 	}
230 
231 	feclen = ntohs(ft->length);
232 
233 	buf += sizeof(struct fec_tlv);
234 	len -= sizeof(struct fec_tlv);
235 
236 	while (feclen >= FEC_ELM_MIN_LEN) {
237 		addr_type = validate_fec_elm(buf);
238 		if (addr_type < 0) {
239 			session_shutdown(nbr, S_BAD_TLV_VAL, lr->msgid,
240 			    lr->type);
241 			return (-1);
242 		}
243 
244 		map.prefix = decode_fec_elm(buf);
245 		map.prefixlen = decode_fec_len_elm(buf, addr_type);
246 		map.prefix &= prefixlen2mask(map.prefixlen);
247 		map.messageid = lr->msgid;
248 
249 		ldpe_imsg_compose_lde(IMSG_LABEL_REQUEST, nbr->peerid, 0, &map,
250 		    sizeof(map));
251 
252 		buf += FEC_ELM_MIN_LEN + PREFIX_SIZE(map.prefixlen);
253 		feclen -= (FEC_ELM_MIN_LEN + PREFIX_SIZE(map.prefixlen));
254 	}
255 
256 	nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
257 
258 	return (ntohs(lr->length));
259 }
260 
261 /* Label Withdraw Message */
262 void
263 send_labelwithdraw(struct nbr *nbr)
264 {
265 	struct buf		*buf;
266 	struct mapping_entry	*me;
267 	struct ldp_hdr		*ldp_hdr;
268 	u_int16_t		 tlv_size, size;
269 
270 	if (nbr->iface->passive)
271 		return;
272 
273 	log_debug("send_labelwithdraw: neighbor ID %s", inet_ntoa(nbr->id));
274 
275 	if ((buf = buf_open(LDP_MAX_LEN)) == NULL)
276 		fatal("send_labelwithdraw");
277 
278 	/* real size will be set up later */
279 	gen_ldp_hdr(buf, nbr->iface, 0);
280 
281 	size = LDP_HDR_SIZE - TLV_HDR_LEN;
282 
283 	TAILQ_FOREACH(me, &nbr->withdraw_list, entry) {
284 		if (me->label == NO_LABEL)
285 			tlv_size = PREFIX_SIZE(me->prefixlen);
286 		else
287 			tlv_size = BASIC_LABEL_MAP_LEN +
288 			    PREFIX_SIZE(me->prefixlen);
289 
290 		size += tlv_size;
291 
292 		gen_msg_tlv(buf, MSG_TYPE_LABELWITHDRAW, tlv_size);
293 		gen_fec_tlv(buf, me->prefix, me->prefixlen);
294 
295 		if (me->label != NO_LABEL)
296 			gen_label_tlv(buf, me->label);
297 	}
298 
299 	/* XXX: should we remove them first? */
300 	nbr_mapping_list_clr(nbr, &nbr->withdraw_list);
301 
302 	ldp_hdr = buf_seek(buf, 0, sizeof(struct ldp_hdr));
303 	ldp_hdr->length = htons(size);
304 
305 	evbuf_enqueue(&nbr->wbuf, buf);
306 }
307 
308 int
309 recv_labelwithdraw(struct nbr *nbr, char *buf, u_int16_t len)
310 {
311 	struct ldp_msg		*lw;
312 
313 	log_debug("recv_labelwithdraw: neighbor ID %s", inet_ntoa(nbr->id));
314 
315 	if (nbr->state != NBR_STA_OPER)
316 		return (-1);
317 
318 	lw = (struct ldp_msg *)buf;
319 
320 	if ((len - TLV_HDR_LEN) < ntohs(lw->length)) {
321 		session_shutdown(nbr, S_BAD_MSG_LEN, lw->msgid, lw->type);
322 		return (-1);
323 	}
324 
325 	buf += sizeof(struct ldp_msg);
326 	len -= sizeof(struct ldp_msg);
327 
328 	/* XXX XXX */
329 
330 	nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
331 
332 	return (ntohs(lw->length));
333 }
334 
335 /* Label Release Message */
336 void
337 send_labelrelease(struct nbr *nbr)
338 {
339 	struct buf		*buf;
340 	struct mapping_entry	*me;
341 	struct ldp_hdr		*ldp_hdr;
342 	u_int16_t		 tlv_size, size;
343 
344 	if (nbr->iface->passive)
345 		return;
346 
347 	log_debug("send_labelrelease: neighbor ID %s", inet_ntoa(nbr->id));
348 
349 	if ((buf = buf_open(LDP_MAX_LEN)) == NULL)
350 		fatal("send_labelrelease");
351 
352 	/* real size will be set up later */
353 	gen_ldp_hdr(buf, nbr->iface, 0);
354 
355 	size = LDP_HDR_SIZE - TLV_HDR_LEN;
356 
357 	TAILQ_FOREACH(me, &nbr->release_list, entry) {
358 		if (me->label == NO_LABEL)
359 			tlv_size = PREFIX_SIZE(me->prefixlen);
360 		else
361 			tlv_size = BASIC_LABEL_MAP_LEN +
362 			    PREFIX_SIZE(me->prefixlen);
363 
364 		size += tlv_size;
365 
366 		gen_msg_tlv(buf, MSG_TYPE_LABELRELEASE, tlv_size);
367 		gen_fec_tlv(buf, me->prefix, me->prefixlen);
368 
369 		if (me->label != NO_LABEL)
370 			gen_label_tlv(buf, me->label);
371 	}
372 
373 	/* XXX: should we remove them first? */
374 	nbr_mapping_list_clr(nbr, &nbr->release_list);
375 
376 	ldp_hdr = buf_seek(buf, 0, sizeof(struct ldp_hdr));
377 	ldp_hdr->length = htons(size);
378 
379 	evbuf_enqueue(&nbr->wbuf, buf);
380 }
381 
382 int
383 recv_labelrelease(struct nbr *nbr, char *buf, u_int16_t len)
384 {
385 	struct ldp_msg		*lr;
386 
387 	log_debug("recv_labelrelease: neighbor ID %s", inet_ntoa(nbr->id));
388 
389 	if (nbr->state != NBR_STA_OPER)
390 		return (-1);
391 
392 	lr = (struct ldp_msg *)buf;
393 
394 	if ((len - TLV_HDR_LEN) < ntohs(lr->length)) {
395 		session_shutdown(nbr, S_BAD_MSG_LEN, lr->msgid, lr->type);
396 		return (-1);
397 	}
398 
399 	buf += sizeof(struct ldp_msg);
400 	len -= sizeof(struct ldp_msg);
401 
402 	/* XXX XXX XXX */
403 
404 	nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
405 
406 	return (ntohs(lr->length));
407 }
408 
409 /* Label Abort Req Message */
410 void
411 send_labelabortreq(struct nbr *nbr)
412 {
413 	struct buf	*buf;
414 	u_int16_t	 size;
415 
416 	if (nbr->iface->passive)
417 		return;
418 
419 	log_debug("send_labelabortreq: neighbor ID %s", inet_ntoa(nbr->id));
420 
421 	if ((buf = buf_open(LDP_MAX_LEN)) == NULL)
422 		fatal("send_labelabortreq");
423 
424 	size = LDP_HDR_SIZE + sizeof(struct ldp_msg);
425 
426 	gen_ldp_hdr(buf, nbr->iface, size);
427 
428 	size -= LDP_HDR_SIZE;
429 
430 	gen_msg_tlv(buf, MSG_TYPE_LABELABORTREQ, size);
431 
432 	evbuf_enqueue(&nbr->wbuf, buf);
433 }
434 
435 int
436 recv_labelabortreq(struct nbr *nbr, char *buf, u_int16_t len)
437 {
438 	struct ldp_msg	*la;
439 
440 	log_debug("recv_labelabortreq: neighbor ID %s", inet_ntoa(nbr->id));
441 
442 	if (nbr->state != NBR_STA_OPER)
443 		return (-1);
444 
445 	la = (struct ldp_msg *)buf;
446 
447 	if ((len - TLV_HDR_LEN) < ntohs(la->length)) {
448 		session_shutdown(nbr, S_BAD_MSG_LEN, la->msgid, la->type);
449 		return (-1);
450 	}
451 
452 	buf += sizeof(struct ldp_msg);
453 	len -= sizeof(struct ldp_msg);
454 
455 	/* XXX XXX XXX */
456 
457 	nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
458 
459 	return (ntohs(la->length));
460 }
461 
462 /* Other TLV related functions */
463 void
464 gen_fec_tlv(struct buf *buf, u_int32_t prefix, u_int8_t prefixlen)
465 {
466 	struct fec_tlv	ft;
467 	u_int8_t	type;
468 	u_int16_t	family;
469 	u_int8_t	len;
470 
471 	len = PREFIX_SIZE(prefixlen);
472 	ft.type = htons(TLV_TYPE_FEC);
473 	ft.length = htons(sizeof(type) + sizeof(family) + sizeof(prefixlen) +
474 	    len);
475 
476 	buf_add(buf, &ft, sizeof(ft));
477 
478 	type = FEC_PREFIX;
479 	family = htons(FEC_IPV4);
480 
481 	buf_add(buf, &type, sizeof(type));
482 	buf_add(buf, &family, sizeof(family));
483 	buf_add(buf, &prefixlen, sizeof(prefixlen));
484 	if (len)
485 		buf_add(buf, &prefix, len);
486 }
487 
488 void
489 gen_label_tlv(struct buf *buf, u_int32_t label)
490 {
491 	struct label_tlv	lt;
492 
493 	lt.type = htons(TLV_TYPE_GENERICLABEL);
494 	lt.length = htons(sizeof(label));
495 	lt.label = htonl(label);
496 
497 	buf_add(buf, &lt, sizeof(lt));
498 }
499 
500 u_int32_t
501 tlv_decode_label(struct label_tlv *lt)
502 {
503 	if (lt->type != htons(TLV_TYPE_GENERICLABEL))
504 		return (NO_LABEL);
505 
506 	if (ntohs(lt->length) != sizeof(lt->label))
507 		return (NO_LABEL);
508 
509 	return (ntohl(lt->label));
510 }
511 
512 int
513 validate_fec_elm(char *buf)
514 {
515 	u_int16_t	*family;
516 	u_int8_t	 type;
517 
518 	type = *buf;
519 
520 	if (type != FEC_WILDCARD && type != FEC_PREFIX &&
521 	    type != FEC_ADDRESS)
522 		return (-1);
523 
524 	buf += sizeof(u_int8_t);
525 	family = (u_int16_t *)buf;
526 
527 	if (*family != htons(FEC_IPV4))
528 		return (-1);
529 
530 	return (type);
531 }
532 
533 u_int32_t
534 decode_fec_elm(char *buf)
535 {
536 	struct fec_elm *fe = (struct fec_elm *)buf;
537 
538 	return (fe->addr);
539 }
540 
541 int
542 decode_fec_len_elm(char *buf, u_int8_t type)
543 {
544 	u_int8_t len;
545 
546 	/* Skip type and family */
547 	buf += sizeof(u_int8_t);
548 	buf += sizeof(u_int16_t);
549 
550 	len = *buf;
551 
552 	switch (type) {
553 	case FEC_PREFIX:
554 		return (len);
555 	case FEC_ADDRESS:
556 		return (len * 8);
557 	case FEC_WILDCARD:
558 		/* XXX: not handled for now */
559 	default:
560 		/* Should not happen */
561 		return (-1);
562 	}
563 
564 	/* NOTREACHED */
565 	return (-1);
566 }
567