xref: /openbsd-src/usr.sbin/ldpd/labelmapping.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: labelmapping.c,v 1.28 2013/10/17 17:52:20 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 <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 <netmpls/mpls.h>
29 #include <unistd.h>
30 
31 #include <errno.h>
32 #include <event.h>
33 #include <limits.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "ldpd.h"
38 #include "ldp.h"
39 #include "log.h"
40 #include "ldpe.h"
41 
42 void		gen_label_tlv(struct ibuf *, u_int32_t);
43 void		gen_reqid_tlv(struct ibuf *, u_int32_t);
44 void		gen_fec_tlv(struct ibuf *, struct in_addr, u_int8_t);
45 
46 int	tlv_decode_label(struct nbr *, struct ldp_msg *, char *, u_int16_t,
47     u_int32_t *);
48 int	tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *, u_int16_t,
49     u_int8_t *, u_int32_t *, u_int8_t *);
50 
51 static void
52 enqueue_pdu(struct nbr *nbr, struct ibuf *buf, u_int16_t size)
53 {
54 	struct ldp_hdr		*ldp_hdr;
55 
56 	ldp_hdr = ibuf_seek(buf, 0, sizeof(struct ldp_hdr));
57 	ldp_hdr->length = htons(size);
58 	evbuf_enqueue(&nbr->tcp->wbuf, buf);
59 }
60 
61 /* Generic function that handles all Label Message types */
62 void
63 send_labelmessage(struct nbr *nbr, u_int16_t type, struct mapping_head *mh)
64 {
65 	struct ibuf		*buf = NULL;
66 	struct mapping_entry	*me;
67 	u_int16_t		 tlv_size, size = 0;
68 	int			 first = 1;
69 
70 	while ((me = TAILQ_FIRST(mh)) != NULL) {
71 		/* generate pdu */
72 		if (first) {
73 			if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL)
74 				fatal("send_labelmapping");
75 
76 			/* real size will be set up later */
77 			gen_ldp_hdr(buf, 0);
78 
79 			size = LDP_HDR_PDU_LEN;
80 			first = 0;
81 		}
82 
83 		/* calculate size */
84 		tlv_size = LDP_MSG_LEN + TLV_HDR_LEN + FEC_ELM_MIN_LEN +
85 		    PREFIX_SIZE(me->map.prefixlen);
86 		if (type == MSG_TYPE_LABELMAPPING ||
87 		    me->map.flags & F_MAP_OPTLABEL)
88 			tlv_size += LABEL_TLV_LEN;
89 		if (me->map.flags & F_MAP_REQ_ID)
90 			tlv_size += REQID_TLV_LEN;
91 
92 		/* maximum pdu length exceeded, we need a new ldp pdu */
93 		if (size + tlv_size > LDP_MAX_LEN) {
94 			enqueue_pdu(nbr, buf, size);
95 			first = 1;
96 			continue;
97 		}
98 
99 		size += tlv_size;
100 
101 		/* append message and tlvs */
102 		gen_msg_tlv(buf, type, tlv_size);
103 		gen_fec_tlv(buf, me->map.prefix, me->map.prefixlen);
104 		if (type == MSG_TYPE_LABELMAPPING ||
105 		    me->map.flags & F_MAP_OPTLABEL)
106 			gen_label_tlv(buf, me->map.label);
107 		if (me->map.flags & F_MAP_REQ_ID)
108 			gen_reqid_tlv(buf, me->map.requestid);
109 
110 		TAILQ_REMOVE(mh, me, entry);
111 		free(me);
112 	}
113 
114 	enqueue_pdu(nbr, buf, size);
115 
116 	nbr_fsm(nbr, NBR_EVT_PDU_SENT);
117 }
118 
119 /* Generic function that handles all Label Message types */
120 int
121 recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type)
122 {
123 	struct ldp_msg		 	 lm;
124 	struct tlv			 ft;
125 	u_int32_t			 label, reqid;
126 	u_int8_t			 flags = 0;
127 
128 	int				 feclen, lbllen, tlen;
129 	u_int8_t			 addr_type;
130 	struct mapping_entry		*me;
131 	struct mapping_head		 mh;
132 
133 	bcopy(buf, &lm, sizeof(lm));
134 
135 	buf += sizeof(struct ldp_msg);
136 	len -= sizeof(struct ldp_msg);
137 
138 	/* FEC TLV */
139 	if (len < sizeof(ft)) {
140 		session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, lm.type);
141 		return (-1);
142 	}
143 
144 	bcopy(buf, &ft, sizeof(ft));
145 	if (ntohs(ft.type) != TLV_TYPE_FEC) {
146 		send_notification_nbr(nbr, S_MISS_MSG, lm.msgid, lm.type);
147 		return (-1);
148 	}
149 	feclen = ntohs(ft.length);
150 
151 	if (feclen > len - TLV_HDR_LEN) {
152 		session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, lm.type);
153 		return (-1);
154 	}
155 
156 	buf += TLV_HDR_LEN;	/* just advance to the end of the fec header */
157 	len -= TLV_HDR_LEN;
158 
159 	TAILQ_INIT(&mh);
160 	do {
161 		me = calloc(1, sizeof(*me));
162 		me->map.messageid = lm.msgid;
163 		TAILQ_INSERT_HEAD(&mh, me, entry);
164 
165 		if ((tlen = tlv_decode_fec_elm(nbr, &lm, buf, feclen,
166 		    &addr_type, &me->map.prefix.s_addr, &me->map.prefixlen)) == -1)
167 			goto err;
168 
169 		/*
170 		 * The Wildcard FEC Element can be used only in the
171 		 * Label Withdraw and Label Release messages.
172 		 */
173 		if (addr_type == FEC_WILDCARD) {
174 			switch (type) {
175 			case MSG_TYPE_LABELWITHDRAW:
176 			case MSG_TYPE_LABELRELEASE:
177 				me->map.flags |= F_MAP_WILDCARD;
178 				break;
179 			default:
180 				session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid,
181 				    lm.type);
182 				goto err;
183 				break;
184 			}
185 		}
186 
187 		/*
188 		 * LDP supports the use of multiple FEC Elements per
189 		 * FEC for the Label Mapping message only.
190 		 */
191 		if (type != MSG_TYPE_LABELMAPPING &&
192 		    tlen != feclen) {
193 			session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid,
194 			    lm.type);
195 			goto err;
196 		}
197 
198 		buf += tlen;
199 		len -= tlen;
200 		feclen -= tlen;
201 	} while (feclen > 0);
202 
203 	/* Mandatory Label TLV */
204 	if (type == MSG_TYPE_LABELMAPPING) {
205 		lbllen = tlv_decode_label(nbr, &lm, buf, len, &label);
206 		if (lbllen == -1)
207 			goto err;
208 
209 		buf += lbllen;
210 		len -= lbllen;
211 	}
212 
213 	/* Optional Parameters */
214 	while (len > 0) {
215 		struct tlv 	tlv;
216 
217 		if (len < sizeof(tlv)) {
218 			session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid,
219 			    lm.type);
220 			goto err;
221 		}
222 
223 		bcopy(buf, &tlv, sizeof(tlv));
224 		buf += TLV_HDR_LEN;
225 		len -= TLV_HDR_LEN;
226 
227 		switch (ntohs(tlv.type)) {
228 		case TLV_TYPE_LABELREQUEST:
229 			switch (type) {
230 			case MSG_TYPE_LABELMAPPING:
231 			case MSG_TYPE_LABELABORTREQ:
232 				if (ntohs(tlv.length) != 4) {
233 					session_shutdown(nbr, S_BAD_TLV_LEN,
234 					    lm.msgid, lm.type);
235 					goto err;
236 				}
237 
238 				flags |= F_MAP_REQ_ID;
239 				reqid = ntohl(*(u_int32_t *)buf);
240 				break;
241 			default:
242 				/* ignore */
243 				break;
244 			}
245 			break;
246 		case TLV_TYPE_HOPCOUNT:
247 		case TLV_TYPE_PATHVECTOR:
248 			/* TODO just ignore for now */
249 			break;
250 		case TLV_TYPE_GENERICLABEL:
251 			switch (type) {
252 			case MSG_TYPE_LABELWITHDRAW:
253 			case MSG_TYPE_LABELRELEASE:
254 				if (ntohs(tlv.length) != 4) {
255 					session_shutdown(nbr, S_BAD_TLV_LEN,
256 					    lm.msgid, lm.type);
257 					goto err;
258 				}
259 
260 				label = ntohl(*(u_int32_t *)buf);
261 				flags |= F_MAP_OPTLABEL;
262 				break;
263 			default:
264 				/* ignore */
265 				break;
266 			}
267 			break;
268 		case TLV_TYPE_ATMLABEL:
269 		case TLV_TYPE_FRLABEL:
270 			switch (type) {
271 			case MSG_TYPE_LABELWITHDRAW:
272 			case MSG_TYPE_LABELRELEASE:
273 				/* unsupported */
274 				session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid,
275 				    lm.type);
276 				goto err;
277 				break;
278 			default:
279 				/* ignore */
280 				break;
281 			}
282 			break;
283 		default:
284 			if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) {
285 				send_notification_nbr(nbr, S_UNKNOWN_TLV,
286 				    lm.msgid, lm.type);
287 			}
288 			/* ignore unknown tlv */
289 			break;
290 		}
291 		buf += ntohs(tlv.length);
292 		len -= ntohs(tlv.length);
293 	}
294 
295 	/* notify lde about the received message. */
296 	while ((me = TAILQ_FIRST(&mh)) != NULL) {
297 		int imsg_type = IMSG_NONE;
298 
299 		me->map.flags |= flags;
300 		if (type == MSG_TYPE_LABELMAPPING ||
301 		    me->map.flags & F_MAP_OPTLABEL)
302 			me->map.label = label;
303 		if (me->map.flags & F_MAP_REQ_ID)
304 			me->map.requestid = reqid;
305 
306 		switch (type) {
307 		case MSG_TYPE_LABELMAPPING:
308 			imsg_type = IMSG_LABEL_MAPPING;
309 			break;
310 		case MSG_TYPE_LABELREQUEST:
311 			imsg_type = IMSG_LABEL_REQUEST;
312 			break;
313 		case MSG_TYPE_LABELWITHDRAW:
314 			imsg_type = IMSG_LABEL_WITHDRAW;
315 			break;
316 		case MSG_TYPE_LABELRELEASE:
317 			imsg_type = IMSG_LABEL_RELEASE;
318 			break;
319 		case MSG_TYPE_LABELABORTREQ:
320 			imsg_type = IMSG_LABEL_ABORT;
321 			break;
322 		default:
323 			break;
324 		}
325 
326 		ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map,
327 		    sizeof(struct map));
328 
329 		TAILQ_REMOVE(&mh, me, entry);
330 		free(me);
331 	}
332 
333 	return (ntohs(lm.length));
334 
335 err:
336 	mapping_list_clr(&mh);
337 
338 	return (-1);
339 }
340 
341 /* Other TLV related functions */
342 void
343 gen_label_tlv(struct ibuf *buf, u_int32_t label)
344 {
345 	struct label_tlv	lt;
346 
347 	lt.type = htons(TLV_TYPE_GENERICLABEL);
348 	lt.length = htons(sizeof(label));
349 	lt.label = htonl(label);
350 
351 	ibuf_add(buf, &lt, sizeof(lt));
352 }
353 
354 int
355 tlv_decode_label(struct nbr *nbr, struct ldp_msg *lm, char *buf,
356     u_int16_t len, u_int32_t *label)
357 {
358 	struct label_tlv lt;
359 
360 	if (len < sizeof(lt)) {
361 		session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type);
362 		return (-1);
363 	}
364 	bcopy(buf, &lt, sizeof(lt));
365 
366 	if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) {
367 		send_notification_nbr(nbr, S_MISS_MSG, lm->msgid, lm->type);
368 		return (-1);
369 	}
370 
371 	switch (htons(lt.type)) {
372 	case TLV_TYPE_GENERICLABEL:
373 		if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_LEN) {
374 			session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid,
375 			    lm->type);
376 			return (-1);
377 		}
378 
379 		*label = ntohl(lt.label);
380 		if (*label > MPLS_LABEL_MAX ||
381 		    (*label <= MPLS_LABEL_RESERVED_MAX &&
382 		     *label != MPLS_LABEL_IPV4NULL &&
383 		     *label != MPLS_LABEL_IMPLNULL)) {
384 			session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid,
385 			    lm->type);
386 			return (-1);
387 		}
388 		break;
389 	case TLV_TYPE_ATMLABEL:
390 	case TLV_TYPE_FRLABEL:
391 	default:
392 		/* unsupported */
393 		session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, lm->type);
394 		return (-1);
395 	}
396 
397 	return (sizeof(lt));
398 }
399 
400 void
401 gen_reqid_tlv(struct ibuf *buf, u_int32_t reqid)
402 {
403 	struct reqid_tlv	rt;
404 
405 	rt.type = htons(TLV_TYPE_LABELREQUEST);
406 	rt.length = htons(sizeof(reqid));
407 	rt.reqid = htonl(reqid);
408 
409 	ibuf_add(buf, &rt, sizeof(rt));
410 }
411 
412 void
413 gen_fec_tlv(struct ibuf *buf, struct in_addr prefix, u_int8_t prefixlen)
414 {
415 	struct tlv	ft;
416 	u_int8_t	type;
417 	u_int16_t	family;
418 	u_int8_t	len;
419 
420 	len = PREFIX_SIZE(prefixlen);
421 	ft.type = htons(TLV_TYPE_FEC);
422 	ft.length = htons(sizeof(type) + sizeof(family) + sizeof(prefixlen) +
423 	    len);
424 
425 	ibuf_add(buf, &ft, sizeof(ft));
426 
427 	type = FEC_PREFIX;
428 	family = htons(FEC_IPV4);
429 
430 	ibuf_add(buf, &type, sizeof(type));
431 	ibuf_add(buf, &family, sizeof(family));
432 	ibuf_add(buf, &prefixlen, sizeof(prefixlen));
433 	if (len)
434 		ibuf_add(buf, &prefix, len);
435 }
436 
437 int
438 tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf,
439     u_int16_t len, u_int8_t *type, u_int32_t *prefix, u_int8_t *prefixlen)
440 {
441 	u_int16_t	family, off = 0;
442 
443 	*type = *buf;
444 	off += sizeof(u_int8_t);
445 
446 	if (*type == FEC_WILDCARD) {
447 		if (len == 0)
448 			return (off);
449 		else {
450 			session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid,
451 			    lm->type);
452 			return (-1);
453 		}
454 	}
455 
456 	if (*type != FEC_PREFIX) {
457 		send_notification_nbr(nbr, S_UNKNOWN_FEC, lm->msgid, lm->type);
458 		return (-1);
459 	}
460 
461 	if (len < FEC_ELM_MIN_LEN) {
462 		session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type);
463 		return (-1);
464 	}
465 
466 	bcopy(buf + off, &family, sizeof(family));
467 	off += sizeof(family);
468 
469 	if (family != htons(FEC_IPV4)) {
470 		send_notification_nbr(nbr, S_UNSUP_ADDR, lm->msgid, lm->type);
471 		return (-1);
472 	}
473 
474 	*prefixlen = buf[off];
475 	off += sizeof(u_int8_t);
476 
477 	if (len < off + PREFIX_SIZE(*prefixlen)) {
478 		session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type);
479 		return (-1);
480 	}
481 
482 	*prefix = 0;
483 	bcopy(buf + off, prefix, PREFIX_SIZE(*prefixlen));
484 
485 	return (off + PREFIX_SIZE(*prefixlen));
486 }
487