We were aborting the session upon receipt of MAC Address Withdrawal
messages. Now make the parser aware that optional TLVs are possible in
address messages.
---
 address.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 59 insertions(+), 14 deletions(-)

diff --git a/address.c b/address.c
index 9b65511..e891173 100644
--- a/address.c
+++ b/address.c
@@ -144,11 +144,24 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
 {
        struct ldp_msg          msg;
        uint16_t                msg_type;
-       struct address_list_tlv alt;
        enum imsg_type          type;
+       struct address_list_tlv alt;
+       uint16_t                alt_len;
+       uint16_t                alt_family;
        struct lde_addr         lde_addr;
 
        memcpy(&msg, buf, sizeof(msg));
+       msg_type = ntohs(msg.type);
+       switch (msg_type) {
+       case MSG_TYPE_ADDR:
+               type = IMSG_ADDRESS_ADD;
+               break;
+       case MSG_TYPE_ADDRWITHDRAW:
+               type = IMSG_ADDRESS_DEL;
+               break;
+       default:
+               fatalx("recv_address: unexpected msg type");
+       }
        buf += LDP_MSG_SIZE;
        len -= LDP_MSG_SIZE;
 
@@ -157,9 +170,10 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
                session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
                return (-1);
        }
-
        memcpy(&alt, buf, sizeof(alt));
-       if (ntohs(alt.length) != len - TLV_HDR_SIZE) {
+       alt_len = ntohs(alt.length);
+       alt_family = ntohs(alt.family);
+       if (alt_len > len - TLV_HDR_SIZE) {
                session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
                return (-1);
        }
@@ -167,7 +181,7 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
                send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
                return (-1);
        }
-       switch (ntohs(alt.family)) {
+       switch (alt_family) {
        case AF_IPV4:
                if (!nbr->v4_enabled)
                        /* just ignore the message */
@@ -182,19 +196,15 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
                send_notification(nbr->tcp, S_UNSUP_ADDR, msg.id, msg.type);
                return (-1);
        }
+       alt_len -= sizeof(alt.family);
        buf += sizeof(alt);
        len -= sizeof(alt);
 
-       msg_type = ntohs(msg.type);
-       if (msg_type == MSG_TYPE_ADDR)
-               type = IMSG_ADDRESS_ADD;
-       else
-               type = IMSG_ADDRESS_DEL;
-
-       while (len > 0) {
-               switch (ntohs(alt.family)) {
+       /* Process all received addresses */
+       while (alt_len > 0) {
+               switch (alt_family) {
                case AF_IPV4:
-                       if (len < sizeof(struct in_addr)) {
+                       if (alt_len < sizeof(struct in_addr)) {
                                session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
                                    msg.type);
                                return (-1);
@@ -206,9 +216,10 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
 
                        buf += sizeof(struct in_addr);
                        len -= sizeof(struct in_addr);
+                       alt_len -= sizeof(struct in_addr);
                        break;
                case AF_IPV6:
-                       if (len < sizeof(struct in6_addr)) {
+                       if (alt_len < sizeof(struct in6_addr)) {
                                session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
                                    msg.type);
                                return (-1);
@@ -220,6 +231,7 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
 
                        buf += sizeof(struct in6_addr);
                        len -= sizeof(struct in6_addr);
+                       alt_len -= sizeof(struct in6_addr);
                        break;
                default:
                        fatalx("recv_address: unknown af");
@@ -231,6 +243,39 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
                    sizeof(lde_addr));
        }
 
+       /* Optional Parameters */
+       while (len > 0) {
+               struct tlv      tlv;
+               uint16_t        tlv_type;
+               uint16_t        tlv_len;
+
+               if (len < sizeof(tlv)) {
+                       session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+                       return (-1);
+               }
+
+               memcpy(&tlv, buf, TLV_HDR_SIZE);
+               tlv_type = ntohs(tlv.type);
+               tlv_len = ntohs(tlv.length);
+               if (tlv_len + TLV_HDR_SIZE > len) {
+                       session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+                       return (-1);
+               }
+               buf += TLV_HDR_SIZE;
+               len -= TLV_HDR_SIZE;
+
+               switch (tlv_type) {
+               default:
+                       if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
+                               send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
+                                   msg.id, msg.type, tlv_type, tlv_len, buf);
+                       /* ignore unknown tlv */
+                       break;
+               }
+               buf += tlv_len;
+               len -= tlv_len;
+       }
+
        return (0);
 }
 
-- 
1.9.1

Reply via email to