1*8bc5e3a3Sclaudio /* $OpenBSD: labelmapping.c,v 1.69 2023/07/03 11:51:27 claudio Exp $ */
2ab0c2486Smichele
3ab0c2486Smichele /*
45dc9330aSrenato * Copyright (c) 2014, 2015 Renato Westphal <renato@openbsd.org>
5ab0c2486Smichele * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
6ab0c2486Smichele *
7ab0c2486Smichele * Permission to use, copy, modify, and distribute this software for any
8ab0c2486Smichele * purpose with or without fee is hereby granted, provided that the above
9ab0c2486Smichele * copyright notice and this permission notice appear in all copies.
10ab0c2486Smichele *
11ab0c2486Smichele * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12ab0c2486Smichele * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13ab0c2486Smichele * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14ab0c2486Smichele * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15ab0c2486Smichele * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16ab0c2486Smichele * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17ab0c2486Smichele * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18ab0c2486Smichele */
19ab0c2486Smichele
20ab0c2486Smichele #include <sys/types.h>
21ab0c2486Smichele #include <sys/socket.h>
22ab0c2486Smichele #include <arpa/inet.h>
2335791d36Srenato #include <netmpls/mpls.h>
24b2cd1366Sguenther #include <limits.h>
25*8bc5e3a3Sclaudio #include <stddef.h>
26ab0c2486Smichele #include <stdlib.h>
27ab0c2486Smichele #include <string.h>
28ab0c2486Smichele
29ab0c2486Smichele #include "ldpd.h"
30ab0c2486Smichele #include "ldpe.h"
315411bbb6Srenato #include "log.h"
32ab0c2486Smichele
33c28a25a1Srenato static void enqueue_pdu(struct nbr *, struct ibuf *, uint16_t);
3465f1d9c1Srenato static int gen_label_tlv(struct ibuf *, uint32_t);
35c28a25a1Srenato static int tlv_decode_label(struct nbr *, struct ldp_msg *, char *,
36c28a25a1Srenato uint16_t, uint32_t *);
3765f1d9c1Srenato static int gen_reqid_tlv(struct ibuf *, uint32_t);
38297a8bbeSrenato static void log_msg_mapping(int, uint16_t, struct nbr *, struct map *);
39ab0c2486Smichele
40bb21b33cSrenato static void
enqueue_pdu(struct nbr * nbr,struct ibuf * buf,uint16_t size)413de94509Srenato enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size)
42ab0c2486Smichele {
43*8bc5e3a3Sclaudio if (ibuf_set_n16(buf, offsetof(struct ldp_hdr, length), size) == -1)
44*8bc5e3a3Sclaudio fatal(__func__);
45bb21b33cSrenato evbuf_enqueue(&nbr->tcp->wbuf, buf);
46bb21b33cSrenato }
47bb21b33cSrenato
48bb21b33cSrenato /* Generic function that handles all Label Message types */
49bb21b33cSrenato void
send_labelmessage(struct nbr * nbr,uint16_t type,struct mapping_head * mh)503de94509Srenato send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
51bb21b33cSrenato {
52bb21b33cSrenato struct ibuf *buf = NULL;
53bb21b33cSrenato struct mapping_entry *me;
543de94509Srenato uint16_t msg_size, size = 0;
55bb21b33cSrenato int first = 1;
5665f1d9c1Srenato int err = 0;
57bb21b33cSrenato
5834f55a3fSrenato /* nothing to send */
5934f55a3fSrenato if (TAILQ_EMPTY(mh))
6034f55a3fSrenato return;
6134f55a3fSrenato
62bb21b33cSrenato while ((me = TAILQ_FIRST(mh)) != NULL) {
63bb21b33cSrenato /* generate pdu */
64bb21b33cSrenato if (first) {
653de94509Srenato if ((buf = ibuf_open(nbr->max_pdu_len +
663de94509Srenato LDP_HDR_DEAD_LEN)) == NULL)
67b7b4db73Srenato fatal(__func__);
68ab0c2486Smichele
69ab0c2486Smichele /* real size will be set up later */
7065f1d9c1Srenato err |= gen_ldp_hdr(buf, 0);
71ab0c2486Smichele
72bb21b33cSrenato size = LDP_HDR_PDU_LEN;
73bb21b33cSrenato first = 0;
74bb21b33cSrenato }
75ab0c2486Smichele
76bb21b33cSrenato /* calculate size */
779246985aSrenato msg_size = LDP_MSG_SIZE;
789246985aSrenato msg_size += len_fec_tlv(&me->map);
79cf483f25Srenato if (me->map.label != NO_LABEL)
8060e1e0e7Srenato msg_size += LABEL_TLV_SIZE;
813220fd77Sclaudio if (me->map.flags & F_MAP_REQ_ID)
8260e1e0e7Srenato msg_size += REQID_TLV_SIZE;
835ba85977Srenato if (me->map.flags & F_MAP_STATUS)
845ba85977Srenato msg_size += STATUS_SIZE;
85bb21b33cSrenato
86bb21b33cSrenato /* maximum pdu length exceeded, we need a new ldp pdu */
873de94509Srenato if (size + msg_size > nbr->max_pdu_len) {
88bb21b33cSrenato enqueue_pdu(nbr, buf, size);
89bb21b33cSrenato first = 1;
90bb21b33cSrenato continue;
91bb21b33cSrenato }
92bb21b33cSrenato
933de94509Srenato size += msg_size;
94ab0c2486Smichele
95bb21b33cSrenato /* append message and tlvs */
9665f1d9c1Srenato err |= gen_msg_hdr(buf, type, msg_size);
9765f1d9c1Srenato err |= gen_fec_tlv(buf, &me->map);
98cf483f25Srenato if (me->map.label != NO_LABEL)
9965f1d9c1Srenato err |= gen_label_tlv(buf, me->map.label);
1003220fd77Sclaudio if (me->map.flags & F_MAP_REQ_ID)
10165f1d9c1Srenato err |= gen_reqid_tlv(buf, me->map.requestid);
1026399cec1Srenato if (me->map.flags & F_MAP_PW_STATUS)
10365f1d9c1Srenato err |= gen_pw_status_tlv(buf, me->map.pw_status);
1045ba85977Srenato if (me->map.flags & F_MAP_STATUS)
10560e1e0e7Srenato err |= gen_status_tlv(buf, me->map.st.status_code,
10660e1e0e7Srenato me->map.st.msg_id, me->map.st.msg_type);
10765f1d9c1Srenato if (err) {
10865f1d9c1Srenato ibuf_free(buf);
1092163d027Srenato mapping_list_clr(mh);
11065f1d9c1Srenato return;
11165f1d9c1Srenato }
112bb21b33cSrenato
113297a8bbeSrenato log_msg_mapping(1, type, nbr, &me->map);
114c0cfacb4Srenato
115bb21b33cSrenato TAILQ_REMOVE(mh, me, entry);
116bb21b33cSrenato free(me);
117ab0c2486Smichele }
118ab0c2486Smichele
119bb21b33cSrenato enqueue_pdu(nbr, buf, size);
120ab0c2486Smichele
121b93f77ccSclaudio nbr_fsm(nbr, NBR_EVT_PDU_SENT);
122ab0c2486Smichele }
123ab0c2486Smichele
124cf650e8bSrenato /* Generic function that handles all Label Message types */
125ab0c2486Smichele int
recv_labelmessage(struct nbr * nbr,char * buf,uint16_t len,uint16_t type)1263de94509Srenato recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
127ab0c2486Smichele {
12860e1e0e7Srenato struct ldp_msg msg;
12928970269Sclaudio struct tlv ft;
1303de94509Srenato uint32_t label = NO_LABEL, reqid = 0;
1313de94509Srenato uint32_t pw_status = 0;
1323de94509Srenato uint8_t flags = 0;
133cf650e8bSrenato int feclen, lbllen, tlen;
134cf650e8bSrenato struct mapping_entry *me;
135cf650e8bSrenato struct mapping_head mh;
1368d99d653Srenato struct map map;
13789f23408Sclaudio
13860e1e0e7Srenato memcpy(&msg, buf, sizeof(msg));
1393de94509Srenato buf += LDP_MSG_SIZE;
1403de94509Srenato len -= LDP_MSG_SIZE;
141ab0c2486Smichele
142cf650e8bSrenato /* FEC TLV */
14389f23408Sclaudio if (len < sizeof(ft)) {
14460e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
14589f23408Sclaudio return (-1);
14689f23408Sclaudio }
14789f23408Sclaudio
1483de94509Srenato memcpy(&ft, buf, sizeof(ft));
14935791d36Srenato if (ntohs(ft.type) != TLV_TYPE_FEC) {
1500101edf8Srenato send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
15135791d36Srenato return (-1);
15235791d36Srenato }
15389f23408Sclaudio feclen = ntohs(ft.length);
15460e1e0e7Srenato if (feclen > len - TLV_HDR_SIZE) {
15560e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
15689f23408Sclaudio return (-1);
15789f23408Sclaudio }
15889f23408Sclaudio
15960e1e0e7Srenato buf += TLV_HDR_SIZE; /* just advance to the end of the fec header */
16060e1e0e7Srenato len -= TLV_HDR_SIZE;
16189f23408Sclaudio
162cf650e8bSrenato TAILQ_INIT(&mh);
16389f23408Sclaudio do {
1648d99d653Srenato memset(&map, 0, sizeof(map));
16560e1e0e7Srenato map.msg_id = msg.id;
166cf650e8bSrenato
16760e1e0e7Srenato if ((tlen = tlv_decode_fec_elm(nbr, &msg, buf, feclen,
1688d99d653Srenato &map)) == -1)
169cf650e8bSrenato goto err;
170cf09440fSrenato if (map.type == MAP_TYPE_PWID &&
171912987a0Srenato !(map.flags & F_MAP_PW_ID) &&
172912987a0Srenato type != MSG_TYPE_LABELWITHDRAW &&
173912987a0Srenato type != MSG_TYPE_LABELRELEASE) {
1740101edf8Srenato send_notification(nbr->tcp, S_MISS_MSG, msg.id,
17560e1e0e7Srenato msg.type);
1766399cec1Srenato return (-1);
1776399cec1Srenato }
178cf650e8bSrenato
179cf650e8bSrenato /*
180cf650e8bSrenato * The Wildcard FEC Element can be used only in the
181cf650e8bSrenato * Label Withdraw and Label Release messages.
182cf650e8bSrenato */
183cf09440fSrenato if (map.type == MAP_TYPE_WILDCARD) {
184cf650e8bSrenato switch (type) {
1856399cec1Srenato case MSG_TYPE_LABELMAPPING:
1866399cec1Srenato case MSG_TYPE_LABELREQUEST:
1876399cec1Srenato case MSG_TYPE_LABELABORTREQ:
18860e1e0e7Srenato session_shutdown(nbr, S_UNKNOWN_FEC, msg.id,
18960e1e0e7Srenato msg.type);
190cf650e8bSrenato goto err;
1916399cec1Srenato default:
192cf650e8bSrenato break;
193cf650e8bSrenato }
19489f23408Sclaudio }
19589f23408Sclaudio
196cf650e8bSrenato /*
197c7c5a728Srenato * RFC 5561 - Section 4:
198c7c5a728Srenato * "An LDP implementation that supports the Typed Wildcard
199c7c5a728Srenato * FEC Element MUST support its use in Label Request, Label
200c7c5a728Srenato * Withdraw, and Label Release messages".
201c7c5a728Srenato */
202c7c5a728Srenato if (map.type == MAP_TYPE_TYPED_WCARD) {
203c7c5a728Srenato switch (type) {
204c7c5a728Srenato case MSG_TYPE_LABELMAPPING:
205c7c5a728Srenato case MSG_TYPE_LABELABORTREQ:
206c7c5a728Srenato session_shutdown(nbr, S_UNKNOWN_FEC, msg.id,
207c7c5a728Srenato msg.type);
208c7c5a728Srenato goto err;
209c7c5a728Srenato default:
210c7c5a728Srenato break;
211c7c5a728Srenato }
212c7c5a728Srenato }
213c7c5a728Srenato
214c7c5a728Srenato /*
215cf650e8bSrenato * LDP supports the use of multiple FEC Elements per
216cf650e8bSrenato * FEC for the Label Mapping message only.
217cf650e8bSrenato */
218cf650e8bSrenato if (type != MSG_TYPE_LABELMAPPING &&
219cf650e8bSrenato tlen != feclen) {
22060e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
221cf650e8bSrenato goto err;
222cf650e8bSrenato }
22389f23408Sclaudio
2248d99d653Srenato mapping_list_add(&mh, &map);
2258d99d653Srenato
22689f23408Sclaudio buf += tlen;
227cf650e8bSrenato len -= tlen;
22889f23408Sclaudio feclen -= tlen;
22989f23408Sclaudio } while (feclen > 0);
23001302d08Sclaudio
231cf650e8bSrenato /* Mandatory Label TLV */
232cf650e8bSrenato if (type == MSG_TYPE_LABELMAPPING) {
23360e1e0e7Srenato lbllen = tlv_decode_label(nbr, &msg, buf, len, &label);
234cf650e8bSrenato if (lbllen == -1)
235cf650e8bSrenato goto err;
236cf650e8bSrenato
237cf650e8bSrenato buf += lbllen;
238cf650e8bSrenato len -= lbllen;
239cf650e8bSrenato }
240cf650e8bSrenato
241cf650e8bSrenato /* Optional Parameters */
242cf650e8bSrenato while (len > 0) {
243cf650e8bSrenato struct tlv tlv;
2443b4c1866Srenato uint16_t tlv_type;
2452c943183Srenato uint16_t tlv_len;
2463de94509Srenato uint32_t reqbuf, labelbuf, statusbuf;
247cf650e8bSrenato
248cf650e8bSrenato if (len < sizeof(tlv)) {
24960e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
250cf650e8bSrenato goto err;
251cf650e8bSrenato }
252cf650e8bSrenato
25360e1e0e7Srenato memcpy(&tlv, buf, TLV_HDR_SIZE);
2543b4c1866Srenato tlv_type = ntohs(tlv.type);
255a78ea73fSrenato tlv_len = ntohs(tlv.length);
256a78ea73fSrenato if (tlv_len + TLV_HDR_SIZE > len) {
257a78ea73fSrenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
258a78ea73fSrenato goto err;
259a78ea73fSrenato }
26060e1e0e7Srenato buf += TLV_HDR_SIZE;
26160e1e0e7Srenato len -= TLV_HDR_SIZE;
262cf650e8bSrenato
2633b4c1866Srenato switch (tlv_type) {
264cf650e8bSrenato case TLV_TYPE_LABELREQUEST:
265cf650e8bSrenato switch (type) {
266cf650e8bSrenato case MSG_TYPE_LABELMAPPING:
267cf483f25Srenato case MSG_TYPE_LABELREQUEST:
26860e1e0e7Srenato if (tlv_len != REQID_TLV_LEN) {
269cf650e8bSrenato session_shutdown(nbr, S_BAD_TLV_LEN,
27060e1e0e7Srenato msg.id, msg.type);
271cf650e8bSrenato goto err;
272cf650e8bSrenato }
273cf650e8bSrenato
274cf650e8bSrenato flags |= F_MAP_REQ_ID;
27583a7713fSderaadt memcpy(&reqbuf, buf, sizeof(reqbuf));
27683a7713fSderaadt reqid = ntohl(reqbuf);
277cf650e8bSrenato break;
278cf650e8bSrenato default:
279cf650e8bSrenato /* ignore */
280cf650e8bSrenato break;
281cf650e8bSrenato }
282cf650e8bSrenato break;
2835953eecfSrenato case TLV_TYPE_HOPCOUNT:
2845953eecfSrenato case TLV_TYPE_PATHVECTOR:
2855953eecfSrenato /* ignore */
2865953eecfSrenato break;
287cf650e8bSrenato case TLV_TYPE_GENERICLABEL:
288cf650e8bSrenato switch (type) {
289cf650e8bSrenato case MSG_TYPE_LABELWITHDRAW:
290cf650e8bSrenato case MSG_TYPE_LABELRELEASE:
29160e1e0e7Srenato if (tlv_len != LABEL_TLV_LEN) {
292cf650e8bSrenato session_shutdown(nbr, S_BAD_TLV_LEN,
29360e1e0e7Srenato msg.id, msg.type);
294cf650e8bSrenato goto err;
295cf650e8bSrenato }
296cf650e8bSrenato
29783a7713fSderaadt memcpy(&labelbuf, buf, sizeof(labelbuf));
29883a7713fSderaadt label = ntohl(labelbuf);
299cf650e8bSrenato break;
300cf650e8bSrenato default:
301cf650e8bSrenato /* ignore */
302cf650e8bSrenato break;
303cf650e8bSrenato }
304cf650e8bSrenato break;
305cf650e8bSrenato case TLV_TYPE_ATMLABEL:
306cf650e8bSrenato case TLV_TYPE_FRLABEL:
307cf650e8bSrenato switch (type) {
308cf650e8bSrenato case MSG_TYPE_LABELWITHDRAW:
309cf650e8bSrenato case MSG_TYPE_LABELRELEASE:
310cf650e8bSrenato /* unsupported */
31160e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
31260e1e0e7Srenato msg.type);
313cf650e8bSrenato goto err;
314cf650e8bSrenato break;
315cf650e8bSrenato default:
316cf650e8bSrenato /* ignore */
317cf650e8bSrenato break;
318cf650e8bSrenato }
319cf650e8bSrenato break;
3205ba85977Srenato case TLV_TYPE_STATUS:
3215ba85977Srenato if (tlv_len != STATUS_TLV_LEN) {
32260e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
32360e1e0e7Srenato msg.type);
3245ba85977Srenato goto err;
3255ba85977Srenato }
3265ba85977Srenato /* ignore */
3275ba85977Srenato break;
3286399cec1Srenato case TLV_TYPE_PW_STATUS:
3296399cec1Srenato switch (type) {
3306399cec1Srenato case MSG_TYPE_LABELMAPPING:
33160e1e0e7Srenato if (tlv_len != PW_STATUS_TLV_LEN) {
3326399cec1Srenato session_shutdown(nbr, S_BAD_TLV_LEN,
33360e1e0e7Srenato msg.id, msg.type);
3346399cec1Srenato goto err;
3356399cec1Srenato }
3366399cec1Srenato
3376399cec1Srenato flags |= F_MAP_PW_STATUS;
3386399cec1Srenato memcpy(&statusbuf, buf, sizeof(statusbuf));
3396399cec1Srenato pw_status = ntohl(statusbuf);
3406399cec1Srenato break;
3416399cec1Srenato default:
3426399cec1Srenato /* ignore */
3436399cec1Srenato break;
3446399cec1Srenato }
3456399cec1Srenato break;
346cf650e8bSrenato default:
347a78ea73fSrenato if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
3483b4c1866Srenato send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
3493b4c1866Srenato msg.id, msg.type, tlv_type, tlv_len, buf);
350cf650e8bSrenato /* ignore unknown tlv */
351cf650e8bSrenato break;
352cf650e8bSrenato }
3532c943183Srenato buf += tlv_len;
3542c943183Srenato len -= tlv_len;
355cf650e8bSrenato }
356cf650e8bSrenato
357cf650e8bSrenato /* notify lde about the received message. */
358cf650e8bSrenato while ((me = TAILQ_FIRST(&mh)) != NULL) {
359cf650e8bSrenato int imsg_type = IMSG_NONE;
360cf650e8bSrenato
361cf650e8bSrenato me->map.flags |= flags;
362a8c39dc0Srenato switch (me->map.type) {
363a8c39dc0Srenato case MAP_TYPE_PREFIX:
364a8c39dc0Srenato switch (me->map.fec.prefix.af) {
36500f5e67fSrenato case AF_INET:
366a8c39dc0Srenato if (label == MPLS_LABEL_IPV6NULL) {
367a8c39dc0Srenato session_shutdown(nbr, S_BAD_TLV_VAL,
36860e1e0e7Srenato msg.id, msg.type);
369a8c39dc0Srenato goto err;
370a8c39dc0Srenato }
371a8c39dc0Srenato if (!nbr->v4_enabled)
372a8c39dc0Srenato goto next;
373a8c39dc0Srenato break;
37400f5e67fSrenato case AF_INET6:
375a8c39dc0Srenato if (label == MPLS_LABEL_IPV4NULL) {
376a8c39dc0Srenato session_shutdown(nbr, S_BAD_TLV_VAL,
37760e1e0e7Srenato msg.id, msg.type);
378a8c39dc0Srenato goto err;
379a8c39dc0Srenato }
380a8c39dc0Srenato if (!nbr->v6_enabled)
381a8c39dc0Srenato goto next;
382a8c39dc0Srenato break;
383a8c39dc0Srenato default:
384a8c39dc0Srenato fatalx("recv_labelmessage: unknown af");
385a8c39dc0Srenato }
386a8c39dc0Srenato break;
387a8c39dc0Srenato case MAP_TYPE_PWID:
388998f69edSrenato if (label <= MPLS_LABEL_RESERVED_MAX) {
38960e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
39060e1e0e7Srenato msg.type);
391998f69edSrenato goto err;
392998f69edSrenato }
393998f69edSrenato if (me->map.flags & F_MAP_PW_STATUS)
394998f69edSrenato me->map.pw_status = pw_status;
395a8c39dc0Srenato break;
396a8c39dc0Srenato default:
397a8c39dc0Srenato break;
398998f69edSrenato }
399cf650e8bSrenato me->map.label = label;
400cf650e8bSrenato if (me->map.flags & F_MAP_REQ_ID)
401cf650e8bSrenato me->map.requestid = reqid;
402cf650e8bSrenato
403297a8bbeSrenato log_msg_mapping(0, type, nbr, &me->map);
404c0cfacb4Srenato
405cf650e8bSrenato switch (type) {
406cf650e8bSrenato case MSG_TYPE_LABELMAPPING:
407cf650e8bSrenato imsg_type = IMSG_LABEL_MAPPING;
408cf650e8bSrenato break;
409cf650e8bSrenato case MSG_TYPE_LABELREQUEST:
410cf650e8bSrenato imsg_type = IMSG_LABEL_REQUEST;
411cf650e8bSrenato break;
412cf650e8bSrenato case MSG_TYPE_LABELWITHDRAW:
413cf650e8bSrenato imsg_type = IMSG_LABEL_WITHDRAW;
414cf650e8bSrenato break;
415cf650e8bSrenato case MSG_TYPE_LABELRELEASE:
416cf650e8bSrenato imsg_type = IMSG_LABEL_RELEASE;
417cf650e8bSrenato break;
418cf650e8bSrenato case MSG_TYPE_LABELABORTREQ:
419cf650e8bSrenato imsg_type = IMSG_LABEL_ABORT;
420cf650e8bSrenato break;
421cf650e8bSrenato default:
422cf650e8bSrenato break;
423cf650e8bSrenato }
424cf650e8bSrenato
425cf650e8bSrenato ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map,
426cf650e8bSrenato sizeof(struct map));
427cf650e8bSrenato
428a8c39dc0Srenato next:
429cf650e8bSrenato TAILQ_REMOVE(&mh, me, entry);
430cf650e8bSrenato free(me);
431cf650e8bSrenato }
432cf650e8bSrenato
4339277622bSrenato return (0);
434cf650e8bSrenato
435cf650e8bSrenato err:
436cf650e8bSrenato mapping_list_clr(&mh);
437cf650e8bSrenato
438cf650e8bSrenato return (-1);
439ab0c2486Smichele }
440ab0c2486Smichele
441ab0c2486Smichele /* Other TLV related functions */
44265f1d9c1Srenato static int
gen_label_tlv(struct ibuf * buf,uint32_t label)4433de94509Srenato gen_label_tlv(struct ibuf *buf, uint32_t label)
4443220fd77Sclaudio {
4453220fd77Sclaudio struct label_tlv lt;
4463220fd77Sclaudio
4473220fd77Sclaudio lt.type = htons(TLV_TYPE_GENERICLABEL);
44860e1e0e7Srenato lt.length = htons(LABEL_TLV_LEN);
4493220fd77Sclaudio lt.label = htonl(label);
4503220fd77Sclaudio
45165f1d9c1Srenato return (ibuf_add(buf, <, sizeof(lt)));
4523220fd77Sclaudio }
4533220fd77Sclaudio
454c28a25a1Srenato static int
tlv_decode_label(struct nbr * nbr,struct ldp_msg * msg,char * buf,uint16_t len,uint32_t * label)45560e1e0e7Srenato tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf,
4563de94509Srenato uint16_t len, uint32_t *label)
4573220fd77Sclaudio {
45889f23408Sclaudio struct label_tlv lt;
4593220fd77Sclaudio
46035791d36Srenato if (len < sizeof(lt)) {
46160e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type);
46289f23408Sclaudio return (-1);
46335791d36Srenato }
4643de94509Srenato memcpy(<, buf, sizeof(lt));
4653220fd77Sclaudio
46635791d36Srenato if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) {
4670101edf8Srenato send_notification(nbr->tcp, S_MISS_MSG, msg->id, msg->type);
46889f23408Sclaudio return (-1);
46935791d36Srenato }
47089f23408Sclaudio
47135791d36Srenato switch (htons(lt.type)) {
47235791d36Srenato case TLV_TYPE_GENERICLABEL:
47360e1e0e7Srenato if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) {
47460e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
47560e1e0e7Srenato msg->type);
47689f23408Sclaudio return (-1);
47735791d36Srenato }
47889f23408Sclaudio
47989f23408Sclaudio *label = ntohl(lt.label);
48035791d36Srenato if (*label > MPLS_LABEL_MAX ||
48135791d36Srenato (*label <= MPLS_LABEL_RESERVED_MAX &&
48235791d36Srenato *label != MPLS_LABEL_IPV4NULL &&
483a8c39dc0Srenato *label != MPLS_LABEL_IPV6NULL &&
48435791d36Srenato *label != MPLS_LABEL_IMPLNULL)) {
48560e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
48660e1e0e7Srenato msg->type);
48735791d36Srenato return (-1);
48835791d36Srenato }
48935791d36Srenato break;
49035791d36Srenato case TLV_TYPE_ATMLABEL:
49135791d36Srenato case TLV_TYPE_FRLABEL:
49235791d36Srenato default:
49335791d36Srenato /* unsupported */
49460e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type);
49535791d36Srenato return (-1);
49635791d36Srenato }
49789f23408Sclaudio
49889f23408Sclaudio return (sizeof(lt));
4993220fd77Sclaudio }
5003220fd77Sclaudio
50165f1d9c1Srenato static int
gen_reqid_tlv(struct ibuf * buf,uint32_t reqid)5023de94509Srenato gen_reqid_tlv(struct ibuf *buf, uint32_t reqid)
5033220fd77Sclaudio {
5043220fd77Sclaudio struct reqid_tlv rt;
5053220fd77Sclaudio
5063220fd77Sclaudio rt.type = htons(TLV_TYPE_LABELREQUEST);
50760e1e0e7Srenato rt.length = htons(REQID_TLV_LEN);
5083220fd77Sclaudio rt.reqid = htonl(reqid);
5093220fd77Sclaudio
51065f1d9c1Srenato return (ibuf_add(buf, &rt, sizeof(rt)));
5113220fd77Sclaudio }
5123220fd77Sclaudio
51365f1d9c1Srenato int
gen_pw_status_tlv(struct ibuf * buf,uint32_t status)5143de94509Srenato gen_pw_status_tlv(struct ibuf *buf, uint32_t status)
515ab0c2486Smichele {
5166399cec1Srenato struct pw_status_tlv st;
517ab0c2486Smichele
5186399cec1Srenato st.type = htons(TLV_TYPE_PW_STATUS);
51960e1e0e7Srenato st.length = htons(PW_STATUS_TLV_LEN);
5206399cec1Srenato st.value = htonl(status);
521ab0c2486Smichele
52265f1d9c1Srenato return (ibuf_add(buf, &st, sizeof(st)));
523ab0c2486Smichele }
524ab0c2486Smichele
5259246985aSrenato uint16_t
len_fec_tlv(struct map * map)5269246985aSrenato len_fec_tlv(struct map *map)
5279246985aSrenato {
5289246985aSrenato uint16_t len = TLV_HDR_SIZE;
5299246985aSrenato
5309246985aSrenato switch (map->type) {
5319246985aSrenato case MAP_TYPE_WILDCARD:
5329246985aSrenato len += FEC_ELM_WCARD_LEN;
5339246985aSrenato break;
5349246985aSrenato case MAP_TYPE_PREFIX:
5359246985aSrenato len += FEC_ELM_PREFIX_MIN_LEN +
5369246985aSrenato PREFIX_SIZE(map->fec.prefix.prefixlen);
5379246985aSrenato break;
5389246985aSrenato case MAP_TYPE_PWID:
5399246985aSrenato len += FEC_PWID_ELM_MIN_LEN;
5409246985aSrenato if (map->flags & F_MAP_PW_ID)
5419246985aSrenato len += PW_STATUS_TLV_LEN;
5429246985aSrenato if (map->flags & F_MAP_PW_IFMTU)
5439246985aSrenato len += FEC_SUBTLV_IFMTU_SIZE;
5449246985aSrenato if (map->flags & F_MAP_PW_STATUS)
5459246985aSrenato len += PW_STATUS_TLV_SIZE;
5469246985aSrenato break;
5479246985aSrenato case MAP_TYPE_TYPED_WCARD:
5489246985aSrenato len += FEC_ELM_TWCARD_MIN_LEN;
5499246985aSrenato switch (map->fec.twcard.type) {
5509246985aSrenato case MAP_TYPE_PREFIX:
5519246985aSrenato case MAP_TYPE_PWID:
5529246985aSrenato len += sizeof(uint16_t);
5539246985aSrenato break;
5549246985aSrenato default:
5559246985aSrenato fatalx("len_fec_tlv: unexpected fec type");
5569246985aSrenato }
5579246985aSrenato break;
5589246985aSrenato default:
5599246985aSrenato fatalx("len_fec_tlv: unexpected fec type");
5609246985aSrenato }
5619246985aSrenato
5629246985aSrenato return (len);
5639246985aSrenato }
5649246985aSrenato
56565f1d9c1Srenato int
gen_fec_tlv(struct ibuf * buf,struct map * map)5666399cec1Srenato gen_fec_tlv(struct ibuf *buf, struct map *map)
567cf483f25Srenato {
568cf483f25Srenato struct tlv ft;
5693de94509Srenato uint16_t family, len, pw_type, ifmtu;
570c7c5a728Srenato uint8_t pw_len = 0, twcard_len;
5713de94509Srenato uint32_t group_id, pwid;
57265f1d9c1Srenato int err = 0;
573cf483f25Srenato
574cf483f25Srenato ft.type = htons(TLV_TYPE_FEC);
5756399cec1Srenato
5766399cec1Srenato switch (map->type) {
5773de94509Srenato case MAP_TYPE_WILDCARD:
5783de94509Srenato ft.length = htons(sizeof(uint8_t));
57965f1d9c1Srenato err |= ibuf_add(buf, &ft, sizeof(ft));
58065f1d9c1Srenato err |= ibuf_add(buf, &map->type, sizeof(map->type));
5816399cec1Srenato break;
5823de94509Srenato case MAP_TYPE_PREFIX:
583a8c39dc0Srenato len = PREFIX_SIZE(map->fec.prefix.prefixlen);
5846399cec1Srenato ft.length = htons(sizeof(map->type) + sizeof(family) +
585a8c39dc0Srenato sizeof(map->fec.prefix.prefixlen) + len);
58665f1d9c1Srenato err |= ibuf_add(buf, &ft, sizeof(ft));
58765f1d9c1Srenato err |= ibuf_add(buf, &map->type, sizeof(map->type));
58800f5e67fSrenato switch (map->fec.prefix.af) {
58900f5e67fSrenato case AF_INET:
59000f5e67fSrenato family = htons(AF_IPV4);
59100f5e67fSrenato break;
59200f5e67fSrenato case AF_INET6:
59300f5e67fSrenato family = htons(AF_IPV6);
59400f5e67fSrenato break;
59500f5e67fSrenato default:
59600f5e67fSrenato fatalx("gen_fec_tlv: unknown af");
59700f5e67fSrenato break;
59800f5e67fSrenato }
59965f1d9c1Srenato err |= ibuf_add(buf, &family, sizeof(family));
60065f1d9c1Srenato err |= ibuf_add(buf, &map->fec.prefix.prefixlen,
601a8c39dc0Srenato sizeof(map->fec.prefix.prefixlen));
6026399cec1Srenato if (len)
60365f1d9c1Srenato err |= ibuf_add(buf, &map->fec.prefix.prefix, len);
6046399cec1Srenato break;
605cf09440fSrenato case MAP_TYPE_PWID:
6066399cec1Srenato if (map->flags & F_MAP_PW_ID)
60702a212eeSrenato pw_len += FEC_PWID_SIZE;
6086399cec1Srenato if (map->flags & F_MAP_PW_IFMTU)
60960e1e0e7Srenato pw_len += FEC_SUBTLV_IFMTU_SIZE;
6106399cec1Srenato
6116399cec1Srenato len = FEC_PWID_ELM_MIN_LEN + pw_len;
6126399cec1Srenato
6136399cec1Srenato ft.length = htons(len);
61465f1d9c1Srenato err |= ibuf_add(buf, &ft, sizeof(ft));
6156399cec1Srenato
61665f1d9c1Srenato err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
6176399cec1Srenato pw_type = map->fec.pwid.type;
6186399cec1Srenato if (map->flags & F_MAP_PW_CWORD)
6196399cec1Srenato pw_type |= CONTROL_WORD_FLAG;
6206399cec1Srenato pw_type = htons(pw_type);
62165f1d9c1Srenato err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
62265f1d9c1Srenato err |= ibuf_add(buf, &pw_len, sizeof(uint8_t));
6236399cec1Srenato group_id = htonl(map->fec.pwid.group_id);
62465f1d9c1Srenato err |= ibuf_add(buf, &group_id, sizeof(uint32_t));
6256399cec1Srenato if (map->flags & F_MAP_PW_ID) {
6266399cec1Srenato pwid = htonl(map->fec.pwid.pwid);
62765f1d9c1Srenato err |= ibuf_add(buf, &pwid, sizeof(uint32_t));
6286399cec1Srenato }
6296399cec1Srenato if (map->flags & F_MAP_PW_IFMTU) {
6306399cec1Srenato struct subtlv stlv;
6316399cec1Srenato
6326399cec1Srenato stlv.type = SUBTLV_IFMTU;
63360e1e0e7Srenato stlv.length = FEC_SUBTLV_IFMTU_SIZE;
63465f1d9c1Srenato err |= ibuf_add(buf, &stlv, sizeof(uint16_t));
6356399cec1Srenato
6366399cec1Srenato ifmtu = htons(map->fec.pwid.ifmtu);
63765f1d9c1Srenato err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t));
6386399cec1Srenato }
6396399cec1Srenato break;
640c7c5a728Srenato case MAP_TYPE_TYPED_WCARD:
641c7c5a728Srenato len = FEC_ELM_TWCARD_MIN_LEN;
642c7c5a728Srenato switch (map->fec.twcard.type) {
643c7c5a728Srenato case MAP_TYPE_PREFIX:
6446702dd25Srenato case MAP_TYPE_PWID:
645c7c5a728Srenato len += sizeof(uint16_t);
646c7c5a728Srenato break;
647c7c5a728Srenato default:
648c7c5a728Srenato fatalx("gen_fec_tlv: unexpected fec type");
649c7c5a728Srenato }
650c7c5a728Srenato ft.length = htons(len);
651c7c5a728Srenato err |= ibuf_add(buf, &ft, sizeof(ft));
652c7c5a728Srenato err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
653c7c5a728Srenato err |= ibuf_add(buf, &map->fec.twcard.type, sizeof(uint8_t));
654c7c5a728Srenato
655c7c5a728Srenato switch (map->fec.twcard.type) {
656c7c5a728Srenato case MAP_TYPE_PREFIX:
657c7c5a728Srenato twcard_len = sizeof(uint16_t);
658c7c5a728Srenato err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
659c7c5a728Srenato
660c7c5a728Srenato switch (map->fec.twcard.u.prefix_af) {
661c7c5a728Srenato case AF_INET:
662c7c5a728Srenato family = htons(AF_IPV4);
663c7c5a728Srenato break;
664c7c5a728Srenato case AF_INET6:
665c7c5a728Srenato family = htons(AF_IPV6);
666c7c5a728Srenato break;
667c7c5a728Srenato default:
668c7c5a728Srenato fatalx("gen_fec_tlv: unknown af");
669c7c5a728Srenato break;
670c7c5a728Srenato }
671c7c5a728Srenato
672c7c5a728Srenato err |= ibuf_add(buf, &family, sizeof(uint16_t));
673c7c5a728Srenato break;
6746702dd25Srenato case MAP_TYPE_PWID:
6756702dd25Srenato twcard_len = sizeof(uint16_t);
6766702dd25Srenato err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
6776702dd25Srenato pw_type = htons(map->fec.twcard.u.pw_type);
6786702dd25Srenato err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
6796702dd25Srenato break;
680c7c5a728Srenato default:
681c7c5a728Srenato fatalx("gen_fec_tlv: unexpected fec type");
682c7c5a728Srenato }
683c7c5a728Srenato break;
6846399cec1Srenato default:
6856399cec1Srenato break;
6866399cec1Srenato }
68765f1d9c1Srenato
68865f1d9c1Srenato return (err);
689cf483f25Srenato }
690cf483f25Srenato
691ab0c2486Smichele int
tlv_decode_fec_elm(struct nbr * nbr,struct ldp_msg * msg,char * buf,uint16_t len,struct map * map)69260e1e0e7Srenato tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
6933de94509Srenato uint16_t len, struct map *map)
694ab0c2486Smichele {
695a8c39dc0Srenato uint16_t off = 0;
696c7c5a728Srenato uint8_t pw_len, twcard_len;
697ab0c2486Smichele
6986399cec1Srenato map->type = *buf;
6993de94509Srenato off += sizeof(uint8_t);
700dc9c556eSmichele
7016399cec1Srenato switch (map->type) {
702cf09440fSrenato case MAP_TYPE_WILDCARD:
703cf483f25Srenato if (len == FEC_ELM_WCARD_LEN)
704fae3538eSclaudio return (off);
70535791d36Srenato else {
70660e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
70760e1e0e7Srenato msg->type);
70835791d36Srenato return (-1);
70935791d36Srenato }
7106399cec1Srenato break;
711cf09440fSrenato case MAP_TYPE_PREFIX:
712cf483f25Srenato if (len < FEC_ELM_PREFIX_MIN_LEN) {
71360e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
71460e1e0e7Srenato msg->type);
71535791d36Srenato return (-1);
71635791d36Srenato }
717ab0c2486Smichele
7186399cec1Srenato /* Address Family */
719a8c39dc0Srenato memcpy(&map->fec.prefix.af, buf + off,
720a8c39dc0Srenato sizeof(map->fec.prefix.af));
721a8c39dc0Srenato off += sizeof(map->fec.prefix.af);
72200f5e67fSrenato map->fec.prefix.af = ntohs(map->fec.prefix.af);
72300f5e67fSrenato switch (map->fec.prefix.af) {
72400f5e67fSrenato case AF_IPV4:
72500f5e67fSrenato map->fec.prefix.af = AF_INET;
72600f5e67fSrenato break;
72700f5e67fSrenato case AF_IPV6:
72800f5e67fSrenato map->fec.prefix.af = AF_INET6;
72900f5e67fSrenato break;
73000f5e67fSrenato default:
7310101edf8Srenato send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id,
73260e1e0e7Srenato msg->type);
73335791d36Srenato return (-1);
73435791d36Srenato }
735ab0c2486Smichele
736a8c39dc0Srenato /* Prefix Length */
737a8c39dc0Srenato map->fec.prefix.prefixlen = buf[off];
7383de94509Srenato off += sizeof(uint8_t);
739a8c39dc0Srenato if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) {
74060e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
74160e1e0e7Srenato msg->type);
74235791d36Srenato return (-1);
74335791d36Srenato }
744fae3538eSclaudio
7456399cec1Srenato /* Prefix */
746a8c39dc0Srenato memset(&map->fec.prefix.prefix, 0,
747a8c39dc0Srenato sizeof(map->fec.prefix.prefix));
748a8c39dc0Srenato memcpy(&map->fec.prefix.prefix, buf + off,
749a8c39dc0Srenato PREFIX_SIZE(map->fec.prefix.prefixlen));
750fae3538eSclaudio
75100f5e67fSrenato /* Just in case... */
75200f5e67fSrenato ldp_applymask(map->fec.prefix.af, &map->fec.prefix.prefix,
75300f5e67fSrenato &map->fec.prefix.prefix, map->fec.prefix.prefixlen);
75400f5e67fSrenato
755a8c39dc0Srenato return (off + PREFIX_SIZE(map->fec.prefix.prefixlen));
756cf09440fSrenato case MAP_TYPE_PWID:
7576399cec1Srenato if (len < FEC_PWID_ELM_MIN_LEN) {
75860e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
75960e1e0e7Srenato msg->type);
7606399cec1Srenato return (-1);
7616399cec1Srenato }
7626399cec1Srenato
7636399cec1Srenato /* PW type */
7643de94509Srenato memcpy(&map->fec.pwid.type, buf + off, sizeof(uint16_t));
7656399cec1Srenato map->fec.pwid.type = ntohs(map->fec.pwid.type);
7666399cec1Srenato if (map->fec.pwid.type & CONTROL_WORD_FLAG) {
7676399cec1Srenato map->flags |= F_MAP_PW_CWORD;
7686399cec1Srenato map->fec.pwid.type &= ~CONTROL_WORD_FLAG;
7696399cec1Srenato }
7703de94509Srenato off += sizeof(uint16_t);
7716399cec1Srenato
7726399cec1Srenato /* PW info Length */
7736399cec1Srenato pw_len = buf[off];
7743de94509Srenato off += sizeof(uint8_t);
7756399cec1Srenato
7766399cec1Srenato if (len != FEC_PWID_ELM_MIN_LEN + pw_len) {
77760e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
77860e1e0e7Srenato msg->type);
7796399cec1Srenato return (-1);
7806399cec1Srenato }
7816399cec1Srenato
7826399cec1Srenato /* Group ID */
7833de94509Srenato memcpy(&map->fec.pwid.group_id, buf + off, sizeof(uint32_t));
7846399cec1Srenato map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id);
7853de94509Srenato off += sizeof(uint32_t);
7866399cec1Srenato
7876399cec1Srenato /* PW ID */
7886399cec1Srenato if (pw_len == 0)
7896399cec1Srenato return (off);
7906399cec1Srenato
7913de94509Srenato if (pw_len < sizeof(uint32_t)) {
79260e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
79360e1e0e7Srenato msg->type);
7946399cec1Srenato return (-1);
7956399cec1Srenato }
7966399cec1Srenato
7973de94509Srenato memcpy(&map->fec.pwid.pwid, buf + off, sizeof(uint32_t));
7986399cec1Srenato map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid);
7996399cec1Srenato map->flags |= F_MAP_PW_ID;
8003de94509Srenato off += sizeof(uint32_t);
8013de94509Srenato pw_len -= sizeof(uint32_t);
8026399cec1Srenato
8036399cec1Srenato /* Optional Interface Parameter Sub-TLVs */
8046399cec1Srenato while (pw_len > 0) {
8056399cec1Srenato struct subtlv stlv;
8066399cec1Srenato
8076399cec1Srenato if (pw_len < sizeof(stlv)) {
80860e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
80960e1e0e7Srenato msg->type);
8106399cec1Srenato return (-1);
8116399cec1Srenato }
8126399cec1Srenato
8133de94509Srenato memcpy(&stlv, buf + off, sizeof(stlv));
814a78ea73fSrenato if (stlv.length > pw_len) {
815a78ea73fSrenato session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
816a78ea73fSrenato msg->type);
817a78ea73fSrenato return (-1);
818a78ea73fSrenato }
819a78ea73fSrenato
8206399cec1Srenato switch (stlv.type) {
8216399cec1Srenato case SUBTLV_IFMTU:
82260e1e0e7Srenato if (stlv.length != FEC_SUBTLV_IFMTU_SIZE) {
8236399cec1Srenato session_shutdown(nbr, S_BAD_TLV_LEN,
82460e1e0e7Srenato msg->id, msg->type);
8256399cec1Srenato return (-1);
8266399cec1Srenato }
827d3e006a4Srenato memcpy(&map->fec.pwid.ifmtu, buf + off +
82860e1e0e7Srenato SUBTLV_HDR_SIZE, sizeof(uint16_t));
8296399cec1Srenato map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu);
8306399cec1Srenato map->flags |= F_MAP_PW_IFMTU;
8316399cec1Srenato break;
8326399cec1Srenato default:
8336399cec1Srenato /* ignore */
8346399cec1Srenato break;
8356399cec1Srenato }
836d3e006a4Srenato off += stlv.length;
837d3e006a4Srenato pw_len -= stlv.length;
8386399cec1Srenato }
8396399cec1Srenato
8406399cec1Srenato return (off);
841c7c5a728Srenato case MAP_TYPE_TYPED_WCARD:
842c7c5a728Srenato if (len < FEC_ELM_TWCARD_MIN_LEN) {
843c7c5a728Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
844c7c5a728Srenato msg->type);
845c7c5a728Srenato return (-1);
846c7c5a728Srenato }
847c7c5a728Srenato
848c7c5a728Srenato memcpy(&map->fec.twcard.type, buf + off, sizeof(uint8_t));
849c7c5a728Srenato off += sizeof(uint8_t);
850c7c5a728Srenato memcpy(&twcard_len, buf + off, sizeof(uint8_t));
851c7c5a728Srenato off += sizeof(uint8_t);
852c7c5a728Srenato if (len != FEC_ELM_TWCARD_MIN_LEN + twcard_len) {
853c7c5a728Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
854c7c5a728Srenato msg->type);
855c7c5a728Srenato return (-1);
856c7c5a728Srenato }
857c7c5a728Srenato
858c7c5a728Srenato switch (map->fec.twcard.type) {
859c7c5a728Srenato case MAP_TYPE_PREFIX:
860c7c5a728Srenato if (twcard_len != sizeof(uint16_t)) {
861c7c5a728Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
862c7c5a728Srenato msg->type);
863c7c5a728Srenato return (-1);
864c7c5a728Srenato }
865c7c5a728Srenato
866c7c5a728Srenato memcpy(&map->fec.twcard.u.prefix_af, buf + off,
867c7c5a728Srenato sizeof(uint16_t));
868c7c5a728Srenato map->fec.twcard.u.prefix_af =
869c7c5a728Srenato ntohs(map->fec.twcard.u.prefix_af);
870c7c5a728Srenato off += sizeof(uint16_t);
871c7c5a728Srenato
872c7c5a728Srenato switch (map->fec.twcard.u.prefix_af) {
873c7c5a728Srenato case AF_IPV4:
874c7c5a728Srenato map->fec.twcard.u.prefix_af = AF_INET;
875c7c5a728Srenato break;
876c7c5a728Srenato case AF_IPV6:
877c7c5a728Srenato map->fec.twcard.u.prefix_af = AF_INET6;
878c7c5a728Srenato break;
879c7c5a728Srenato default:
880c7c5a728Srenato session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
881c7c5a728Srenato msg->type);
882c7c5a728Srenato return (-1);
883c7c5a728Srenato }
884c7c5a728Srenato break;
8856702dd25Srenato case MAP_TYPE_PWID:
8866702dd25Srenato if (twcard_len != sizeof(uint16_t)) {
8876702dd25Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
8886702dd25Srenato msg->type);
8896702dd25Srenato return (-1);
8906702dd25Srenato }
8916702dd25Srenato
8926702dd25Srenato memcpy(&map->fec.twcard.u.pw_type, buf + off,
8936702dd25Srenato sizeof(uint16_t));
8946702dd25Srenato map->fec.twcard.u.pw_type =
8956702dd25Srenato ntohs(map->fec.twcard.u.pw_type);
8966702dd25Srenato /* ignore the reserved bit as per RFC 6667 */
8976702dd25Srenato map->fec.twcard.u.pw_type &= ~PW_TWCARD_RESERVED_BIT;
8986702dd25Srenato off += sizeof(uint16_t);
8996702dd25Srenato break;
900c7c5a728Srenato default:
901c7c5a728Srenato send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id,
902c7c5a728Srenato msg->type);
903c7c5a728Srenato return (-1);
904c7c5a728Srenato }
905c7c5a728Srenato
906c7c5a728Srenato return (off);
9076399cec1Srenato default:
9080101edf8Srenato send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type);
9096399cec1Srenato break;
9106399cec1Srenato }
9116399cec1Srenato
9126399cec1Srenato return (-1);
913ab0c2486Smichele }
914297a8bbeSrenato
915297a8bbeSrenato static void
log_msg_mapping(int out,uint16_t msg_type,struct nbr * nbr,struct map * map)916297a8bbeSrenato log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map)
917297a8bbeSrenato {
918297a8bbeSrenato log_debug("msg-%s: %s: lsr-id %s, fec %s, label %s",
919297a8bbeSrenato (out) ? "out" : "in", msg_name(msg_type), inet_ntoa(nbr->id),
920297a8bbeSrenato log_map(map), log_label(map->label));
921297a8bbeSrenato }
922