diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2010-05-25 09:40:11 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2010-05-25 09:40:11 +0000 |
commit | 69524634b4bd806319c98cdbbba47d3e17499849 (patch) | |
tree | 3eb0df3c62882ff985b7ef6af171b1079406e5ea /usr.sbin/ldpd/labelmapping.c | |
parent | 83f8184091e94b05e8d2b12af39914f7a5e2b900 (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.c | 255 |
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)); } |