diff options
Diffstat (limited to 'pimd/pim_tlv.c')
| -rw-r--r-- | pimd/pim_tlv.c | 1227 | 
1 files changed, 607 insertions, 620 deletions
diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index 550fdde8eb..6d7adf2422 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -29,67 +29,61 @@  #include "pim_str.h"  #include "pim_msg.h" -uint8_t *pim_tlv_append_uint16(uint8_t *buf, -			       const uint8_t *buf_pastend, -			       uint16_t option_type, -			       uint16_t option_value) +uint8_t *pim_tlv_append_uint16(uint8_t *buf, const uint8_t *buf_pastend, +			       uint16_t option_type, uint16_t option_value)  { -  uint16_t option_len = 2; +	uint16_t option_len = 2; -  if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) -    return NULL; +	if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) +		return NULL; -  *(uint16_t *) buf = htons(option_type); -  buf += 2; -  *(uint16_t *) buf = htons(option_len); -  buf += 2; -  *(uint16_t *) buf = htons(option_value); -  buf += option_len; +	*(uint16_t *)buf = htons(option_type); +	buf += 2; +	*(uint16_t *)buf = htons(option_len); +	buf += 2; +	*(uint16_t *)buf = htons(option_value); +	buf += option_len; -  return buf; +	return buf;  } -uint8_t *pim_tlv_append_2uint16(uint8_t *buf, -				const uint8_t *buf_pastend, -				uint16_t option_type, -				uint16_t option_value1, +uint8_t *pim_tlv_append_2uint16(uint8_t *buf, const uint8_t *buf_pastend, +				uint16_t option_type, uint16_t option_value1,  				uint16_t option_value2)  { -  uint16_t option_len = 4; +	uint16_t option_len = 4; -  if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) -    return NULL; +	if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) +		return NULL; -  *(uint16_t *) buf = htons(option_type); -  buf += 2; -  *(uint16_t *) buf = htons(option_len); -  buf += 2; -  *(uint16_t *) buf = htons(option_value1); -  buf += 2; -  *(uint16_t *) buf = htons(option_value2); -  buf += 2; +	*(uint16_t *)buf = htons(option_type); +	buf += 2; +	*(uint16_t *)buf = htons(option_len); +	buf += 2; +	*(uint16_t *)buf = htons(option_value1); +	buf += 2; +	*(uint16_t *)buf = htons(option_value2); +	buf += 2; -  return buf; +	return buf;  } -uint8_t *pim_tlv_append_uint32(uint8_t *buf, -			       const uint8_t *buf_pastend, -			       uint16_t option_type, -			       uint32_t option_value) +uint8_t *pim_tlv_append_uint32(uint8_t *buf, const uint8_t *buf_pastend, +			       uint16_t option_type, uint32_t option_value)  { -  uint16_t option_len = 4; +	uint16_t option_len = 4; -  if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) -    return NULL; +	if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) +		return NULL; -  *(uint16_t *) buf = htons(option_type); -  buf += 2; -  *(uint16_t *) buf = htons(option_len); -  buf += 2; -  pim_write_uint32(buf, option_value); -  buf += option_len; +	*(uint16_t *)buf = htons(option_type); +	buf += 2; +	*(uint16_t *)buf = htons(option_len); +	buf += 2; +	pim_write_uint32(buf, option_value); +	buf += option_len; -  return buf; +	return buf;  }  #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr)) @@ -108,7 +102,8 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf,   *       The PIM address family of the 'Unicast Address' field of this   *       address.   * - *       Values 0-127 are as assigned by the IANA for Internet Address   *       Families in [7].  Values 128-250 are reserved to be assigned by + *       Values 0-127 are as assigned by the IANA for Internet Address   * + * Families in [7].  Values 128-250 are reserved to be assigned by   *       the IANA for PIM-specific Address Families.  Values 251 though   *       255 are designated for private use.  As there is no assignment   *       authority for this space, collisions should be expected. @@ -122,31 +117,33 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf,   *       The unicast address as represented by the given Address Family   *       and Encoding Type.   */ -int -pim_encode_addr_ucast (uint8_t *buf, struct prefix *p) +int pim_encode_addr_ucast(uint8_t *buf, struct prefix *p)  { -  switch (p->family) -    { -    case AF_INET: -      *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ -      ++buf; -      *(uint8_t *)buf = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */ -      ++buf; -      memcpy (buf, &p->u.prefix4, sizeof (struct in_addr)); -      return ucast_ipv4_encoding_len; -      break; -    case AF_INET6: -      *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV6; -      ++buf; -      *(uint8_t *)buf = 0; -      ++buf; -      memcpy (buf, &p->u.prefix6, sizeof (struct in6_addr)); -      return ucast_ipv6_encoding_len; -      break; -    default: -      return 0; -      break; -    } +	switch (p->family) { +	case AF_INET: +		*(uint8_t *)buf = +			PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != +							PIM_MSG_ADDRESS_FAMILY_IPV4 +							*/ +		++buf; +		*(uint8_t *)buf = 0; /* ucast IPv4 native encoding type (RFC +					4601: 4.9.1) */ +		++buf; +		memcpy(buf, &p->u.prefix4, sizeof(struct in_addr)); +		return ucast_ipv4_encoding_len; +		break; +	case AF_INET6: +		*(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV6; +		++buf; +		*(uint8_t *)buf = 0; +		++buf; +		memcpy(buf, &p->u.prefix6, sizeof(struct in6_addr)); +		return ucast_ipv6_encoding_len; +		break; +	default: +		return 0; +		break; +	}  }  #define group_ipv4_encoding_len (4 + sizeof (struct in_addr)) @@ -194,614 +191,604 @@ pim_encode_addr_ucast (uint8_t *buf, struct prefix *p)   *  Group multicast Address   *       Contains the group address.   */ -int -pim_encode_addr_group (uint8_t *buf, afi_t afi, int bidir, int scope, struct in_addr group) +int pim_encode_addr_group(uint8_t *buf, afi_t afi, int bidir, int scope, +			  struct in_addr group)  { -  uint8_t flags = 0; - -  flags |= bidir << 8; -  flags |= scope; - -  switch (afi) -    { -    case AFI_IP: -      *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4; -      ++buf; -      *(uint8_t *)buf = 0; -      ++buf; -      *(uint8_t *)buf = flags; -      ++buf; -      *(uint8_t *)buf = 32; -      ++buf; -      memcpy (buf, &group, sizeof (struct in_addr)); -      return group_ipv4_encoding_len; -      break; -    default: -      return 0; -      break; -    } +	uint8_t flags = 0; + +	flags |= bidir << 8; +	flags |= scope; + +	switch (afi) { +	case AFI_IP: +		*(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4; +		++buf; +		*(uint8_t *)buf = 0; +		++buf; +		*(uint8_t *)buf = flags; +		++buf; +		*(uint8_t *)buf = 32; +		++buf; +		memcpy(buf, &group, sizeof(struct in_addr)); +		return group_ipv4_encoding_len; +		break; +	default: +		return 0; +		break; +	}  } -uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, -				       const uint8_t *buf_pastend, -				       struct list *ifconnected, -                                       int family) +uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, +				       struct list *ifconnected, int family)  { -  struct listnode *node; -  uint16_t option_len = 0; -  uint8_t *curr; -  size_t uel; - -  node = listhead(ifconnected); - -  /* Empty address list ? */ -  if (!node) { -    return buf; -  } - -  if (family == AF_INET) -    uel = ucast_ipv4_encoding_len; -  else -    uel = ucast_ipv6_encoding_len; - -  /* Scan secondary address list */ -  curr = buf + 4; /* skip T and L */ -  for (; node; node = listnextnode(node)) { -    struct connected *ifc = listgetdata(node); -    struct prefix *p = ifc->address; -    int l_encode; - -    if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) -      continue; - -    if ((curr + uel) > buf_pastend) -          return 0; - -    if (p->family != family) -      continue; - -    l_encode = pim_encode_addr_ucast (curr, p); -    curr += l_encode; -    option_len += l_encode; -  } - -  if (PIM_DEBUG_PIM_TRACE_DETAIL) { -    zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu", -	       __PRETTY_FUNCTION__, -	       option_len / uel); -  } - -  if (option_len < 1) { -    /* Empty secondary unicast IPv4 address list */ -    return buf; -  } - -  /* -   * Write T and L -   */ -  *(uint16_t *) buf       = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST); -  *(uint16_t *) (buf + 2) = htons(option_len); - -  return curr; +	struct listnode *node; +	uint16_t option_len = 0; +	uint8_t *curr; +	size_t uel; + +	node = listhead(ifconnected); + +	/* Empty address list ? */ +	if (!node) { +		return buf; +	} + +	if (family == AF_INET) +		uel = ucast_ipv4_encoding_len; +	else +		uel = ucast_ipv6_encoding_len; + +	/* Scan secondary address list */ +	curr = buf + 4; /* skip T and L */ +	for (; node; node = listnextnode(node)) { +		struct connected *ifc = listgetdata(node); +		struct prefix *p = ifc->address; +		int l_encode; + +		if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) +			continue; + +		if ((curr + uel) > buf_pastend) +			return 0; + +		if (p->family != family) +			continue; + +		l_encode = pim_encode_addr_ucast(curr, p); +		curr += l_encode; +		option_len += l_encode; +	} + +	if (PIM_DEBUG_PIM_TRACE_DETAIL) { +		zlog_debug( +			"%s: number of encoded secondary unicast IPv4 addresses: %zu", +			__PRETTY_FUNCTION__, option_len / uel); +	} + +	if (option_len < 1) { +		/* Empty secondary unicast IPv4 address list */ +		return buf; +	} + +	/* +	 * Write T and L +	 */ +	*(uint16_t *)buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST); +	*(uint16_t *)(buf + 2) = htons(option_len); + +	return curr;  }  static int check_tlv_length(const char *label, const char *tlv_name,  			    const char *ifname, struct in_addr src_addr,  			    int correct_len, int option_len)  { -  if (option_len != correct_len) { -    char src_str[INET_ADDRSTRLEN]; -    pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); -    zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s", -	      label, tlv_name, -	      option_len, correct_len, -	      src_str, ifname); -    return -1; -  } - -  return 0; +	if (option_len != correct_len) { +		char src_str[INET_ADDRSTRLEN]; +		pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); +		zlog_warn( +			"%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s", +			label, tlv_name, option_len, correct_len, src_str, +			ifname); +		return -1; +	} + +	return 0;  } -static void check_tlv_redefinition_uint16(const char *label, const char *tlv_name, -					  const char *ifname, struct in_addr src_addr, -					  pim_hello_options options, -					  pim_hello_options opt_mask, -					  uint16_t new, uint16_t old) +static void check_tlv_redefinition_uint16( +	const char *label, const char *tlv_name, const char *ifname, +	struct in_addr src_addr, pim_hello_options options, +	pim_hello_options opt_mask, uint16_t new, uint16_t old)  { -  if (PIM_OPTION_IS_SET(options, opt_mask)) { -    char src_str[INET_ADDRSTRLEN]; -    pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); -    zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", -	      label, tlv_name, -	      new, old, -	      src_str, ifname); -  } +	if (PIM_OPTION_IS_SET(options, opt_mask)) { +		char src_str[INET_ADDRSTRLEN]; +		pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); +		zlog_warn( +			"%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", +			label, tlv_name, new, old, src_str, ifname); +	}  } -static void check_tlv_redefinition_uint32(const char *label, const char *tlv_name, -					  const char *ifname, struct in_addr src_addr, -					  pim_hello_options options, -					  pim_hello_options opt_mask, -					  uint32_t new, uint32_t old) +static void check_tlv_redefinition_uint32( +	const char *label, const char *tlv_name, const char *ifname, +	struct in_addr src_addr, pim_hello_options options, +	pim_hello_options opt_mask, uint32_t new, uint32_t old)  { -  if (PIM_OPTION_IS_SET(options, opt_mask)) { -    char src_str[INET_ADDRSTRLEN]; -    pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); -    zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", -	      label, tlv_name, -	      new, old, -	      src_str, ifname); -  } +	if (PIM_OPTION_IS_SET(options, opt_mask)) { +		char src_str[INET_ADDRSTRLEN]; +		pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); +		zlog_warn( +			"%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", +			label, tlv_name, new, old, src_str, ifname); +	}  } -static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv_name, -					      const char *ifname, struct in_addr src_addr, -					      pim_hello_options options, -					      pim_hello_options opt_mask, -					      uint32_t new, uint32_t old) +static void check_tlv_redefinition_uint32_hex( +	const char *label, const char *tlv_name, const char *ifname, +	struct in_addr src_addr, pim_hello_options options, +	pim_hello_options opt_mask, uint32_t new, uint32_t old)  { -  if (PIM_OPTION_IS_SET(options, opt_mask)) { -    char src_str[INET_ADDRSTRLEN]; -    pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); -    zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s", -	      label, tlv_name, -	      new, old, -	      src_str, ifname); -  } +	if (PIM_OPTION_IS_SET(options, opt_mask)) { +		char src_str[INET_ADDRSTRLEN]; +		pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); +		zlog_warn( +			"%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s", +			label, tlv_name, new, old, src_str, ifname); +	}  }  int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr,  			   pim_hello_options *hello_options, -			   uint16_t *hello_option_holdtime, -			   uint16_t option_len, -			   const uint8_t *tlv_curr)  +			   uint16_t *hello_option_holdtime, uint16_t option_len, +			   const uint8_t *tlv_curr)  { -  const char *label = "holdtime"; - -  if (check_tlv_length(__PRETTY_FUNCTION__, label, -		       ifname, src_addr, -		       sizeof(uint16_t), option_len)) { -    return -1; -  } -   -  check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label, -				ifname, src_addr, -				*hello_options, PIM_OPTION_MASK_HOLDTIME, -				PIM_TLV_GET_HOLDTIME(tlv_curr), -				*hello_option_holdtime); -   -  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME); -   -  *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr); -   -  return 0; +	const char *label = "holdtime"; + +	if (check_tlv_length(__PRETTY_FUNCTION__, label, ifname, src_addr, +			     sizeof(uint16_t), option_len)) { +		return -1; +	} + +	check_tlv_redefinition_uint16( +		__PRETTY_FUNCTION__, label, ifname, src_addr, *hello_options, +		PIM_OPTION_MASK_HOLDTIME, PIM_TLV_GET_HOLDTIME(tlv_curr), +		*hello_option_holdtime); + +	PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME); + +	*hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr); + +	return 0;  }  int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr,  				  pim_hello_options *hello_options,  				  uint16_t *hello_option_propagation_delay,  				  uint16_t *hello_option_override_interval, -				  uint16_t option_len, -				  const uint8_t *tlv_curr)  +				  uint16_t option_len, const uint8_t *tlv_curr)  { -  if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay", -		       ifname, src_addr, -		       sizeof(uint32_t), option_len)) { -    return -1; -  } -   -  check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay", -				ifname, src_addr, -				*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY, -				PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr), -				*hello_option_propagation_delay); -   -  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY); -   -  *hello_option_propagation_delay = PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr); -  if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) { -    PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); -  } -  else { -    PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); -  } -  ++tlv_curr; -  ++tlv_curr; -  *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr); -   -  return 0; +	if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay", ifname, +			     src_addr, sizeof(uint32_t), option_len)) { +		return -1; +	} + +	check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay", +				      ifname, src_addr, *hello_options, +				      PIM_OPTION_MASK_LAN_PRUNE_DELAY, +				      PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr), +				      *hello_option_propagation_delay); + +	PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY); + +	*hello_option_propagation_delay = +		PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr); +	if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) { +		PIM_OPTION_SET(*hello_options, +			       PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); +	} else { +		PIM_OPTION_UNSET(*hello_options, +				 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); +	} +	++tlv_curr; +	++tlv_curr; +	*hello_option_override_interval = +		PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr); + +	return 0;  }  int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr,  			      pim_hello_options *hello_options,  			      uint32_t *hello_option_dr_priority, -			      uint16_t option_len, -			      const uint8_t *tlv_curr)  +			      uint16_t option_len, const uint8_t *tlv_curr)  { -  const char *label = "dr_priority"; - -  if (check_tlv_length(__PRETTY_FUNCTION__, label, -		       ifname, src_addr, -		       sizeof(uint32_t), option_len)) { -    return -1; -  } -   -  check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label, -				ifname, src_addr, -				*hello_options, PIM_OPTION_MASK_DR_PRIORITY, -				PIM_TLV_GET_DR_PRIORITY(tlv_curr), -				*hello_option_dr_priority); -   -  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY); -   -  *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr); - -  return 0; +	const char *label = "dr_priority"; + +	if (check_tlv_length(__PRETTY_FUNCTION__, label, ifname, src_addr, +			     sizeof(uint32_t), option_len)) { +		return -1; +	} + +	check_tlv_redefinition_uint32( +		__PRETTY_FUNCTION__, label, ifname, src_addr, *hello_options, +		PIM_OPTION_MASK_DR_PRIORITY, PIM_TLV_GET_DR_PRIORITY(tlv_curr), +		*hello_option_dr_priority); + +	PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY); + +	*hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr); + +	return 0;  }  int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr,  				pim_hello_options *hello_options,  				uint32_t *hello_option_generation_id, -				uint16_t option_len, -				const uint8_t *tlv_curr)  +				uint16_t option_len, const uint8_t *tlv_curr)  { -  const char *label = "generation_id"; - -  if (check_tlv_length(__PRETTY_FUNCTION__, label, -		       ifname, src_addr, -		       sizeof(uint32_t), option_len)) { -    return -1; -  } -   -  check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label, -				    ifname, src_addr, -				    *hello_options, PIM_OPTION_MASK_GENERATION_ID, -				    PIM_TLV_GET_GENERATION_ID(tlv_curr), -				    *hello_option_generation_id); -   -  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID); -   -  *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr); -   -  return 0; +	const char *label = "generation_id"; + +	if (check_tlv_length(__PRETTY_FUNCTION__, label, ifname, src_addr, +			     sizeof(uint32_t), option_len)) { +		return -1; +	} + +	check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label, ifname, +					  src_addr, *hello_options, +					  PIM_OPTION_MASK_GENERATION_ID, +					  PIM_TLV_GET_GENERATION_ID(tlv_curr), +					  *hello_option_generation_id); + +	PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID); + +	*hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr); + +	return 0;  } -int -pim_parse_addr_ucast (struct prefix *p, -		      const uint8_t *buf, -		      int buf_size) +int pim_parse_addr_ucast(struct prefix *p, const uint8_t *buf, int buf_size)  { -  const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */ -  const uint8_t *addr; -  const uint8_t *pastend; -  int family; -  int type; - -  if (buf_size < ucast_encoding_min_len) { -    zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d", -	      __PRETTY_FUNCTION__, -	      buf_size, ucast_encoding_min_len); -    return -1; -  } - -  addr = buf; -  pastend = buf + buf_size; - -  family = *addr++; -  type = *addr++; - -  if (type) { -    zlog_warn("%s: unknown unicast address encoding type=%d", -	      __PRETTY_FUNCTION__, -	      type); -    return -2; -  } - -  switch (family) { -  case PIM_MSG_ADDRESS_FAMILY_IPV4: -    if ((addr + sizeof(struct in_addr)) > pastend) { -      zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu", -		__PRETTY_FUNCTION__, -		pastend - addr, sizeof(struct in_addr)); -      return -3; -    } - -    p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ -    memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); -    p->prefixlen = IPV4_MAX_PREFIXLEN; -    addr += sizeof(struct in_addr); - -    break; -  case PIM_MSG_ADDRESS_FAMILY_IPV6: -    if ((addr + sizeof(struct in6_addr)) > pastend) { -      zlog_warn ("%s: IPv6 unicast address overflow: left=%zd needed %zu", -                 __PRETTY_FUNCTION__, -                 pastend - addr, sizeof(struct in6_addr)); -      return -3; -    } - -    p->family = AF_INET6; -    p->prefixlen = IPV6_MAX_PREFIXLEN; -    memcpy(&p->u.prefix6, addr, sizeof(struct in6_addr)); -    addr += sizeof(struct in6_addr); - -    break; -  default: -    { -      zlog_warn("%s: unknown unicast address encoding family=%d from", -		__PRETTY_FUNCTION__, -		family); -      return -4; -    } -  } - -  return addr - buf; +	const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */ +	const uint8_t *addr; +	const uint8_t *pastend; +	int family; +	int type; + +	if (buf_size < ucast_encoding_min_len) { +		zlog_warn( +			"%s: unicast address encoding overflow: left=%d needed=%d", +			__PRETTY_FUNCTION__, buf_size, ucast_encoding_min_len); +		return -1; +	} + +	addr = buf; +	pastend = buf + buf_size; + +	family = *addr++; +	type = *addr++; + +	if (type) { +		zlog_warn("%s: unknown unicast address encoding type=%d", +			  __PRETTY_FUNCTION__, type); +		return -2; +	} + +	switch (family) { +	case PIM_MSG_ADDRESS_FAMILY_IPV4: +		if ((addr + sizeof(struct in_addr)) > pastend) { +			zlog_warn( +				"%s: IPv4 unicast address overflow: left=%zd needed=%zu", +				__PRETTY_FUNCTION__, pastend - addr, +				sizeof(struct in_addr)); +			return -3; +		} + +		p->family = AF_INET; /* notice: AF_INET != +					PIM_MSG_ADDRESS_FAMILY_IPV4 */ +		memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); +		p->prefixlen = IPV4_MAX_PREFIXLEN; +		addr += sizeof(struct in_addr); + +		break; +	case PIM_MSG_ADDRESS_FAMILY_IPV6: +		if ((addr + sizeof(struct in6_addr)) > pastend) { +			zlog_warn( +				"%s: IPv6 unicast address overflow: left=%zd needed %zu", +				__PRETTY_FUNCTION__, pastend - addr, +				sizeof(struct in6_addr)); +			return -3; +		} + +		p->family = AF_INET6; +		p->prefixlen = IPV6_MAX_PREFIXLEN; +		memcpy(&p->u.prefix6, addr, sizeof(struct in6_addr)); +		addr += sizeof(struct in6_addr); + +		break; +	default: { +		zlog_warn("%s: unknown unicast address encoding family=%d from", +			  __PRETTY_FUNCTION__, family); +		return -4; +	} +	} + +	return addr - buf;  } -int -pim_parse_addr_group (struct prefix_sg *sg, -		      const uint8_t *buf, -		      int buf_size) +int pim_parse_addr_group(struct prefix_sg *sg, const uint8_t *buf, int buf_size)  { -  const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ -  const uint8_t *addr; -  const uint8_t *pastend; -  int family; -  int type; -  int mask_len; - -  if (buf_size < grp_encoding_min_len) { -    zlog_warn("%s: group address encoding overflow: left=%d needed=%d", -	      __PRETTY_FUNCTION__, -	      buf_size, grp_encoding_min_len); -    return -1; -  } - -  addr = buf; -  pastend = buf + buf_size; - -  family = *addr++; -  type = *addr++; -  //++addr; -  ++addr; /* skip b_reserved_z fields */ -  mask_len = *addr++; - -  switch (family) { -  case PIM_MSG_ADDRESS_FAMILY_IPV4: -    if (type) { -      zlog_warn("%s: unknown group address encoding type=%d from", -		__PRETTY_FUNCTION__, type); -      return -2; -    } - -    if ((addr + sizeof(struct in_addr)) > pastend) { -      zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from", -		__PRETTY_FUNCTION__, -		pastend - addr, sizeof(struct in_addr)); -      return -3; -    } - -    memcpy(&sg->grp.s_addr, addr, sizeof(struct in_addr)); - -    addr += sizeof(struct in_addr); - -    break; -  default: -    { -      zlog_warn("%s: unknown group address encoding family=%d mask_len=%d from", -		__PRETTY_FUNCTION__, family, mask_len); -      return -4; -    } -  } - -  return addr - buf; +	const int grp_encoding_min_len = +		4; /* 1 family + 1 type + 1 reserved + 1 addr */ +	const uint8_t *addr; +	const uint8_t *pastend; +	int family; +	int type; +	int mask_len; + +	if (buf_size < grp_encoding_min_len) { +		zlog_warn( +			"%s: group address encoding overflow: left=%d needed=%d", +			__PRETTY_FUNCTION__, buf_size, grp_encoding_min_len); +		return -1; +	} + +	addr = buf; +	pastend = buf + buf_size; + +	family = *addr++; +	type = *addr++; +	//++addr; +	++addr; /* skip b_reserved_z fields */ +	mask_len = *addr++; + +	switch (family) { +	case PIM_MSG_ADDRESS_FAMILY_IPV4: +		if (type) { +			zlog_warn( +				"%s: unknown group address encoding type=%d from", +				__PRETTY_FUNCTION__, type); +			return -2; +		} + +		if ((addr + sizeof(struct in_addr)) > pastend) { +			zlog_warn( +				"%s: IPv4 group address overflow: left=%zd needed=%zu from", +				__PRETTY_FUNCTION__, pastend - addr, +				sizeof(struct in_addr)); +			return -3; +		} + +		memcpy(&sg->grp.s_addr, addr, sizeof(struct in_addr)); + +		addr += sizeof(struct in_addr); + +		break; +	default: { +		zlog_warn( +			"%s: unknown group address encoding family=%d mask_len=%d from", +			__PRETTY_FUNCTION__, family, mask_len); +		return -4; +	} +	} + +	return addr - buf;  } -int -pim_parse_addr_source(struct prefix_sg *sg, -		      uint8_t *flags, -		      const uint8_t *buf, -		      int buf_size) +int pim_parse_addr_source(struct prefix_sg *sg, uint8_t *flags, +			  const uint8_t *buf, int buf_size)  { -  const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ -  const uint8_t *addr; -  const uint8_t *pastend; -  int family; -  int type; -  int mask_len; - -  if (buf_size < src_encoding_min_len) { -    zlog_warn("%s: source address encoding overflow: left=%d needed=%d", -	      __PRETTY_FUNCTION__, -	      buf_size, src_encoding_min_len); -    return -1; -  } - -  addr = buf; -  pastend = buf + buf_size; - -  family = *addr++; -  type = *addr++; -  *flags = *addr++; -  mask_len = *addr++; - -  if (type) { -    zlog_warn("%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x", -	      __PRETTY_FUNCTION__, -	      type, -	      buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); -    return -2; -  } - -  switch (family) { -  case PIM_MSG_ADDRESS_FAMILY_IPV4: -    if ((addr + sizeof(struct in_addr)) > pastend) { -      zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu", -		__PRETTY_FUNCTION__, -		pastend - addr, sizeof(struct in_addr)); -      return -3; -    } - -    memcpy(&sg->src, addr, sizeof(struct in_addr)); - -    /*  -       RFC 4601: 4.9.1  Encoded Source and Group Address Formats - -       Encoded-Source Address - -       The mask length MUST be equal to the mask length in bits for -       the given Address Family and Encoding Type (32 for IPv4 native -       and 128 for IPv6 native).  A router SHOULD ignore any messages -       received with any other mask length. -    */ -    if (mask_len != 32) { -      zlog_warn("%s: IPv4 bad source address mask: %d", -		__PRETTY_FUNCTION__, mask_len); -      return -4; -    } - -    addr += sizeof(struct in_addr); - -    break; -  default: -    { -      zlog_warn("%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x", -		__PRETTY_FUNCTION__, -		family, -		buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); -      return -5; -    } -  } - -  return addr - buf; -} +	const int src_encoding_min_len = +		4; /* 1 family + 1 type + 1 reserved + 1 addr */ +	const uint8_t *addr; +	const uint8_t *pastend; +	int family; +	int type; +	int mask_len; + +	if (buf_size < src_encoding_min_len) { +		zlog_warn( +			"%s: source address encoding overflow: left=%d needed=%d", +			__PRETTY_FUNCTION__, buf_size, src_encoding_min_len); +		return -1; +	} + +	addr = buf; +	pastend = buf + buf_size; + +	family = *addr++; +	type = *addr++; +	*flags = *addr++; +	mask_len = *addr++; -#define FREE_ADDR_LIST(hello_option_addr_list) \ -{ \ -  if (hello_option_addr_list) { \ -    list_delete(hello_option_addr_list); \ -    hello_option_addr_list = 0; \ -  } \ +	if (type) { +		zlog_warn( +			"%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x", +			__PRETTY_FUNCTION__, type, buf[0], buf[1], buf[2], +			buf[3], buf[4], buf[5], buf[6], buf[7]); +		return -2; +	} + +	switch (family) { +	case PIM_MSG_ADDRESS_FAMILY_IPV4: +		if ((addr + sizeof(struct in_addr)) > pastend) { +			zlog_warn( +				"%s: IPv4 source address overflow: left=%zd needed=%zu", +				__PRETTY_FUNCTION__, pastend - addr, +				sizeof(struct in_addr)); +			return -3; +		} + +		memcpy(&sg->src, addr, sizeof(struct in_addr)); + +		/* +		   RFC 4601: 4.9.1  Encoded Source and Group Address Formats + +		   Encoded-Source Address + +		   The mask length MUST be equal to the mask length in bits for +		   the given Address Family and Encoding Type (32 for IPv4 +		   native +		   and 128 for IPv6 native).  A router SHOULD ignore any +		   messages +		   received with any other mask length. +		*/ +		if (mask_len != 32) { +			zlog_warn("%s: IPv4 bad source address mask: %d", +				  __PRETTY_FUNCTION__, mask_len); +			return -4; +		} + +		addr += sizeof(struct in_addr); + +		break; +	default: { +		zlog_warn( +			"%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x", +			__PRETTY_FUNCTION__, family, buf[0], buf[1], buf[2], +			buf[3], buf[4], buf[5], buf[6], buf[7]); +		return -5; +	} +	} + +	return addr - buf;  } +#define FREE_ADDR_LIST(hello_option_addr_list)                                 \ +	{                                                                      \ +		if (hello_option_addr_list) {                                  \ +			list_delete(hello_option_addr_list);                   \ +			hello_option_addr_list = 0;                            \ +		}                                                              \ +	} +  int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,  			    pim_hello_options *hello_options,  			    struct list **hello_option_addr_list, -			    uint16_t option_len, -			    const uint8_t *tlv_curr)  +			    uint16_t option_len, const uint8_t *tlv_curr)  { -  const uint8_t *addr; -  const uint8_t *pastend; - -  zassert(hello_option_addr_list); - -  /* -    Scan addr list -   */ -  addr = tlv_curr; -  pastend = tlv_curr + option_len; -  while (addr < pastend) { -    struct prefix tmp; -    int addr_offset; - -    /* -      Parse ucast addr -     */ -    addr_offset = pim_parse_addr_ucast(&tmp, addr, pastend - addr); -    if (addr_offset < 1) { -      char src_str[INET_ADDRSTRLEN]; -      pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); -      zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", -		__PRETTY_FUNCTION__, -		src_str, ifname); -      FREE_ADDR_LIST(*hello_option_addr_list); -      return -1; -    } -    addr += addr_offset; - -    /* -      Debug -     */ -    if (PIM_DEBUG_PIM_TRACE) { -      switch (tmp.family) { -      case AF_INET: -	{ -	  char addr_str[INET_ADDRSTRLEN]; -	  char src_str[INET_ADDRSTRLEN]; -	  pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str)); -	  pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); -	  zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s", -		     __PRETTY_FUNCTION__, -		     *hello_option_addr_list ? -		     ((int) listcount(*hello_option_addr_list)) : -1, -		     addr_str, src_str, ifname); -	} -	break; -      case AF_INET6: -        break; -      default: -	{ -	  char src_str[INET_ADDRSTRLEN]; -	  pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); -	  zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s", -		     __PRETTY_FUNCTION__, -		     *hello_option_addr_list ? -		     ((int) listcount(*hello_option_addr_list)) : -1, -		     src_str, ifname); -	} -      } -    } - -    /* -      Exclude neighbor's primary address if incorrectly included in -      the secondary address list -     */ -    if (tmp.family == AF_INET) { -      if (tmp.u.prefix4.s_addr == src_addr.s_addr) { -	  char src_str[INET_ADDRSTRLEN]; -	  pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); -	  zlog_warn("%s: ignoring primary address in secondary list from %s on %s", -		    __PRETTY_FUNCTION__, -		    src_str, ifname); -	  continue; -      } -    } - -    /* -      Allocate list if needed -     */ -    if (!*hello_option_addr_list) { -      *hello_option_addr_list = list_new(); -      if (!*hello_option_addr_list) { -	zlog_err("%s %s: failure: hello_option_addr_list=list_new()", -		 __FILE__, __PRETTY_FUNCTION__); -	return -2; -      } -      (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free; -    } - -    /* -      Attach addr to list -     */ -    { -      struct prefix *p; -      p = prefix_new(); -      if (!p) { -	zlog_err("%s %s: failure: prefix_new()", -		 __FILE__, __PRETTY_FUNCTION__); -	FREE_ADDR_LIST(*hello_option_addr_list); -	return -3; -      } -      prefix_copy(p, &tmp); -      listnode_add(*hello_option_addr_list, p); -    } - -  } /* while (addr < pastend) */ -   -  /* -    Mark hello option -   */ -  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST); -   -  return 0; +	const uint8_t *addr; +	const uint8_t *pastend; + +	zassert(hello_option_addr_list); + +	/* +	  Scan addr list +	 */ +	addr = tlv_curr; +	pastend = tlv_curr + option_len; +	while (addr < pastend) { +		struct prefix tmp; +		int addr_offset; + +		/* +		  Parse ucast addr +		 */ +		addr_offset = pim_parse_addr_ucast(&tmp, addr, pastend - addr); +		if (addr_offset < 1) { +			char src_str[INET_ADDRSTRLEN]; +			pim_inet4_dump("<src?>", src_addr, src_str, +				       sizeof(src_str)); +			zlog_warn( +				"%s: pim_parse_addr_ucast() failure: from %s on %s", +				__PRETTY_FUNCTION__, src_str, ifname); +			FREE_ADDR_LIST(*hello_option_addr_list); +			return -1; +		} +		addr += addr_offset; + +		/* +		  Debug +		 */ +		if (PIM_DEBUG_PIM_TRACE) { +			switch (tmp.family) { +			case AF_INET: { +				char addr_str[INET_ADDRSTRLEN]; +				char src_str[INET_ADDRSTRLEN]; +				pim_inet4_dump("<addr?>", tmp.u.prefix4, +					       addr_str, sizeof(addr_str)); +				pim_inet4_dump("<src?>", src_addr, src_str, +					       sizeof(src_str)); +				zlog_debug( +					"%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s", +					__PRETTY_FUNCTION__, +					*hello_option_addr_list +						? ((int)listcount( +							  *hello_option_addr_list)) +						: -1, +					addr_str, src_str, ifname); +			} break; +			case AF_INET6: +				break; +			default: { +				char src_str[INET_ADDRSTRLEN]; +				pim_inet4_dump("<src?>", src_addr, src_str, +					       sizeof(src_str)); +				zlog_debug( +					"%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s", +					__PRETTY_FUNCTION__, +					*hello_option_addr_list +						? ((int)listcount( +							  *hello_option_addr_list)) +						: -1, +					src_str, ifname); +			} +			} +		} + +		/* +		  Exclude neighbor's primary address if incorrectly included in +		  the secondary address list +		 */ +		if (tmp.family == AF_INET) { +			if (tmp.u.prefix4.s_addr == src_addr.s_addr) { +				char src_str[INET_ADDRSTRLEN]; +				pim_inet4_dump("<src?>", src_addr, src_str, +					       sizeof(src_str)); +				zlog_warn( +					"%s: ignoring primary address in secondary list from %s on %s", +					__PRETTY_FUNCTION__, src_str, ifname); +				continue; +			} +		} + +		/* +		  Allocate list if needed +		 */ +		if (!*hello_option_addr_list) { +			*hello_option_addr_list = list_new(); +			if (!*hello_option_addr_list) { +				zlog_err( +					"%s %s: failure: hello_option_addr_list=list_new()", +					__FILE__, __PRETTY_FUNCTION__); +				return -2; +			} +			(*hello_option_addr_list)->del = +				(void (*)(void *))prefix_free; +		} + +		/* +		  Attach addr to list +		 */ +		{ +			struct prefix *p; +			p = prefix_new(); +			if (!p) { +				zlog_err("%s %s: failure: prefix_new()", +					 __FILE__, __PRETTY_FUNCTION__); +				FREE_ADDR_LIST(*hello_option_addr_list); +				return -3; +			} +			prefix_copy(p, &tmp); +			listnode_add(*hello_option_addr_list, p); +		} + +	} /* while (addr < pastend) */ + +	/* +	  Mark hello option +	 */ +	PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST); + +	return 0;  }  | 
