#include "mpls.h"
-static void enqueue_pdu(struct nbr *, struct ibuf *, uint16_t);
+static void enqueue_pdu(struct nbr *, uint16_t, struct ibuf *, uint16_t);
static int gen_label_tlv(struct ibuf *, uint32_t);
-static int tlv_decode_label(struct nbr *, struct ldp_msg *, char *,
- uint16_t, uint32_t *);
static int gen_reqid_tlv(struct ibuf *, uint32_t);
static void log_msg_mapping(int, uint16_t, struct nbr *, struct map *);
static void
-enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size)
+enqueue_pdu(struct nbr *nbr, uint16_t type, struct ibuf *buf, uint16_t size)
{
struct ldp_hdr *ldp_hdr;
ldp_hdr = ibuf_seek(buf, 0, sizeof(struct ldp_hdr));
- ldp_hdr->length = htons(size);
+ ldp_hdr->length = htons(size - LDP_HDR_DEAD_LEN);
evbuf_enqueue(&nbr->tcp->wbuf, buf);
}
/* real size will be set up later */
err |= gen_ldp_hdr(buf, 0);
- size = LDP_HDR_PDU_LEN;
+ size = LDP_HDR_SIZE;
first = 0;
}
/* calculate size */
- msg_size = LDP_MSG_SIZE + TLV_HDR_SIZE;
- switch (me->map.type) {
- case MAP_TYPE_WILDCARD:
- msg_size += FEC_ELM_WCARD_LEN;
- break;
- case MAP_TYPE_PREFIX:
- msg_size += FEC_ELM_PREFIX_MIN_LEN +
- PREFIX_SIZE(me->map.fec.prefix.prefixlen);
- break;
- case MAP_TYPE_PWID:
- msg_size += FEC_PWID_ELM_MIN_LEN;
- if (me->map.flags & F_MAP_PW_ID)
- msg_size += PW_STATUS_TLV_LEN;
- if (me->map.flags & F_MAP_PW_IFMTU)
- msg_size += FEC_SUBTLV_IFMTU_SIZE;
- if (me->map.flags & F_MAP_PW_STATUS)
- msg_size += PW_STATUS_TLV_SIZE;
- break;
- case MAP_TYPE_TYPED_WCARD:
- msg_size += FEC_ELM_TWCARD_MIN_LEN;
- switch (me->map.fec.twcard.type) {
- case MAP_TYPE_PREFIX:
- case MAP_TYPE_PWID:
- msg_size += sizeof(uint16_t);
- break;
- default:
- fatalx("send_labelmessage: unexpected fec type");
- }
- break;
- }
+ msg_size = LDP_MSG_SIZE;
+ msg_size += len_fec_tlv(&me->map);
if (me->map.label != NO_LABEL)
msg_size += LABEL_TLV_SIZE;
if (me->map.flags & F_MAP_REQ_ID)
/* maximum pdu length exceeded, we need a new ldp pdu */
if (size + msg_size > nbr->max_pdu_len) {
- enqueue_pdu(nbr, buf, size);
+ enqueue_pdu(nbr, type, buf, size);
first = 1;
continue;
}
log_msg_mapping(1, type, nbr, &me->map);
+ /* no errors - update per neighbor message counters */
+ switch (type) {
+ case MSG_TYPE_LABELMAPPING:
+ nbr->stats.labelmap_sent++;
+ break;
+ case MSG_TYPE_LABELREQUEST:
+ nbr->stats.labelreq_sent++;
+ break;
+ case MSG_TYPE_LABELWITHDRAW:
+ nbr->stats.labelwdraw_sent++;
+ break;
+ case MSG_TYPE_LABELRELEASE:
+ nbr->stats.labelrel_sent++;
+ break;
+ case MSG_TYPE_LABELABORTREQ:
+ nbr->stats.labelabreq_sent++;
+ break;
+ default:
+ break;
+ }
+
TAILQ_REMOVE(mh, me, entry);
+ assert(me != TAILQ_FIRST(mh));
free(me);
}
- enqueue_pdu(nbr, buf, size);
+ enqueue_pdu(nbr, type, buf, size);
nbr_fsm(nbr, NBR_EVT_PDU_SENT);
}
uint32_t label = NO_LABEL, reqid = 0;
uint32_t pw_status = 0;
uint8_t flags = 0;
- int feclen, lbllen, tlen;
+ int feclen, tlen;
+ uint16_t current_tlv = 1;
struct mapping_entry *me;
struct mapping_head mh;
struct map map;
type != MSG_TYPE_LABELRELEASE) {
send_notification(nbr->tcp, S_MISS_MSG, msg.id,
msg.type);
- return (-1);
+ goto err;
}
/*
feclen -= tlen;
} while (feclen > 0);
- /* Mandatory Label TLV */
- if (type == MSG_TYPE_LABELMAPPING) {
- lbllen = tlv_decode_label(nbr, &msg, buf, len, &label);
- if (lbllen == -1)
- goto err;
-
- buf += lbllen;
- len -= lbllen;
- }
-
/* Optional Parameters */
while (len > 0) {
struct tlv tlv;
buf += TLV_HDR_SIZE;
len -= TLV_HDR_SIZE;
+ /*
+ * For Label Mapping messages the Label TLV is mandatory and
+ * should appear right after the FEC TLV.
+ */
+ if (current_tlv == 1 && type == MSG_TYPE_LABELMAPPING &&
+ !(tlv_type & TLV_TYPE_GENERICLABEL)) {
+ send_notification(nbr->tcp, S_MISS_MSG, msg.id,
+ msg.type);
+ goto err;
+ }
+
switch (tlv_type) {
case TLV_TYPE_LABELREQUEST:
switch (type) {
break;
case TLV_TYPE_GENERICLABEL:
switch (type) {
+ case MSG_TYPE_LABELMAPPING:
case MSG_TYPE_LABELWITHDRAW:
case MSG_TYPE_LABELRELEASE:
if (tlv_len != LABEL_TLV_LEN) {
memcpy(&labelbuf, buf, sizeof(labelbuf));
label = ntohl(labelbuf);
+ /* do not accept invalid labels */
+ if (label > MPLS_LABEL_MAX ||
+ (label <= MPLS_LABEL_RESERVED_MAX &&
+ label != MPLS_LABEL_IPV4_EXPLICIT_NULL &&
+ label != MPLS_LABEL_IPV6_EXPLICIT_NULL &&
+ label != MPLS_LABEL_IMPLICIT_NULL)) {
+ session_shutdown(nbr, S_BAD_TLV_VAL,
+ msg.id, msg.type);
+ goto err;
+ }
break;
default:
/* ignore */
case TLV_TYPE_ATMLABEL:
case TLV_TYPE_FRLABEL:
switch (type) {
+ case MSG_TYPE_LABELMAPPING:
case MSG_TYPE_LABELWITHDRAW:
case MSG_TYPE_LABELRELEASE:
/* unsupported */
}
buf += tlv_len;
len -= tlv_len;
+ current_tlv++;
}
/* notify lde about the received message. */
case MAP_TYPE_PREFIX:
switch (me->map.fec.prefix.af) {
case AF_INET:
- if (label == MPLS_LABEL_IPV6NULL) {
+ if (label == MPLS_LABEL_IPV6_EXPLICIT_NULL) {
session_shutdown(nbr, S_BAD_TLV_VAL,
msg.id, msg.type);
goto err;
goto next;
break;
case AF_INET6:
- if (label == MPLS_LABEL_IPV4NULL) {
+ if (label == MPLS_LABEL_IPV4_EXPLICIT_NULL) {
session_shutdown(nbr, S_BAD_TLV_VAL,
msg.id, msg.type);
goto err;
next:
TAILQ_REMOVE(&mh, me, entry);
+ assert(me != TAILQ_FIRST(&mh));
free(me);
}
return (ibuf_add(buf, <, sizeof(lt)));
}
-static int
-tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf,
- uint16_t len, uint32_t *label)
-{
- struct label_tlv lt;
-
- if (len < sizeof(lt)) {
- session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type);
- return (-1);
- }
- memcpy(<, buf, sizeof(lt));
-
- if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) {
- send_notification(nbr->tcp, S_MISS_MSG, msg->id, msg->type);
- return (-1);
- }
-
- switch (htons(lt.type)) {
- case TLV_TYPE_GENERICLABEL:
- if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) {
- session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
- msg->type);
- return (-1);
- }
-
- *label = ntohl(lt.label);
- if (*label > MPLS_LABEL_MAX ||
- (*label <= MPLS_LABEL_RESERVED_MAX &&
- *label != MPLS_LABEL_IPV4NULL &&
- *label != MPLS_LABEL_IPV6NULL &&
- *label != MPLS_LABEL_IMPLNULL)) {
- session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
- msg->type);
- return (-1);
- }
- break;
- case TLV_TYPE_ATMLABEL:
- case TLV_TYPE_FRLABEL:
- default:
- /* unsupported */
- session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type);
- return (-1);
- }
-
- return (sizeof(lt));
-}
-
static int
gen_reqid_tlv(struct ibuf *buf, uint32_t reqid)
{
return (ibuf_add(buf, &st, sizeof(st)));
}
+uint16_t
+len_fec_tlv(struct map *map)
+{
+ uint16_t len = TLV_HDR_SIZE;
+
+ switch (map->type) {
+ case MAP_TYPE_WILDCARD:
+ len += FEC_ELM_WCARD_LEN;
+ break;
+ case MAP_TYPE_PREFIX:
+ len += FEC_ELM_PREFIX_MIN_LEN +
+ PREFIX_SIZE(map->fec.prefix.prefixlen);
+ break;
+ case MAP_TYPE_PWID:
+ len += FEC_PWID_ELM_MIN_LEN;
+ if (map->flags & F_MAP_PW_ID)
+ len += PW_STATUS_TLV_LEN;
+ if (map->flags & F_MAP_PW_IFMTU)
+ len += FEC_SUBTLV_IFMTU_SIZE;
+ if (map->flags & F_MAP_PW_STATUS)
+ len += PW_STATUS_TLV_SIZE;
+ break;
+ case MAP_TYPE_TYPED_WCARD:
+ len += FEC_ELM_TWCARD_MIN_LEN;
+ switch (map->fec.twcard.type) {
+ case MAP_TYPE_PREFIX:
+ case MAP_TYPE_PWID:
+ len += sizeof(uint16_t);
+ break;
+ default:
+ fatalx("len_fec_tlv: unexpected fec type");
+ }
+ break;
+ default:
+ fatalx("len_fec_tlv: unexpected fec type");
+ }
+
+ return (len);
+}
+
int
gen_fec_tlv(struct ibuf *buf, struct map *map)
{