summaryrefslogtreecommitdiff
path: root/usr.sbin/ldpd/labelmapping.c
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2010-05-25 09:40:11 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2010-05-25 09:40:11 +0000
commit69524634b4bd806319c98cdbbba47d3e17499849 (patch)
tree3eb0df3c62882ff985b7ef6af171b1079406e5ea /usr.sbin/ldpd/labelmapping.c
parent83f8184091e94b05e8d2b12af39914f7a5e2b900 (diff)
Implement the missing label map recv functions and cleanup the other recv
functions a bit to make them all look more similar. All but the label req abort message are now parsed and passed to the lde.
Diffstat (limited to 'usr.sbin/ldpd/labelmapping.c')
-rw-r--r--usr.sbin/ldpd/labelmapping.c255
1 files changed, 178 insertions, 77 deletions
diff --git a/usr.sbin/ldpd/labelmapping.c b/usr.sbin/ldpd/labelmapping.c
index 9dcc8825af8..966fec475dd 100644
--- a/usr.sbin/ldpd/labelmapping.c
+++ b/usr.sbin/ldpd/labelmapping.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: labelmapping.c,v 1.9 2010/05/17 08:07:04 claudio Exp $ */
+/* $OpenBSD: labelmapping.c,v 1.10 2010/05/25 09:40:10 claudio Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -41,9 +41,8 @@ void gen_fec_tlv(struct buf *, u_int32_t, u_int8_t);
void gen_label_tlv(struct buf *, u_int32_t);
u_int32_t tlv_decode_label(struct label_tlv *);
-u_int32_t decode_fec_elm(char *);
-int decode_fec_len_elm(char *, u_int8_t);
-int validate_fec_elm(char *);
+int tlv_decode_fec_elm(char *, u_int16_t, u_int8_t *, u_int32_t *,
+ u_int8_t *);
/* Label Mapping Message */
void
@@ -92,14 +91,14 @@ recv_labelmapping(struct nbr *nbr, char *buf, u_int16_t len)
struct fec_tlv *ft;
struct label_tlv *lt;
struct map map;
- int feclen, addr_type;
+ int feclen, tlen;
+ u_int8_t addr_type;
log_debug("recv_labelmapping: neighbor ID %s", inet_ntoa(nbr->id));
if (nbr->state != NBR_STA_OPER)
return (-1);
- bzero(&map, sizeof(map));
lm = (struct ldp_msg *)buf;
if ((len - TLV_HDR_LEN) < ntohs(lm->length)) {
@@ -111,46 +110,47 @@ recv_labelmapping(struct nbr *nbr, char *buf, u_int16_t len)
len -= sizeof(struct ldp_msg);
ft = (struct fec_tlv *)buf;
- lt = (struct label_tlv *)(buf + TLV_HDR_LEN + ntohs(ft->length));
- if (len < (sizeof(*ft) + LABEL_TLV_LEN)) {
+ if (len < sizeof(*ft) ||
+ (len - TLV_HDR_LEN) < ntohs(ft->length)) {
session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type);
return (-1);
}
feclen = ntohs(ft->length);
- if (len - TLV_HDR_LEN < feclen) {
+ buf += sizeof(struct fec_tlv);
+ len -= sizeof(struct fec_tlv);
+
+ if (len < feclen + LABEL_TLV_LEN) {
session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type);
return (-1);
}
+ bzero(&map, sizeof(map));
+ map.messageid = lm->msgid;
+
+ lt = (struct label_tlv *)(buf + feclen);
map.label = tlv_decode_label(lt);
if (map.label == NO_LABEL) {
session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, lm->type);
return (-1);
}
- buf += sizeof(struct fec_tlv);
- len -= sizeof(struct fec_tlv);
-
- while (feclen >= FEC_ELM_MIN_LEN) {
- addr_type = validate_fec_elm(buf);
- if (addr_type < 0) {
+ do {
+ if ((tlen = tlv_decode_fec_elm(buf, feclen, &addr_type,
+ &map.prefix, &map.prefixlen)) == -1 ||
+ addr_type == FEC_WILDCARD) {
session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid,
lm->type);
return (-1);
}
- map.prefix = decode_fec_elm(buf);
- map.prefixlen = decode_fec_len_elm(buf, addr_type);
- map.prefix &= prefixlen2mask(map.prefixlen);
-
ldpe_imsg_compose_lde(IMSG_LABEL_MAPPING, nbr->peerid, 0, &map,
sizeof(map));
- buf += FEC_ELM_MIN_LEN + PREFIX_SIZE(map.prefixlen);
- feclen -= (FEC_ELM_MIN_LEN + PREFIX_SIZE(map.prefixlen));
- }
+ buf += tlen;
+ feclen -= tlen;
+ } while (feclen > 0);
nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
@@ -202,14 +202,14 @@ recv_labelrequest(struct nbr *nbr, char *buf, u_int16_t len)
struct ldp_msg *lr;
struct fec_tlv *ft;
struct map map;
- int feclen, addr_type;
+ int feclen, tlen;
+ u_int8_t addr_type;
log_debug("recv_labelrequest: neighbor ID %s", inet_ntoa(nbr->id));
if (nbr->state != NBR_STA_OPER)
return (-1);
- bzero(&map, sizeof(map));
lr = (struct ldp_msg *)buf;
if ((len - TLV_HDR_LEN) < ntohs(lr->length)) {
@@ -229,29 +229,27 @@ recv_labelrequest(struct nbr *nbr, char *buf, u_int16_t len)
}
feclen = ntohs(ft->length);
-
buf += sizeof(struct fec_tlv);
len -= sizeof(struct fec_tlv);
- while (feclen >= FEC_ELM_MIN_LEN) {
- addr_type = validate_fec_elm(buf);
- if (addr_type < 0) {
+ bzero(&map, sizeof(map));
+ map.messageid = lr->msgid;
+
+ do {
+ if ((tlen = tlv_decode_fec_elm(buf, feclen, &addr_type,
+ &map.prefix, &map.prefixlen)) == -1 ||
+ addr_type == FEC_WILDCARD) {
session_shutdown(nbr, S_BAD_TLV_VAL, lr->msgid,
lr->type);
return (-1);
}
- map.prefix = decode_fec_elm(buf);
- map.prefixlen = decode_fec_len_elm(buf, addr_type);
- map.prefix &= prefixlen2mask(map.prefixlen);
- map.messageid = lr->msgid;
-
ldpe_imsg_compose_lde(IMSG_LABEL_REQUEST, nbr->peerid, 0, &map,
sizeof(map));
- buf += FEC_ELM_MIN_LEN + PREFIX_SIZE(map.prefixlen);
- feclen -= (FEC_ELM_MIN_LEN + PREFIX_SIZE(map.prefixlen));
- }
+ buf += tlen;
+ feclen -= tlen;
+ } while (feclen > 0);
nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
@@ -308,7 +306,12 @@ send_labelwithdraw(struct nbr *nbr)
int
recv_labelwithdraw(struct nbr *nbr, char *buf, u_int16_t len)
{
- struct ldp_msg *lw;
+ struct map map;
+ struct ldp_msg *lw;
+ struct fec_tlv *ft;
+ u_int32_t optlabel = NO_LABEL;
+ int feclen, tlen;
+ u_int8_t addr_type;
log_debug("recv_labelwithdraw: neighbor ID %s", inet_ntoa(nbr->id));
@@ -325,7 +328,59 @@ recv_labelwithdraw(struct nbr *nbr, char *buf, u_int16_t len)
buf += sizeof(struct ldp_msg);
len -= sizeof(struct ldp_msg);
- /* XXX XXX */
+ ft = (struct fec_tlv *)buf;
+
+ if (len < sizeof(*ft) ||
+ (len - TLV_HDR_LEN) < ntohs(ft->length)) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, lw->msgid, lw->type);
+ return (-1);
+ }
+
+ feclen = ntohs(ft->length);
+ buf += sizeof(struct fec_tlv);
+ len -= sizeof(struct fec_tlv);
+
+ /* release may include optional label */
+ if (len >= feclen) {
+ struct label_tlv *lt;
+
+ lt = (struct label_tlv *)(buf + feclen);
+ optlabel = tlv_decode_label(lt);
+ if (optlabel == NO_LABEL) {
+ session_shutdown(nbr, S_BAD_TLV_VAL, lw->msgid,
+ lw->type);
+ return (-1);
+ }
+ }
+
+ bzero(&map, sizeof(map));
+ map.messageid = lw->msgid;
+ if (optlabel != NO_LABEL) {
+ map.label = optlabel;
+ map.flags = F_MAP_OPTLABEL;
+ }
+ do {
+ if ((tlen = tlv_decode_fec_elm(buf, feclen, &addr_type,
+ &map.prefix, &map.prefixlen)) == -1) {
+ session_shutdown(nbr, S_BAD_TLV_VAL, lw->msgid,
+ lw->type);
+ return (-1);
+ }
+
+ if (addr_type == FEC_WILDCARD) {
+ map.prefix = 0;
+ map.prefixlen = 0;
+ map.flags |= F_MAP_WILDCARD;
+
+ } else
+ map.flags &= ~F_MAP_WILDCARD;
+
+ ldpe_imsg_compose_lde(IMSG_LABEL_WITHDRAW, nbr->peerid, 0, &map,
+ sizeof(map));
+
+ buf += tlen;
+ feclen -= tlen;
+ } while (feclen > 0);
nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
@@ -382,7 +437,12 @@ send_labelrelease(struct nbr *nbr)
int
recv_labelrelease(struct nbr *nbr, char *buf, u_int16_t len)
{
- struct ldp_msg *lr;
+ struct map map;
+ struct ldp_msg *lr;
+ struct fec_tlv *ft;
+ u_int32_t optlabel = NO_LABEL;
+ int feclen, tlen;
+ u_int8_t addr_type;
log_debug("recv_labelrelease: neighbor ID %s", inet_ntoa(nbr->id));
@@ -399,7 +459,59 @@ recv_labelrelease(struct nbr *nbr, char *buf, u_int16_t len)
buf += sizeof(struct ldp_msg);
len -= sizeof(struct ldp_msg);
- /* XXX XXX XXX */
+ ft = (struct fec_tlv *)buf;
+
+ if (len < sizeof(*ft) ||
+ (len - TLV_HDR_LEN) < ntohs(ft->length)) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, lr->msgid, lr->type);
+ return (-1);
+ }
+
+ feclen = ntohs(ft->length);
+ buf += sizeof(struct fec_tlv);
+ len -= sizeof(struct fec_tlv);
+
+ /* release may include optional label */
+ if (len >= feclen) {
+ struct label_tlv *lt;
+
+ lt = (struct label_tlv *)(buf + feclen);
+ optlabel = tlv_decode_label(lt);
+ if (optlabel == NO_LABEL) {
+ session_shutdown(nbr, S_BAD_TLV_VAL, lr->msgid,
+ lr->type);
+ return (-1);
+ }
+ }
+
+ bzero(&map, sizeof(map));
+ map.messageid = lr->msgid;
+ if (optlabel != NO_LABEL) {
+ map.label = optlabel;
+ map.flags = F_MAP_OPTLABEL;
+ }
+ do {
+ if ((tlen = tlv_decode_fec_elm(buf, feclen, &addr_type,
+ &map.prefix, &map.prefixlen)) == -1) {
+ session_shutdown(nbr, S_BAD_TLV_VAL, lr->msgid,
+ lr->type);
+ return (-1);
+ }
+
+ if (addr_type == FEC_WILDCARD) {
+ map.prefix = 0;
+ map.prefixlen = 0;
+ map.flags |= F_MAP_WILDCARD;
+
+ } else
+ map.flags &= ~F_MAP_WILDCARD;
+
+ ldpe_imsg_compose_lde(IMSG_LABEL_RELEASE, nbr->peerid, 0, &map,
+ sizeof(map));
+
+ buf += tlen;
+ feclen -= tlen;
+ } while (feclen > 0);
nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
@@ -510,52 +622,41 @@ tlv_decode_label(struct label_tlv *lt)
}
int
-validate_fec_elm(char *buf)
+tlv_decode_fec_elm(char *buf, u_int16_t len, u_int8_t *type, u_int32_t *prefix,
+ u_int8_t *prefixlen)
{
- u_int16_t *family;
- u_int8_t type;
-
- type = *buf;
+ u_int16_t family, off = 0;
- if (type != FEC_WILDCARD && type != FEC_PREFIX)
- return (-1);
+ *type = *buf;
+ off += sizeof(u_int8_t);
- buf += sizeof(u_int8_t);
- family = (u_int16_t *)buf;
+ if (*type == FEC_WILDCARD) {
+ if (len == 0)
+ return (off);
+ else
+ return (-1); /* XXX Malformed TLV Value */
+ }
- if (*family != htons(FEC_IPV4))
- return (-1);
+ if (*type != FEC_PREFIX)
+ return (-1); /* XXX "Unknown FEC" Notification */
- return (type);
-}
+ if (len < FEC_ELM_MIN_LEN)
+ return (-1); /* XXX Bad TLV Length */
-u_int32_t
-decode_fec_elm(char *buf)
-{
- struct fec_elm *fe = (struct fec_elm *)buf;
+ bcopy(buf + off, &family, sizeof(family));
+ off += sizeof(family);
- return (fe->addr);
-}
+ if (family != htons(FEC_IPV4))
+ return (-1); /* XXX "Unsupported Address Family" */
-int
-decode_fec_len_elm(char *buf, u_int8_t type)
-{
- u_int8_t len;
+ *prefixlen = buf[off];
+ off += sizeof(u_int8_t);
- /* Skip type and family */
- buf += sizeof(u_int8_t);
- buf += sizeof(u_int16_t);
+ if (len < off + PREFIX_SIZE(*prefixlen))
+ return (-1); /* XXX Bad TLV Length */
- len = *buf;
+ *prefix = 0;
+ bcopy(buf + off, prefix, PREFIX_SIZE(*prefixlen));
- switch (type) {
- case FEC_PREFIX:
- return (len);
- case FEC_WILDCARD:
- return (0);
- default:
- /* Should not happen */
- return (-1);
- }
- /* NOTREACHED */
+ return (off + PREFIX_SIZE(*prefixlen));
}