File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / pimd / pim_tlv.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:11 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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>