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