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 96 /* First we need to check that the interface hasn't been removed or deactivated */ 97 if(check_device(sock, iface) < 0) { 98 if (iface->IgnoreIfMissing) /* a bit more quiet warning message.. */ 99 dlog(LOG_DEBUG, 4, "interface %s does not exist, ignoring the interface", iface->Name); 100 else { 101 flog(LOG_WARNING, "interface %s does not exist, ignoring the interface", iface->Name); 102 } 103 iface->HasFailed = 1; 104 } else { 105 /* check_device was successful, act if it has failed previously */ 106 if (iface->HasFailed == 1) { 107 flog(LOG_WARNING, "interface %s seems to have come back up, trying to reinitialize", iface->Name); 108 iface->HasFailed = 0; 109 /* XXX: reinitializes 'iface', so this probably isn't going to work until next send_ra().. */ 110 reload_config(); 111 } 112 } 113 114 /* Make sure that we've joined the all-routers multicast group */ 115 if (check_allrouters_membership(sock, iface) < 0) 116 flog(LOG_WARNING, "problem checking all-routers membership on %s", iface->Name); 117 118 dlog(LOG_DEBUG, 3, "sending RA on %s", iface->Name); 119 120 /* Foxconn modified start pling 09/01/2010 */ 121 /* IPv6 Self Test v5.0.0 always assume the RA is multicast */ 122 //if ((dest == NULL) || 123 // ( (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 */ 124 if (1) 125 /* Foxconn modified end pling 09/01/2010 */ 126 { 127 struct timeval tv; 128 129 dest = (struct in6_addr *)all_hosts_addr; 130 gettimeofday(&tv, NULL); 131 132 iface->last_multicast_sec = tv.tv_sec; 133 iface->last_multicast_usec = tv.tv_usec; 134 } 135 136 memset((void *)&addr, 0, sizeof(addr)); 137 addr.sin6_family = AF_INET6; 138 addr.sin6_port = htons(IPPROTO_ICMPV6); 139 memcpy(&addr.sin6_addr, dest, sizeof(struct in6_addr)); 140 141 memset(&buff, 0, sizeof(buff)); 142 radvert = (struct nd_router_advert *) buff; 143 144 radvert->nd_ra_type = ND_ROUTER_ADVERT; 145 radvert->nd_ra_code = 0; 146 radvert->nd_ra_cksum = 0; 147 148 radvert->nd_ra_curhoplimit = iface->AdvCurHopLimit; 149 radvert->nd_ra_flags_reserved = 150 (iface->AdvManagedFlag)?ND_RA_FLAG_MANAGED:0; 151 radvert->nd_ra_flags_reserved |= 152 (iface->AdvOtherConfigFlag)?ND_RA_FLAG_OTHER:0; 153 /* Mobile IPv6 ext */ 154 radvert->nd_ra_flags_reserved |= 155 (iface->AdvHomeAgentFlag)?ND_RA_FLAG_HOME_AGENT:0; 156 157 /* if forwarding is disabled, send zero router lifetime */ 158 radvert->nd_ra_router_lifetime = !check_ip6_forwarding() ? htons(iface->AdvDefaultLifetime) : 0; 159 radvert->nd_ra_flags_reserved |= 160 (iface->AdvDefaultPreference << ND_OPT_RI_PRF_SHIFT) & ND_OPT_RI_PRF_MASK; 161 162 radvert->nd_ra_reachable = htonl(iface->AdvReachableTime); 163 radvert->nd_ra_retransmit = htonl(iface->AdvRetransTimer); 164 165 len = sizeof(struct nd_router_advert); 166 167 prefix = iface->AdvPrefixList; 168 169 /* 170 * add prefix options 171 */ 172 173 while(prefix) 174 { 175 /* Foxconn Perry added start, 2011/05/13, for IPv6 obsolete prefix information */ 176 /* Router advertisment should not have obsolete prefix information for nornam RA */ 177 if(iface->init_racount>=MAX_INITIAL_RTR_ADVERTISEMENTS && htonl(prefix->AdvValidLifetime)==0) 178 { 179 prefix = prefix->next; 180 continue; 181 } 182 /* Foxconn Perry added end, 2011/05/13, for IPv6 obsolete prefix information */ 183 184 if( prefix->enabled ) 185 { 186 struct nd_opt_prefix_info *pinfo; 187 188 pinfo = (struct nd_opt_prefix_info *) (buff + len); 189 190 pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 191 pinfo->nd_opt_pi_len = 4; 192 pinfo->nd_opt_pi_prefix_len = prefix->PrefixLen; 193 194 pinfo->nd_opt_pi_flags_reserved = 195 (prefix->AdvOnLinkFlag)?ND_OPT_PI_FLAG_ONLINK:0; 196 pinfo->nd_opt_pi_flags_reserved |= 197 (prefix->AdvAutonomousFlag)?ND_OPT_PI_FLAG_AUTO:0; 198 /* Mobile IPv6 ext */ 199 pinfo->nd_opt_pi_flags_reserved |= 200 (prefix->AdvRouterAddr)?ND_OPT_PI_FLAG_RADDR:0; 201 202 pinfo->nd_opt_pi_valid_time = htonl(prefix->AdvValidLifetime); 203 /* Foxconn added start pling 12/22/2011 */ 204 /* Advertise the remaining lifetime (in DHCP mode) */ 205 if (use_dynamic_lifetime) { 206 sec_since_initial_advert = get_current_time() - initial_advert_time; 207 if (sec_since_initial_advert >= prefix->AdvValidLifetime) { 208 /* prefix expired, do not advertise */ 209 prefix = prefix->next; 210 continue; 211 } 212 /* Advertise the remaining lifetime */ 213 remain_lifetime = prefix->AdvValidLifetime - sec_since_initial_advert; 214 pinfo->nd_opt_pi_valid_time = htonl(remain_lifetime); 215 } 216 /* Foxconn added end pling 12/22/2011 */ 217 218 pinfo->nd_opt_pi_preferred_time = htonl(prefix->AdvPreferredLifetime); 219 /* Foxconn added start pling 12/29/2011 */ 220 /* Modify the "preferred lifetime" behaviour per Netgear request */ 221 if (use_dynamic_lifetime) { 222 if (sec_since_initial_advert >= prefix->AdvPreferredLifetime) 223 pinfo->nd_opt_pi_preferred_time = htonl(0); 224 else { 225 remain_lifetime = prefix->AdvPreferredLifetime - sec_since_initial_advert; 226 pinfo->nd_opt_pi_preferred_time = htonl(remain_lifetime); 227 } 228 } 229 /* Foxconn added end pling 12/29/2011 */ 230 231 pinfo->nd_opt_pi_reserved2 = 0; 232 233 memcpy(&pinfo->nd_opt_pi_prefix, &prefix->Prefix, 234 sizeof(struct in6_addr)); 235 236 len += sizeof(*pinfo); 237 } 238 239 prefix = prefix->next; 240 } 241 242 route = iface->AdvRouteList; 243 244 /* 245 * add route options 246 */ 247 248 while(route) 249 { 250 struct nd_opt_route_info_local *rinfo; 251 252 rinfo = (struct nd_opt_route_info_local *) (buff + len); 253 254 rinfo->nd_opt_ri_type = ND_OPT_ROUTE_INFORMATION; 255 /* XXX: the prefixes are allowed to be sent in smaller chunks as well */ 256 rinfo->nd_opt_ri_len = 3; 257 rinfo->nd_opt_ri_prefix_len = route->PrefixLen; 258 259 rinfo->nd_opt_ri_flags_reserved = 260 (route->AdvRoutePreference << ND_OPT_RI_PRF_SHIFT) & ND_OPT_RI_PRF_MASK; 261 rinfo->nd_opt_ri_lifetime = htonl(route->AdvRouteLifetime); 262 263 memcpy(&rinfo->nd_opt_ri_prefix, &route->Prefix, 264 sizeof(struct in6_addr)); 265 len += sizeof(*rinfo); 266 267 route = route->next; 268 } 269 270 rdnss = iface->AdvRDNSSList; 271 272 /* 273 * add rdnss options 274 */ 275 276 while(rdnss) 277 { 278 struct nd_opt_rdnss_info_local *rdnssinfo; 279 280 rdnssinfo = (struct nd_opt_rdnss_info_local *) (buff + len); 281 282 rdnssinfo->nd_opt_rdnssi_type = ND_OPT_RDNSS_INFORMATION; 283 rdnssinfo->nd_opt_rdnssi_len = 1 + 2*rdnss->AdvRDNSSNumber; 284 rdnssinfo->nd_opt_rdnssi_pref_flag_reserved = 285 ((rdnss->AdvRDNSSPreference << ND_OPT_RDNSSI_PREF_SHIFT) & ND_OPT_RDNSSI_PREF_MASK); 286 rdnssinfo->nd_opt_rdnssi_pref_flag_reserved |= 287 ((rdnss->AdvRDNSSOpenFlag)?ND_OPT_RDNSSI_FLAG_S:0); 288 289 rdnssinfo->nd_opt_rdnssi_lifetime = htonl(rdnss->AdvRDNSSLifetime); 290 291 memcpy(&rdnssinfo->nd_opt_rdnssi_addr1, &rdnss->AdvRDNSSAddr1, 292 sizeof(struct in6_addr)); 293 memcpy(&rdnssinfo->nd_opt_rdnssi_addr2, &rdnss->AdvRDNSSAddr2, 294 sizeof(struct in6_addr)); 295 memcpy(&rdnssinfo->nd_opt_rdnssi_addr3, &rdnss->AdvRDNSSAddr3, 296 sizeof(struct in6_addr)); 297 len += sizeof(*rdnssinfo) - (3-rdnss->AdvRDNSSNumber)*sizeof(struct in6_addr); 298 299 rdnss = rdnss->next; 300 } 301 302 /* 303 * add MTU option 304 */ 305 306 if (iface->AdvLinkMTU != 0) { 307 struct nd_opt_mtu *mtu; 308 309 mtu = (struct nd_opt_mtu *) (buff + len); 310 311 mtu->nd_opt_mtu_type = ND_OPT_MTU; 312 mtu->nd_opt_mtu_len = 1; 313 mtu->nd_opt_mtu_reserved = 0; 314 mtu->nd_opt_mtu_mtu = htonl(iface->AdvLinkMTU); 315 316 len += sizeof(*mtu); 317 } 318 319 /* 320 * add Source Link-layer Address option 321 */ 322 323 if (iface->AdvSourceLLAddress && iface->if_hwaddr_len != -1) 324 { 325 uint8_t *ucp; 326 unsigned int i; 327 328 ucp = (uint8_t *) (buff + len); 329 330 *ucp++ = ND_OPT_SOURCE_LINKADDR; 331 *ucp++ = (uint8_t) ((iface->if_hwaddr_len + 16 + 63) >> 6); 332 333 len += 2 * sizeof(uint8_t); 334 335 i = (iface->if_hwaddr_len + 7) >> 3; 336 memcpy(buff + len, iface->if_hwaddr, i); 337 len += i; 338 } 339 340 /* 341 * Mobile IPv6 ext: Advertisement Interval Option to support 342 * movement detection of mobile nodes 343 */ 344 345 if(iface->AdvIntervalOpt) 346 { 347 struct AdvInterval a_ival; 348 uint32_t ival; 349 if(iface->MaxRtrAdvInterval < Cautious_MaxRtrAdvInterval){ 350 ival = ((iface->MaxRtrAdvInterval + 351 Cautious_MaxRtrAdvInterval_Leeway ) * 1000); 352 353 } 354 else { 355 ival = (iface->MaxRtrAdvInterval * 1000); 356 } 357 a_ival.type = ND_OPT_RTR_ADV_INTERVAL; 358 a_ival.length = 1; 359 a_ival.reserved = 0; 360 a_ival.adv_ival = htonl(ival); 361 362 memcpy(buff + len, &a_ival, sizeof(a_ival)); 363 len += sizeof(a_ival); 364 } 365 366 /* 367 * Mobile IPv6 ext: Home Agent Information Option to support 368 * Dynamic Home Agent Address Discovery 369 */ 370 371 if(iface->AdvHomeAgentInfo && 372 (iface->AdvMobRtrSupportFlag || iface->HomeAgentPreference != 0 || 373 iface->HomeAgentLifetime != iface->AdvDefaultLifetime)) 374 375 { 376 struct HomeAgentInfo ha_info; 377 ha_info.type = ND_OPT_HOME_AGENT_INFO; 378 ha_info.length = 1; 379 ha_info.flags_reserved = 380 (iface->AdvMobRtrSupportFlag)?ND_OPT_HAI_FLAG_SUPPORT_MR:0; 381 ha_info.preference = htons(iface->HomeAgentPreference); 382 ha_info.lifetime = htons(iface->HomeAgentLifetime); 383 384 memcpy(buff + len, &ha_info, sizeof(ha_info)); 385 len += sizeof(ha_info); 386 } 387 388 iov.iov_len = len; 389 iov.iov_base = (caddr_t) buff; 390 391 memset(chdr, 0, sizeof(chdr)); 392 cmsg = (struct cmsghdr *) chdr; 393 394 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 395 cmsg->cmsg_level = IPPROTO_IPV6; 396 cmsg->cmsg_type = IPV6_PKTINFO; 397 398 pkt_info = (struct in6_pktinfo *)CMSG_DATA(cmsg); 399 pkt_info->ipi6_ifindex = iface->if_index; 400 memcpy(&pkt_info->ipi6_addr, &iface->if_addr, sizeof(struct in6_addr)); 401 402#ifdef HAVE_SIN6_SCOPE_ID 403 if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr) || 404 IN6_IS_ADDR_MC_LINKLOCAL(&addr.sin6_addr)) 405 addr.sin6_scope_id = iface->if_index; 406#endif 407 408 memset(&mhdr, 0, sizeof(mhdr)); 409 mhdr.msg_name = (caddr_t)&addr; 410 mhdr.msg_namelen = sizeof(struct sockaddr_in6); 411 mhdr.msg_iov = &iov; 412 mhdr.msg_iovlen = 1; 413 mhdr.msg_control = (void *) cmsg; 414 mhdr.msg_controllen = sizeof(chdr); 415 416 err = sendmsg(sock, &mhdr, 0); 417 418 if (err < 0) { 419 if (!iface->IgnoreIfMissing || !(errno == EINVAL || errno == ENODEV)) 420 flog(LOG_WARNING, "sendmsg: %s", strerror(errno)); 421 else 422 dlog(LOG_DEBUG, 3, "sendmsg: %s", strerror(errno)); 423 } 424} 425