Annotation of embedaddon/quagga/pimd/pim_tlv.c, revision 1.1

1.1     ! misho       1: /*
        !             2:   PIM for Quagga
        !             3:   Copyright (C) 2008  Everton da Silva Marques
        !             4: 
        !             5:   This program is free software; you can redistribute it and/or modify
        !             6:   it under the terms of the GNU General Public License as published by
        !             7:   the Free Software Foundation; either version 2 of the License, or
        !             8:   (at your option) any later version.
        !             9: 
        !            10:   This program is distributed in the hope that it will be useful, but
        !            11:   WITHOUT ANY WARRANTY; without even the implied warranty of
        !            12:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            13:   General Public License for more details.
        !            14:   
        !            15:   You should have received a copy of the GNU General Public License
        !            16:   along with this program; see the file COPYING; if not, write to the
        !            17:   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
        !            18:   MA 02110-1301 USA
        !            19:   
        !            20:   $QuaggaId: $Format:%an, %ai, %h$ $
        !            21: */
        !            22: 
        !            23: #include <zebra.h>
        !            24: 
        !            25: #include "log.h"
        !            26: #include "prefix.h"
        !            27: 
        !            28: #include "pimd.h"
        !            29: #include "pim_int.h"
        !            30: #include "pim_tlv.h"
        !            31: #include "pim_str.h"
        !            32: #include "pim_msg.h"
        !            33: 
        !            34: uint8_t *pim_tlv_append_uint16(uint8_t *buf,
        !            35:                               const uint8_t *buf_pastend,
        !            36:                               uint16_t option_type,
        !            37:                               uint16_t option_value)
        !            38: {
        !            39:   uint16_t option_len = 2;
        !            40: 
        !            41:   if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
        !            42:     return NULL;
        !            43: 
        !            44:   *(uint16_t *) buf = htons(option_type);
        !            45:   buf += 2;
        !            46:   *(uint16_t *) buf = htons(option_len);
        !            47:   buf += 2;
        !            48:   *(uint16_t *) buf = htons(option_value);
        !            49:   buf += option_len;
        !            50: 
        !            51:   return buf;
        !            52: }
        !            53: 
        !            54: uint8_t *pim_tlv_append_2uint16(uint8_t *buf,
        !            55:                                const uint8_t *buf_pastend,
        !            56:                                uint16_t option_type,
        !            57:                                uint16_t option_value1,
        !            58:                                uint16_t option_value2)
        !            59: {
        !            60:   uint16_t option_len = 4;
        !            61: 
        !            62:   if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
        !            63:     return NULL;
        !            64: 
        !            65:   *(uint16_t *) buf = htons(option_type);
        !            66:   buf += 2;
        !            67:   *(uint16_t *) buf = htons(option_len);
        !            68:   buf += 2;
        !            69:   *(uint16_t *) buf = htons(option_value1);
        !            70:   buf += 2;
        !            71:   *(uint16_t *) buf = htons(option_value2);
        !            72:   buf += 2;
        !            73: 
        !            74:   return buf;
        !            75: }
        !            76: 
        !            77: uint8_t *pim_tlv_append_uint32(uint8_t *buf,
        !            78:                               const uint8_t *buf_pastend,
        !            79:                               uint16_t option_type,
        !            80:                               uint32_t option_value)
        !            81: {
        !            82:   uint16_t option_len = 4;
        !            83: 
        !            84:   if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
        !            85:     return NULL;
        !            86: 
        !            87:   *(uint16_t *) buf = htons(option_type);
        !            88:   buf += 2;
        !            89:   *(uint16_t *) buf = htons(option_len);
        !            90:   buf += 2;
        !            91:   pim_write_uint32(buf, option_value);
        !            92:   buf += option_len;
        !            93: 
        !            94:   return buf;
        !            95: }
        !            96: 
        !            97: #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
        !            98: 
        !            99: uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
        !           100:                                       const uint8_t *buf_pastend,
        !           101:                                       struct list *ifconnected)
        !           102: {
        !           103:   struct listnode *node;
        !           104:   uint16_t option_len = 0;
        !           105: 
        !           106:   uint8_t *curr;
        !           107: 
        !           108:   node = listhead(ifconnected);
        !           109: 
        !           110:   /* Empty address list ? */
        !           111:   if (!node) {
        !           112:     return buf;
        !           113:   }
        !           114: 
        !           115:   /* Skip first address (primary) */
        !           116:   node = listnextnode(node);
        !           117: 
        !           118:   /* Scan secondary address list */
        !           119:   curr = buf + 4; /* skip T and L */
        !           120:   for (; node; node = listnextnode(node)) {
        !           121:     struct connected *ifc = listgetdata(node);
        !           122:     struct prefix *p = ifc->address;
        !           123:     
        !           124:     if (p->family != AF_INET)
        !           125:       continue;
        !           126: 
        !           127:     if ((curr + ucast_ipv4_encoding_len) > buf_pastend)
        !           128:       return 0;
        !           129: 
        !           130:     /* Write encoded unicast IPv4 address */
        !           131:     *(uint8_t *) curr = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
        !           132:     ++curr;
        !           133:     *(uint8_t *) curr = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */
        !           134:     ++curr;
        !           135:     memcpy(curr, &p->u.prefix4, sizeof(struct in_addr));
        !           136:     curr += sizeof(struct in_addr);
        !           137: 
        !           138:     option_len += ucast_ipv4_encoding_len; 
        !           139:   }
        !           140: 
        !           141:   if (PIM_DEBUG_PIM_TRACE) {
        !           142:     zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu",
        !           143:               __PRETTY_FUNCTION__,
        !           144:               option_len / ucast_ipv4_encoding_len);
        !           145:   }
        !           146: 
        !           147:   if (option_len < 1) {
        !           148:     /* Empty secondary unicast IPv4 address list */
        !           149:     return buf;
        !           150:   }
        !           151: 
        !           152:   /*
        !           153:    * Write T and L
        !           154:    */
        !           155:   *(uint16_t *) buf       = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST);
        !           156:   *(uint16_t *) (buf + 2) = htons(option_len);
        !           157: 
        !           158:   return curr;
        !           159: }
        !           160: 
        !           161: static int check_tlv_length(const char *label, const char *tlv_name,
        !           162:                            const char *ifname, struct in_addr src_addr,
        !           163:                            int correct_len, int option_len)
        !           164: {
        !           165:   if (option_len != correct_len) {
        !           166:     char src_str[100];
        !           167:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           168:     zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
        !           169:              label, tlv_name,
        !           170:              option_len, correct_len,
        !           171:              src_str, ifname);
        !           172:     return -1;
        !           173:   }
        !           174: 
        !           175:   return 0;
        !           176: }
        !           177: 
        !           178: static void check_tlv_redefinition_uint16(const char *label, const char *tlv_name,
        !           179:                                          const char *ifname, struct in_addr src_addr,
        !           180:                                          pim_hello_options options,
        !           181:                                          pim_hello_options opt_mask,
        !           182:                                          uint16_t new, uint16_t old)
        !           183: {
        !           184:   if (PIM_OPTION_IS_SET(options, opt_mask)) {
        !           185:     char src_str[100];
        !           186:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           187:     zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
        !           188:              label, tlv_name,
        !           189:              new, old,
        !           190:              src_str, ifname);
        !           191:   }
        !           192: }
        !           193: 
        !           194: static void check_tlv_redefinition_uint32(const char *label, const char *tlv_name,
        !           195:                                          const char *ifname, struct in_addr src_addr,
        !           196:                                          pim_hello_options options,
        !           197:                                          pim_hello_options opt_mask,
        !           198:                                          uint32_t new, uint32_t old)
        !           199: {
        !           200:   if (PIM_OPTION_IS_SET(options, opt_mask)) {
        !           201:     char src_str[100];
        !           202:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           203:     zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
        !           204:              label, tlv_name,
        !           205:              new, old,
        !           206:              src_str, ifname);
        !           207:   }
        !           208: }
        !           209: 
        !           210: static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv_name,
        !           211:                                              const char *ifname, struct in_addr src_addr,
        !           212:                                              pim_hello_options options,
        !           213:                                              pim_hello_options opt_mask,
        !           214:                                              uint32_t new, uint32_t old)
        !           215: {
        !           216:   if (PIM_OPTION_IS_SET(options, opt_mask)) {
        !           217:     char src_str[100];
        !           218:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           219:     zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
        !           220:              label, tlv_name,
        !           221:              new, old,
        !           222:              src_str, ifname);
        !           223:   }
        !           224: }
        !           225: 
        !           226: int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr,
        !           227:                           pim_hello_options *hello_options,
        !           228:                           uint16_t *hello_option_holdtime,
        !           229:                           uint16_t option_len,
        !           230:                           const uint8_t *tlv_curr) 
        !           231: {
        !           232:   const char *label = "holdtime";
        !           233: 
        !           234:   if (check_tlv_length(__PRETTY_FUNCTION__, label,
        !           235:                       ifname, src_addr,
        !           236:                       sizeof(uint16_t), option_len)) {
        !           237:     return -1;
        !           238:   }
        !           239:   
        !           240:   check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label,
        !           241:                                ifname, src_addr,
        !           242:                                *hello_options, PIM_OPTION_MASK_HOLDTIME,
        !           243:                                PIM_TLV_GET_HOLDTIME(tlv_curr),
        !           244:                                *hello_option_holdtime);
        !           245:   
        !           246:   PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME);
        !           247:   
        !           248:   *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr);
        !           249:   
        !           250:   return 0;
        !           251: }
        !           252: 
        !           253: int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr,
        !           254:                                  pim_hello_options *hello_options,
        !           255:                                  uint16_t *hello_option_propagation_delay,
        !           256:                                  uint16_t *hello_option_override_interval,
        !           257:                                  uint16_t option_len,
        !           258:                                  const uint8_t *tlv_curr) 
        !           259: {
        !           260:   if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay",
        !           261:                       ifname, src_addr,
        !           262:                       sizeof(uint32_t), option_len)) {
        !           263:     return -1;
        !           264:   }
        !           265:   
        !           266:   check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay",
        !           267:                                ifname, src_addr,
        !           268:                                *hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY,
        !           269:                                PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr),
        !           270:                                *hello_option_propagation_delay);
        !           271:   
        !           272:   PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
        !           273:   
        !           274:   *hello_option_propagation_delay = PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr);
        !           275:   if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) {
        !           276:     PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
        !           277:   }
        !           278:   else {
        !           279:     PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
        !           280:   }
        !           281:   ++tlv_curr;
        !           282:   ++tlv_curr;
        !           283:   *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr);
        !           284:   
        !           285:   return 0;
        !           286: }
        !           287: 
        !           288: int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr,
        !           289:                              pim_hello_options *hello_options,
        !           290:                              uint32_t *hello_option_dr_priority,
        !           291:                              uint16_t option_len,
        !           292:                              const uint8_t *tlv_curr) 
        !           293: {
        !           294:   const char *label = "dr_priority";
        !           295: 
        !           296:   if (check_tlv_length(__PRETTY_FUNCTION__, label,
        !           297:                       ifname, src_addr,
        !           298:                       sizeof(uint32_t), option_len)) {
        !           299:     return -1;
        !           300:   }
        !           301:   
        !           302:   check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label,
        !           303:                                ifname, src_addr,
        !           304:                                *hello_options, PIM_OPTION_MASK_DR_PRIORITY,
        !           305:                                PIM_TLV_GET_DR_PRIORITY(tlv_curr),
        !           306:                                *hello_option_dr_priority);
        !           307:   
        !           308:   PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY);
        !           309:   
        !           310:   *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr);
        !           311: 
        !           312:   return 0;
        !           313: }
        !           314: 
        !           315: int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr,
        !           316:                                pim_hello_options *hello_options,
        !           317:                                uint32_t *hello_option_generation_id,
        !           318:                                uint16_t option_len,
        !           319:                                const uint8_t *tlv_curr) 
        !           320: {
        !           321:   const char *label = "generation_id";
        !           322: 
        !           323:   if (check_tlv_length(__PRETTY_FUNCTION__, label,
        !           324:                       ifname, src_addr,
        !           325:                       sizeof(uint32_t), option_len)) {
        !           326:     return -1;
        !           327:   }
        !           328:   
        !           329:   check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label,
        !           330:                                    ifname, src_addr,
        !           331:                                    *hello_options, PIM_OPTION_MASK_GENERATION_ID,
        !           332:                                    PIM_TLV_GET_GENERATION_ID(tlv_curr),
        !           333:                                    *hello_option_generation_id);
        !           334:   
        !           335:   PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID);
        !           336:   
        !           337:   *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr);
        !           338:   
        !           339:   return 0;
        !           340: }
        !           341: 
        !           342: int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr,
        !           343:                         struct prefix *p,
        !           344:                         const uint8_t *buf,
        !           345:                         int buf_size)
        !           346: {
        !           347:   const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */
        !           348:   const uint8_t *addr;
        !           349:   const uint8_t *pastend;
        !           350:   int family;
        !           351:   int type;
        !           352: 
        !           353:   if (buf_size < ucast_encoding_min_len) {
        !           354:     char src_str[100];
        !           355:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           356:     zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d from %s on %s",
        !           357:              __PRETTY_FUNCTION__,
        !           358:              buf_size, ucast_encoding_min_len,
        !           359:              src_str, ifname);
        !           360:     return -1;
        !           361:   }
        !           362: 
        !           363:   addr = buf;
        !           364:   pastend = buf + buf_size;
        !           365: 
        !           366:   family = *addr++;
        !           367:   type = *addr++;
        !           368: 
        !           369:   switch (family) {
        !           370:   case PIM_MSG_ADDRESS_FAMILY_IPV4:
        !           371:     if (type) {
        !           372:       char src_str[100];
        !           373:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           374:       zlog_warn("%s: unknown unicast address encoding type=%d from %s on %s",
        !           375:                __PRETTY_FUNCTION__,
        !           376:                type, src_str, ifname);
        !           377:       return -2;
        !           378:     }
        !           379: 
        !           380:     if ((addr + sizeof(struct in_addr)) > pastend) {
        !           381:       char src_str[100];
        !           382:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           383:       zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu from %s on %s",
        !           384:                __PRETTY_FUNCTION__,
        !           385:                pastend - addr, sizeof(struct in_addr),
        !           386:                src_str, ifname);
        !           387:       return -3;
        !           388:     }
        !           389: 
        !           390:     p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
        !           391:     memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
        !           392: 
        !           393:     addr += sizeof(struct in_addr);
        !           394: 
        !           395:     break;
        !           396:   default:
        !           397:     {
        !           398:       char src_str[100];
        !           399:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           400:       zlog_warn("%s: unknown unicast address encoding family=%d from %s on %s",
        !           401:                __PRETTY_FUNCTION__,
        !           402:                family, src_str, ifname);
        !           403:       return -4;
        !           404:     }
        !           405:   }
        !           406: 
        !           407:   return addr - buf;
        !           408: }
        !           409: 
        !           410: int pim_parse_addr_group(const char *ifname, struct in_addr src_addr,
        !           411:                         struct prefix *p,
        !           412:                         const uint8_t *buf,
        !           413:                         int buf_size)
        !           414: {
        !           415:   const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
        !           416:   const uint8_t *addr;
        !           417:   const uint8_t *pastend;
        !           418:   int family;
        !           419:   int type;
        !           420:   int mask_len;
        !           421: 
        !           422:   if (buf_size < grp_encoding_min_len) {
        !           423:     char src_str[100];
        !           424:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           425:     zlog_warn("%s: group address encoding overflow: left=%d needed=%d from %s on %s",
        !           426:              __PRETTY_FUNCTION__,
        !           427:              buf_size, grp_encoding_min_len,
        !           428:              src_str, ifname);
        !           429:     return -1;
        !           430:   }
        !           431: 
        !           432:   addr = buf;
        !           433:   pastend = buf + buf_size;
        !           434: 
        !           435:   family = *addr++;
        !           436:   type = *addr++;
        !           437:   //++addr;
        !           438:   ++addr; /* skip b_reserved_z fields */
        !           439:   mask_len = *addr++;
        !           440: 
        !           441:   switch (family) {
        !           442:   case PIM_MSG_ADDRESS_FAMILY_IPV4:
        !           443:     if (type) {
        !           444:       char src_str[100];
        !           445:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           446:       zlog_warn("%s: unknown group address encoding type=%d from %s on %s",
        !           447:                __PRETTY_FUNCTION__,
        !           448:                type, src_str, ifname);
        !           449:       return -2;
        !           450:     }
        !           451: 
        !           452:     if ((addr + sizeof(struct in_addr)) > pastend) {
        !           453:       char src_str[100];
        !           454:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           455:       zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from %s on %s",
        !           456:                __PRETTY_FUNCTION__,
        !           457:                pastend - addr, sizeof(struct in_addr),
        !           458:                src_str, ifname);
        !           459:       return -3;
        !           460:     }
        !           461: 
        !           462:     p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
        !           463:     memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
        !           464:     p->prefixlen = mask_len;
        !           465: 
        !           466:     addr += sizeof(struct in_addr);
        !           467: 
        !           468:     break;
        !           469:   default:
        !           470:     {
        !           471:       char src_str[100];
        !           472:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           473:       zlog_warn("%s: unknown group address encoding family=%d from %s on %s",
        !           474:                __PRETTY_FUNCTION__,
        !           475:                family, src_str, ifname);
        !           476:       return -4;
        !           477:     }
        !           478:   }
        !           479: 
        !           480:   return addr - buf;
        !           481: }
        !           482: 
        !           483: int pim_parse_addr_source(const char *ifname,
        !           484:                          struct in_addr src_addr,
        !           485:                          struct prefix *p,
        !           486:                          uint8_t *flags,
        !           487:                          const uint8_t *buf,
        !           488:                          int buf_size)
        !           489: {
        !           490:   const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
        !           491:   const uint8_t *addr;
        !           492:   const uint8_t *pastend;
        !           493:   int family;
        !           494:   int type;
        !           495:   int mask_len;
        !           496: 
        !           497:   if (buf_size < src_encoding_min_len) {
        !           498:     char src_str[100];
        !           499:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           500:     zlog_warn("%s: source address encoding overflow: left=%d needed=%d from %s on %s",
        !           501:              __PRETTY_FUNCTION__,
        !           502:              buf_size, src_encoding_min_len,
        !           503:              src_str, ifname);
        !           504:     return -1;
        !           505:   }
        !           506: 
        !           507:   addr = buf;
        !           508:   pastend = buf + buf_size;
        !           509: 
        !           510:   family = *addr++;
        !           511:   type = *addr++;
        !           512:   *flags = *addr++;
        !           513:   mask_len = *addr++;
        !           514: 
        !           515:   switch (family) {
        !           516:   case PIM_MSG_ADDRESS_FAMILY_IPV4:
        !           517:     if (type) {
        !           518:       char src_str[100];
        !           519:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           520:       zlog_warn("%s: unknown source address encoding type=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x",
        !           521:                __PRETTY_FUNCTION__,
        !           522:                type, src_str, ifname,
        !           523:                buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
        !           524:       return -2;
        !           525:     }
        !           526: 
        !           527:     if ((addr + sizeof(struct in_addr)) > pastend) {
        !           528:       char src_str[100];
        !           529:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           530:       zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu from %s on %s",
        !           531:                __PRETTY_FUNCTION__,
        !           532:                pastend - addr, sizeof(struct in_addr),
        !           533:                src_str, ifname);
        !           534:       return -3;
        !           535:     }
        !           536: 
        !           537:     p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
        !           538:     memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
        !           539:     p->prefixlen = mask_len;
        !           540: 
        !           541:     /* 
        !           542:        RFC 4601: 4.9.1  Encoded Source and Group Address Formats
        !           543: 
        !           544:        Encoded-Source Address
        !           545: 
        !           546:        The mask length MUST be equal to the mask length in bits for
        !           547:        the given Address Family and Encoding Type (32 for IPv4 native
        !           548:        and 128 for IPv6 native).  A router SHOULD ignore any messages
        !           549:        received with any other mask length.
        !           550:     */
        !           551:     if (p->prefixlen != 32) {
        !           552:       char src_str[100];
        !           553:       pim_inet4_dump("<src?>", p->u.prefix4, src_str, sizeof(src_str));
        !           554:       zlog_warn("%s: IPv4 bad source address mask: %s/%d",
        !           555:                __PRETTY_FUNCTION__, src_str, p->prefixlen);
        !           556:       return -4;
        !           557:     }
        !           558: 
        !           559:     addr += sizeof(struct in_addr);
        !           560: 
        !           561:     break;
        !           562:   default:
        !           563:     {
        !           564:       char src_str[100];
        !           565:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           566:       zlog_warn("%s: unknown source address encoding family=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x",
        !           567:                __PRETTY_FUNCTION__,
        !           568:                family, src_str, ifname,
        !           569:                buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
        !           570:       return -5;
        !           571:     }
        !           572:   }
        !           573: 
        !           574:   return addr - buf;
        !           575: }
        !           576: 
        !           577: #define FREE_ADDR_LIST(hello_option_addr_list) \
        !           578: { \
        !           579:   if (hello_option_addr_list) { \
        !           580:     list_delete(hello_option_addr_list); \
        !           581:     hello_option_addr_list = 0; \
        !           582:   } \
        !           583: }
        !           584: 
        !           585: int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
        !           586:                            pim_hello_options *hello_options,
        !           587:                            struct list **hello_option_addr_list,
        !           588:                            uint16_t option_len,
        !           589:                            const uint8_t *tlv_curr) 
        !           590: {
        !           591:   const uint8_t *addr;
        !           592:   const uint8_t *pastend;
        !           593: 
        !           594:   zassert(hello_option_addr_list);
        !           595: 
        !           596:   /*
        !           597:     Scan addr list
        !           598:    */
        !           599:   addr = tlv_curr;
        !           600:   pastend = tlv_curr + option_len;
        !           601:   while (addr < pastend) {
        !           602:     struct prefix tmp;
        !           603:     int addr_offset;
        !           604: 
        !           605:     /*
        !           606:       Parse ucast addr
        !           607:      */
        !           608:     addr_offset = pim_parse_addr_ucast(ifname, src_addr, &tmp,
        !           609:                                       addr, pastend - addr);
        !           610:     if (addr_offset < 1) {
        !           611:       char src_str[100];
        !           612:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           613:       zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
        !           614:                __PRETTY_FUNCTION__,
        !           615:                src_str, ifname);
        !           616:       FREE_ADDR_LIST(*hello_option_addr_list);
        !           617:       return -1;
        !           618:     }
        !           619:     addr += addr_offset;
        !           620: 
        !           621:     /*
        !           622:       Debug
        !           623:      */
        !           624:     if (PIM_DEBUG_PIM_TRACE) {
        !           625:       switch (tmp.family) {
        !           626:       case AF_INET:
        !           627:        {
        !           628:          char addr_str[100];
        !           629:          char src_str[100];
        !           630:          pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str));
        !           631:          pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           632:          zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
        !           633:                     __PRETTY_FUNCTION__,
        !           634:                     *hello_option_addr_list ?
        !           635:                     ((int) listcount(*hello_option_addr_list)) : -1,
        !           636:                     addr_str, src_str, ifname);
        !           637:        }
        !           638:        break;
        !           639:       default:
        !           640:        {
        !           641:          char src_str[100];
        !           642:          pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           643:          zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
        !           644:                     __PRETTY_FUNCTION__,
        !           645:                     *hello_option_addr_list ?
        !           646:                     ((int) listcount(*hello_option_addr_list)) : -1,
        !           647:                     src_str, ifname);
        !           648:        }
        !           649:       }
        !           650:     }
        !           651: 
        !           652:     /*
        !           653:       Exclude neighbor's primary address if incorrectly included in
        !           654:       the secondary address list
        !           655:      */
        !           656:     if (tmp.family == AF_INET) {
        !           657:       if (tmp.u.prefix4.s_addr == src_addr.s_addr) {
        !           658:          char src_str[100];
        !           659:          pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           660:          zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
        !           661:                    __PRETTY_FUNCTION__,
        !           662:                    src_str, ifname);
        !           663:          continue;
        !           664:       }
        !           665:     }
        !           666: 
        !           667:     /*
        !           668:       Allocate list if needed
        !           669:      */
        !           670:     if (!*hello_option_addr_list) {
        !           671:       *hello_option_addr_list = list_new();
        !           672:       if (!*hello_option_addr_list) {
        !           673:        zlog_err("%s %s: failure: hello_option_addr_list=list_new()",
        !           674:                 __FILE__, __PRETTY_FUNCTION__);
        !           675:        return -2;
        !           676:       }
        !           677:       (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free;
        !           678:     }
        !           679: 
        !           680:     /*
        !           681:       Attach addr to list
        !           682:      */
        !           683:     {
        !           684:       struct prefix *p;
        !           685:       p = prefix_new();
        !           686:       if (!p) {
        !           687:        zlog_err("%s %s: failure: prefix_new()",
        !           688:                 __FILE__, __PRETTY_FUNCTION__);
        !           689:        FREE_ADDR_LIST(*hello_option_addr_list);
        !           690:        return -3;
        !           691:       }
        !           692:       p->family = tmp.family;
        !           693:       p->u.prefix4 = tmp.u.prefix4;
        !           694:       listnode_add(*hello_option_addr_list, p);
        !           695:     }
        !           696: 
        !           697:   } /* while (addr < pastend) */
        !           698:   
        !           699:   /*
        !           700:     Mark hello option
        !           701:    */
        !           702:   PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST);
        !           703:   
        !           704:   return 0;
        !           705: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>