static int send_ra(int sock, struct Interface *iface, struct in6_addr const *dest) { if (!iface->AdvSendAdvert) { dlog(LOG_DEBUG, 2, "AdvSendAdvert is off for %s", iface->props.name); return 0; } if (dest == NULL) { static uint8_t const all_hosts_addr[] = { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; dest = (struct in6_addr const *)all_hosts_addr; clock_gettime(CLOCK_MONOTONIC, &iface->times.last_multicast); } update_iface_times(iface); char address_text[INET6_ADDRSTRLEN] = { "" }; inet_ntop(AF_INET6, dest, address_text, INET6_ADDRSTRLEN); dlog(LOG_DEBUG, 5, "sending RA to %s on %s", address_text, iface->props.name); struct safe_buffer safe_buffer = SAFE_BUFFER_INIT; build_ra(&safe_buffer, iface); int err = really_send(sock, dest, &iface->props, &safe_buffer); safe_buffer_free(&safe_buffer); if (err < 0) { if (!iface->IgnoreIfMissing || !(errno == EINVAL || errno == ENODEV)) flog(LOG_WARNING, "sendmsg: %s", strerror(errno)); else dlog(LOG_DEBUG, 3, "sendmsg: %s", strerror(errno)); return -1; } return 0; }
static void add_pvd(struct safe_buffer * sb, struct AdvPvd const *pvd, int cease_adv) { while (pvd) { /* create a temporary buffer to write the encapsulated options to until we calculate the total length of the outer PVD_CO option */ size_t total_len = 0; struct safe_buffer pvd_sb = SAFE_BUFFER_INIT; struct AdvPrefix *prefix = pvd->AdvPrefixList; while (prefix) { char pfx_str[INET6_ADDRSTRLEN]; addrtostr(&prefix->Prefix, pfx_str, sizeof(pfx_str)); prefix = prefix->next; } struct nd_opt_pvd pvdinfo; memset(&pvdinfo, 0, sizeof(pvdinfo)); /* create PVD_CO container option */ pvdinfo.nd_opt_pvd_container_type = ND_OPT_PVD_CONTAINER; /* initial length of PVD_CO option without encapsulated options */ pvdinfo.nd_opt_pvd_container_len = 1; total_len += pvdinfo.nd_opt_pvd_container_len; pvdinfo.nd_opt_pvd_container_s = 0; pvdinfo.nd_opt_pvd_container_nametype = 0; /* add PVD_ID option */ pvdinfo.nd_opt_pvd_id_type = ND_OPT_PVD_ID; pvdinfo.nd_opt_pvd_id_len = 5; total_len += pvdinfo.nd_opt_pvd_id_len; pvdinfo.nd_opt_pvd_id_idtype = 4; pvdinfo.nd_opt_pvd_id_idlen = 36; memcpy(&pvdinfo.nd_opt_pvd_id_pvdid, pvd->pvdid, sizeof(pvdinfo.nd_opt_pvd_id_pvdid));; /* add encapsulated ND options if specified */ if (pvd->AdvPrefixList) { total_len += add_prefix(&pvd_sb, pvd->AdvPrefixList, cease_adv); } if (pvd->AdvRouteList) { total_len += add_route(&pvd_sb, pvd->AdvRouteList, cease_adv); } if (pvd->AdvRDNSSList) { total_len += add_rdnss(&pvd_sb, pvd->AdvRDNSSList, cease_adv); } if (pvd->AdvDNSSLList) { total_len += add_dnssl(&pvd_sb, pvd->AdvDNSSLList, cease_adv); } /* if (iface->AdvLinkMTU != 0) { add_mtu(sb, iface->AdvLinkMTU); } if (iface->AdvSourceLLAddress && iface->sllao.if_hwaddr_len > 0) { add_sllao(sb, &iface->sllao); } if (iface->mipv6.AdvIntervalOpt) { add_mipv6_rtr_adv_interval(sb, iface->MaxRtrAdvInterval); } if (iface->mipv6.AdvHomeAgentInfo && (iface->mipv6.AdvMobRtrSupportFlag || iface->mipv6.HomeAgentPreference != 0 || iface->mipv6.HomeAgentLifetime != iface->ra_header_info.AdvDefaultLifetime)) { add_mipv6_home_agent_info(sb, &iface->mipv6); } */ if (pvd->AdvLowpanCoList) { total_len += add_lowpanco(&pvd_sb, pvd->AdvLowpanCoList); } if (pvd->AdvAbroList) { total_len += add_abro(&pvd_sb, pvd->AdvAbroList); } /* write out PVD_CO container option + PVD_ID option */ pvdinfo.nd_opt_pvd_container_len = total_len; safe_buffer_append(sb, &pvdinfo, sizeof(pvdinfo)); /* write out encapsulated ND options */ safe_buffer_append(sb, pvd_sb.buffer, pvd_sb.used); /* destroy a temporary buffer */ safe_buffer_free(&pvd_sb); pvd = pvd->next; } }