1/* 2 * $Id: send.c,v 1.30 2009/06/24 09:27:49 psavola Exp $ 3 * 4 * Authors: 5 * Pedro Roque <roque@di.fc.ul.pt> 6 * Lars Fenneberg <lf@elemental.net> 7 * 8 * This software is Copyright 1996,1997 by the above mentioned author(s), 9 * All Rights Reserved. 10 * 11 * The license which is distributed with this software in the file COPYRIGHT 12 * applies to this software. If your distribution is missing this file, you 13 * may request it from <pekkas@netcore.fi>. 14 * 15 */ 16 17#include <config.h> 18#include <includes.h> 19#include <radvd.h> 20 21/* 22 * Sends an advertisement for all specified clients of this interface 23 * (or via broadcast, if there are no restrictions configured). 24 * 25 * If a destination address is given, the RA will be sent to the destination 26 * address only, but only if it was configured. 27 * 28 */ 29void 30send_ra_forall(int sock, struct Interface *iface, struct in6_addr *dest) 31{ 32 struct Clients *current; 33 34 /* If no list of clients was specified for this interface, we broadcast */ 35 if (iface->ClientList == NULL) { 36 send_ra(sock, iface, dest); 37 return; 38 } 39 40 /* If clients are configured, send the advertisement to all of them via unicast */ 41 for (current = iface->ClientList; current; current = current->next) 42 { 43 char address_text[INET6_ADDRSTRLEN]; 44 memset(address_text, 0, sizeof(address_text)); 45 if (get_debuglevel() >= 5) 46 inet_ntop(AF_INET6, ¤t->Address, address_text, INET6_ADDRSTRLEN); 47 48 /* If a non-authorized client sent a solicitation, ignore it (logging later) */ 49 if (dest != NULL && memcmp(dest, ¤t->Address, sizeof(struct in6_addr)) != 0) 50 continue; 51 dlog(LOG_DEBUG, 5, "Sending RA to %s", address_text); 52 send_ra(sock, iface, &(current->Address)); 53 54 /* If we should only send the RA to a specific address, we are done */ 55 if (dest != NULL) 56 return; 57 } 58 if (dest == NULL) 59 return; 60 61 /* If we refused a client's solicitation, log it if debugging is high enough */ 62 char address_text[INET6_ADDRSTRLEN]; 63 memset(address_text, 0, sizeof(address_text)); 64 if (get_debuglevel() >= 5) 65 inet_ntop(AF_INET6, dest, address_text, INET6_ADDRSTRLEN); 66 67 dlog(LOG_DEBUG, 5, "Not answering request from %s, not configured", address_text); 68} 69 70void 71send_ra(int sock, struct Interface *iface, struct in6_addr *dest) 72{ 73 uint8_t all_hosts_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; 74 struct sockaddr_in6 addr; 75 struct in6_pktinfo *pkt_info; 76 struct msghdr mhdr; 77 struct cmsghdr *cmsg; 78 struct iovec iov; 79 char __attribute__((aligned(8))) chdr[CMSG_SPACE(sizeof(struct in6_pktinfo))]; 80 struct nd_router_advert *radvert; 81 struct AdvPrefix *prefix; 82 struct AdvRoute *route; 83 struct AdvRDNSS *rdnss; 84 /* XXX: we don't keep track if buff gets overflowed. In theory the sysadmin could 85 do that with e.g., too many advertised prefixes or routes, but buff is just so 86 large that this should never happen and if it does, it's admin's fault :-) */ 87 unsigned char buff[MSG_SIZE]; 88 size_t len = 0; 89 ssize_t err; 90 91 /* Foxconn added start pling 12/22/2011 */ 92 unsigned long sec_since_initial_advert = 0; 93 unsigned long remain_lifetime = 0; 94 /* Foxconn added end pling 12/22/2011 */ 95 /* First we need to check that the interface hasn't been removed or deactivated */ 96 if(check_device(sock, iface) < 0) { 97 if (iface->IgnoreIfMissing) /* a bit more quiet warning message.. */ 98 dlog(LOG_DEBUG, 4, "interface %s does not exist, ignoring the interface", iface->Name); 99 else { 100 flog(LOG_WARNING, "interface %s does not exist, ignoring the interface", iface->Name); 101 } 102 iface->HasFailed = 1; 103 } else { 104 /* check_device was successful, act if it has failed previously */ 105 if (iface->HasFailed == 1) { 106 flog(LOG_WARNING, "interface %s seems to have come back up, trying to reinitialize", iface->Name); 107 iface->HasFailed = 0; 108 /* XXX: reinitializes 'iface', so this probably isn't going to work until next send_ra().. */ 109 reload_config(); 110 } 111 } 112 113 /* Make sure that we've joined the all-routers multicast group */ 114 if (check_allrouters_membership(sock, iface) < 0) 115 flog(LOG_WARNING, "problem checking all-routers membership on %s", iface->Name); 116 117 dlog(LOG_DEBUG, 3, "sending RA on %s", iface->Name); 118 119 /* Foxconn modified start pling 11/05/2014 */ 120 /* IPv6 Self Test v5.0.0 always assume the RA is multicast */ 121 /* R7000 TD#395, need to restore original code, otherwise some 122 * Win7/Win8 PC can't get DNS IP properly after reboot */ 123 if ((dest == NULL) || 124 ( (dest->s6_addr32[0]==0) && (dest->s6_addr32[1]==0) && (dest->s6_addr32[2]==0) && (dest->s6_addr32[3]==0)) ) /* IPv6Ready- Test v6LC.2.2.9: Processing Router Solicitations, Bob added 07/15/2009 */ 125 //if (1) 126 /* Foxconn modified end pling 11/05/2014 */ 127 { 128 struct timeval tv; 129 130 dest = (struct in6_addr *)all_hosts_addr; 131 gettimeofday(&tv, NULL); 132 133 iface->last_multicast_sec = tv.tv_sec; 134 iface->last_multicast_usec = tv.tv_usec; 135 } 136 137 memset((void *)&addr, 0, sizeof(addr)); 138 addr.sin6_family = AF_INET6; 139 addr.sin6_port = htons(IPPROTO_ICMPV6); 140 memcpy(&addr.sin6_addr, dest, sizeof(struct in6_addr)); 141 142 memset(&buff, 0, sizeof(buff)); 143 radvert = (struct nd_router_advert *) buff; 144 145 radvert->nd_ra_type = ND_ROUTER_ADVERT; 146 radvert->nd_ra_code = 0; 147 radvert->nd_ra_cksum = 0; 148 149 radvert->nd_ra_curhoplimit = iface->AdvCurHopLimit; 150 radvert->nd_ra_flags_reserved = 151 (iface->AdvManagedFlag)?ND_RA_FLAG_MANAGED:0; 152 radvert->nd_ra_flags_reserved |= 153 (iface->AdvOtherConfigFlag)?ND_RA_FLAG_OTHER:0; 154 /* Mobile IPv6 ext */ 155 radvert->nd_ra_flags_reserved |= 156 (iface->AdvHomeAgentFlag)?ND_RA_FLAG_HOME_AGENT:0; 157 158 /* if forwarding is disabled, send zero router lifetime */ 159 radvert->nd_ra_router_lifetime = !check_ip6_forwarding() ? htons(iface->AdvDefaultLifetime) : 0; 160 radvert->nd_ra_flags_reserved |= 161 (iface->AdvDefaultPreference << ND_OPT_RI_PRF_SHIFT) & ND_OPT_RI_PRF_MASK; 162 163 radvert->nd_ra_reachable = htonl(iface->AdvReachableTime); 164 radvert->nd_ra_retransmit = htonl(iface->AdvRetransTimer); 165 166 len = sizeof(struct nd_router_advert); 167 168 prefix = iface->AdvPrefixList; 169 170 /* 171 * add prefix options 172 */ 173 174 while(prefix) 175 { 176 /* Foxconn Perry added start, 2011/05/13, for IPv6 obsolete prefix information */ 177 /* Router advertisment should not have obsolete prefix information for nornam RA */ 178 if(iface->init_racount>=MAX_INITIAL_RTR_ADVERTISEMENTS && htonl(prefix->AdvValidLifetime)==0) 179 { 180 prefix = prefix->next; 181 continue; 182 } 183 /* Foxconn Perry added end, 2011/05/13, for IPv6 obsolete prefix information */ 184 185 if( prefix->enabled ) 186 { 187 struct nd_opt_prefix_info *pinfo; 188 189 pinfo = (struct nd_opt_prefix_info *) (buff + len); 190 191 pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 192 pinfo->nd_opt_pi_len = 4; 193 pinfo->nd_opt_pi_prefix_len = prefix->PrefixLen; 194 195 pinfo->nd_opt_pi_flags_reserved = 196 (prefix->AdvOnLinkFlag)?ND_OPT_PI_FLAG_ONLINK:0; 197 pinfo->nd_opt_pi_flags_reserved |= 198 (prefix->AdvAutonomousFlag)?ND_OPT_PI_FLAG_AUTO:0; 199 /* Mobile IPv6 ext */ 200 pinfo->nd_opt_pi_flags_reserved |= 201 (prefix->AdvRouterAddr)?ND_OPT_PI_FLAG_RADDR:0; 202 203 pinfo->nd_opt_pi_valid_time = htonl(prefix->AdvValidLifetime); 204 /* Foxconn modified start pling 09/25/2011 */ 205 /* Advertise the remaining lifetime (in DHCP mode) 206 * WNDR4500v2 TD#14: make sure obselete prefices are still sent 207 */ 208 //if (use_dynamic_lifetime) { 209 if (use_dynamic_lifetime && htonl(prefix->AdvValidLifetime)) { 210 /* Foxconn modified end pling 09/25/2012 */ 211 sec_since_initial_advert = get_current_time() - initial_advert_time; 212 if (sec_since_initial_advert >= prefix->AdvValidLifetime) { 213 /* prefix expired, do not advertise */ 214 prefix = prefix->next; 215 continue; 216 } 217 /* Advertise the remaining lifetime */ 218 remain_lifetime = prefix->AdvValidLifetime - sec_since_initial_advert; 219 pinfo->nd_opt_pi_valid_time = htonl(remain_lifetime); 220 } 221 /* Foxconn added end pling 12/22/2011 */ 222 pinfo->nd_opt_pi_preferred_time = htonl(prefix->AdvPreferredLifetime); 223 /* Foxconn modified start pling 09/25/2012 */ 224 /* Modify the "preferred lifetime" behaviour per Netgear request. 225 * WNDR4500v2 TD#14: make sure obselete prefices are still sent 226 */ 227 //if (use_dynamic_lifetime) { 228 if (use_dynamic_lifetime && htonl(prefix->AdvPreferredLifetime)) { 229 /* Foxconn modified end pling 09/25/2012 */ 230 if (sec_since_initial_advert >= prefix->AdvPreferredLifetime) 231 pinfo->nd_opt_pi_preferred_time = htonl(0); 232 else { 233 remain_lifetime = prefix->AdvPreferredLifetime - sec_since_initial_advert; 234 pinfo->nd_opt_pi_preferred_time = htonl(remain_lifetime); 235 } 236 } 237 /* Foxconn added end pling 12/29/2011 */ 238 pinfo->nd_opt_pi_reserved2 = 0; 239 240 memcpy(&pinfo->nd_opt_pi_prefix, &prefix->Prefix, 241 sizeof(struct in6_addr)); 242 243 len += sizeof(*pinfo); 244 } 245 246 prefix = prefix->next; 247 } 248 249 route = iface->AdvRouteList; 250 251 /* 252 * add route options 253 */ 254 255 while(route) 256 { 257 struct nd_opt_route_info_local *rinfo; 258 259 rinfo = (struct nd_opt_route_info_local *) (buff + len); 260 261 rinfo->nd_opt_ri_type = ND_OPT_ROUTE_INFORMATION; 262 /* XXX: the prefixes are allowed to be sent in smaller chunks as well */ 263 rinfo->nd_opt_ri_len = 3; 264 rinfo->nd_opt_ri_prefix_len = route->PrefixLen; 265 266 rinfo->nd_opt_ri_flags_reserved = 267 (route->AdvRoutePreference << ND_OPT_RI_PRF_SHIFT) & ND_OPT_RI_PRF_MASK; 268 rinfo->nd_opt_ri_lifetime = htonl(route->AdvRouteLifetime); 269 270 memcpy(&rinfo->nd_opt_ri_prefix, &route->Prefix, 271 sizeof(struct in6_addr)); 272 len += sizeof(*rinfo); 273 274 route = route->next; 275 } 276 277 rdnss = iface->AdvRDNSSList; 278 279 /* 280 * add rdnss options 281 */ 282 283 while(rdnss) 284 { 285 struct nd_opt_rdnss_info_local *rdnssinfo; 286 287 rdnssinfo = (struct nd_opt_rdnss_info_local *) (buff + len); 288 289 rdnssinfo->nd_opt_rdnssi_type = ND_OPT_RDNSS_INFORMATION; 290 rdnssinfo->nd_opt_rdnssi_len = 1 + 2*rdnss->AdvRDNSSNumber; 291 rdnssinfo->nd_opt_rdnssi_pref_flag_reserved = 292 ((rdnss->AdvRDNSSPreference << ND_OPT_RDNSSI_PREF_SHIFT) & ND_OPT_RDNSSI_PREF_MASK); 293 rdnssinfo->nd_opt_rdnssi_pref_flag_reserved |= 294 ((rdnss->AdvRDNSSOpenFlag)?ND_OPT_RDNSSI_FLAG_S:0); 295 296 rdnssinfo->nd_opt_rdnssi_lifetime = htonl(rdnss->AdvRDNSSLifetime); 297 298 memcpy(&rdnssinfo->nd_opt_rdnssi_addr1, &rdnss->AdvRDNSSAddr1, 299 sizeof(struct in6_addr)); 300 memcpy(&rdnssinfo->nd_opt_rdnssi_addr2, &rdnss->AdvRDNSSAddr2, 301 sizeof(struct in6_addr)); 302 memcpy(&rdnssinfo->nd_opt_rdnssi_addr3, &rdnss->AdvRDNSSAddr3, 303 sizeof(struct in6_addr)); 304 len += sizeof(*rdnssinfo) - (3-rdnss->AdvRDNSSNumber)*sizeof(struct in6_addr); 305 306 rdnss = rdnss->next; 307 } 308 309 /* 310 * add MTU option 311 */ 312 313 if (iface->AdvLinkMTU != 0) { 314 struct nd_opt_mtu *mtu; 315 316 mtu = (struct nd_opt_mtu *) (buff + len); 317 318 mtu->nd_opt_mtu_type = ND_OPT_MTU; 319 mtu->nd_opt_mtu_len = 1; 320 mtu->nd_opt_mtu_reserved = 0; 321 mtu->nd_opt_mtu_mtu = htonl(iface->AdvLinkMTU); 322 323 len += sizeof(*mtu); 324 } 325 326 /* 327 * add Source Link-layer Address option 328 */ 329 330 if (iface->AdvSourceLLAddress && iface->if_hwaddr_len != -1) 331 { 332 uint8_t *ucp; 333 unsigned int i; 334 335 ucp = (uint8_t *) (buff + len); 336 337 *ucp++ = ND_OPT_SOURCE_LINKADDR; 338 *ucp++ = (uint8_t) ((iface->if_hwaddr_len + 16 + 63) >> 6); 339 340 len += 2 * sizeof(uint8_t); 341 342 i = (iface->if_hwaddr_len + 7) >> 3; 343 memcpy(buff + len, iface->if_hwaddr, i); 344 len += i; 345 } 346 347 /* 348 * Mobile IPv6 ext: Advertisement Interval Option to support 349 * movement detection of mobile nodes 350 */ 351 352 if(iface->AdvIntervalOpt) 353 { 354 struct AdvInterval a_ival; 355 uint32_t ival; 356 if(iface->MaxRtrAdvInterval < Cautious_MaxRtrAdvInterval){ 357 ival = ((iface->MaxRtrAdvInterval + 358 Cautious_MaxRtrAdvInterval_Leeway ) * 1000); 359 360 } 361 else { 362 ival = (iface->MaxRtrAdvInterval * 1000); 363 } 364 a_ival.type = ND_OPT_RTR_ADV_INTERVAL; 365 a_ival.length = 1; 366 a_ival.reserved = 0; 367 a_ival.adv_ival = htonl(ival); 368 369 memcpy(buff + len, &a_ival, sizeof(a_ival)); 370 len += sizeof(a_ival); 371 } 372 373 /* 374 * Mobile IPv6 ext: Home Agent Information Option to support 375 * Dynamic Home Agent Address Discovery 376 */ 377 378 if(iface->AdvHomeAgentInfo && 379 (iface->AdvMobRtrSupportFlag || iface->HomeAgentPreference != 0 || 380 iface->HomeAgentLifetime != iface->AdvDefaultLifetime)) 381 382 { 383 struct HomeAgentInfo ha_info; 384 ha_info.type = ND_OPT_HOME_AGENT_INFO; 385 ha_info.length = 1; 386 ha_info.flags_reserved = 387 (iface->AdvMobRtrSupportFlag)?ND_OPT_HAI_FLAG_SUPPORT_MR:0; 388 ha_info.preference = htons(iface->HomeAgentPreference); 389 ha_info.lifetime = htons(iface->HomeAgentLifetime); 390 391 memcpy(buff + len, &ha_info, sizeof(ha_info)); 392 len += sizeof(ha_info); 393 } 394 395 iov.iov_len = len; 396 iov.iov_base = (caddr_t) buff; 397 398 memset(chdr, 0, sizeof(chdr)); 399 cmsg = (struct cmsghdr *) chdr; 400 401 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 402 cmsg->cmsg_level = IPPROTO_IPV6; 403 cmsg->cmsg_type = IPV6_PKTINFO; 404 405 pkt_info = (struct in6_pktinfo *)CMSG_DATA(cmsg); 406 pkt_info->ipi6_ifindex = iface->if_index; 407 memcpy(&pkt_info->ipi6_addr, &iface->if_addr, sizeof(struct in6_addr)); 408 409#ifdef HAVE_SIN6_SCOPE_ID 410 if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr) || 411 IN6_IS_ADDR_MC_LINKLOCAL(&addr.sin6_addr)) 412 addr.sin6_scope_id = iface->if_index; 413#endif 414 415 memset(&mhdr, 0, sizeof(mhdr)); 416 mhdr.msg_name = (caddr_t)&addr; 417 mhdr.msg_namelen = sizeof(struct sockaddr_in6); 418 mhdr.msg_iov = &iov; 419 mhdr.msg_iovlen = 1; 420 mhdr.msg_control = (void *) cmsg; 421 mhdr.msg_controllen = sizeof(chdr); 422 423 err = sendmsg(sock, &mhdr, 0); 424 425 if (err < 0) { 426 if (!iface->IgnoreIfMissing || !(errno == EINVAL || errno == ENODEV)) 427 flog(LOG_WARNING, "sendmsg: %s", strerror(errno)); 428 else 429 dlog(LOG_DEBUG, 3, "sendmsg: %s", strerror(errno)); 430 } 431} 432