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