2 * $Id: send.c,v 1.48 2011/05/06 07:51:54 reubenhwk Exp $
5 * Pedro Roque <roque@di.fc.ul.pt>
6 * Lars Fenneberg <lf@elemental.net>
8 * This software is Copyright 1996,1997 by the above mentioned author(s),
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>.
22 * Sends an advertisement for all specified clients of this interface
23 * (or via broadcast, if there are no restrictions configured).
25 * If a destination address is given, the RA will be sent to the destination
26 * address only, but only if it was configured.
30 send_ra_forall(struct Interface
*iface
, struct in6_addr
*dest
)
32 struct Clients
*current
;
34 /* If no list of clients was specified for this interface, we broadcast */
35 if (iface
->ClientList
== NULL
)
36 return send_ra(iface
, dest
);
38 /* If clients are configured, send the advertisement to all of them via unicast */
39 for (current
= iface
->ClientList
; current
; current
= current
->next
)
41 char address_text
[INET6_ADDRSTRLEN
];
42 memset(address_text
, 0, sizeof(address_text
));
43 if (get_debuglevel() >= 5)
44 inet_ntop(AF_INET6
, ¤t
->Address
, address_text
, INET6_ADDRSTRLEN
);
46 /* If a non-authorized client sent a solicitation, ignore it (logging later) */
47 if (dest
!= NULL
&& memcmp(dest
, ¤t
->Address
, sizeof(struct in6_addr
)) != 0)
49 dlog(LOG_DEBUG
, 5, "Sending RA to %s", address_text
);
50 send_ra(iface
, &(current
->Address
));
52 /* If we should only send the RA to a specific address, we are done */
59 /* If we refused a client's solicitation, log it if debugging is high enough */
60 char address_text
[INET6_ADDRSTRLEN
];
61 memset(address_text
, 0, sizeof(address_text
));
62 if (get_debuglevel() >= 5)
63 inet_ntop(AF_INET6
, dest
, address_text
, INET6_ADDRSTRLEN
);
65 dlog(LOG_DEBUG
, 5, "Not answering request from %s, not configured", address_text
);
70 send_ra_inc_len(size_t *len
, int add
)
73 if(*len
>= MSG_SIZE_SEND
)
75 flog(LOG_ERR
, "Too many prefixes or routes. Exiting.");
81 time_diff_secs(const struct timeval
*time_x
, const struct timeval
*time_y
)
85 secs_diff
= time_x
->tv_sec
- time_y
->tv_sec
;
86 if ((time_x
->tv_usec
- time_y
->tv_usec
) >= 500000)
94 decrement_lifetime(const time_t secs
, uint32_t *lifetime
)
97 if (*lifetime
> secs
) {
104 static void cease_adv_pfx_msg(const char *if_name
, struct in6_addr
*pfx
, const int pfx_len
)
106 char pfx_str
[INET6_ADDRSTRLEN
];
108 print_addr(pfx
, pfx_str
);
110 dlog(LOG_DEBUG
, 3, "Will cease advertising %s/%u%%%s, preferred lifetime is 0", pfx_str
, pfx_len
, if_name
);
115 send_ra(struct Interface
*iface
, struct in6_addr
*dest
)
117 uint8_t all_hosts_addr
[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
118 struct sockaddr_in6 addr
;
119 struct in6_pktinfo
*pkt_info
;
121 struct cmsghdr
*cmsg
;
123 char __attribute__((aligned(8))) chdr
[CMSG_SPACE(sizeof(struct in6_pktinfo
))];
124 struct nd_router_advert
*radvert
;
125 struct AdvPrefix
*prefix
;
126 struct AdvRoute
*route
;
127 struct AdvRDNSS
*rdnss
;
128 struct AdvDNSSL
*dnssl
;
129 struct timeval time_now
;
130 time_t secs_since_last_ra
;
132 unsigned char buff
[MSG_SIZE_SEND
];
136 /* First we need to check that the interface hasn't been removed or deactivated */
137 if(check_device(iface
) < 0) {
138 if (iface
->IgnoreIfMissing
) /* a bit more quiet warning message.. */
139 dlog(LOG_DEBUG
, 4, "interface %s does not exist, ignoring the interface", iface
->Name
);
141 flog(LOG_WARNING
, "interface %s does not exist, ignoring the interface", iface
->Name
);
143 iface
->HasFailed
= 1;
144 /* not really a 'success', but we need to schedule new timers.. */
147 /* check_device was successful, act if it has failed previously */
148 if (iface
->HasFailed
== 1) {
149 flog(LOG_WARNING
, "interface %s seems to have come back up, trying to reinitialize", iface
->Name
);
150 iface
->HasFailed
= 0;
152 * return -1 so timer_handler() doesn't schedule new timers,
153 * reload_config() will kick off new timers anyway. This avoids
154 * timer list corruption.
161 /* Make sure that we've joined the all-routers multicast group */
162 if (check_allrouters_membership(iface
) < 0)
163 flog(LOG_WARNING
, "problem checking all-routers membership on %s", iface
->Name
);
165 dlog(LOG_DEBUG
, 3, "sending RA on %s", iface
->Name
);
169 dest
= (struct in6_addr
*)all_hosts_addr
;
170 gettimeofday(&iface
->last_multicast
, NULL
);
173 gettimeofday(&time_now
, NULL
);
174 secs_since_last_ra
= time_diff_secs(&time_now
, &iface
->last_ra_time
);
175 if (secs_since_last_ra
< 0) {
176 secs_since_last_ra
= 0;
177 flog(LOG_WARNING
, "gettimeofday() went backwards!");
179 iface
->last_ra_time
= time_now
;
181 memset((void *)&addr
, 0, sizeof(addr
));
182 addr
.sin6_family
= AF_INET6
;
183 addr
.sin6_port
= htons(IPPROTO_ICMPV6
);
184 memcpy(&addr
.sin6_addr
, dest
, sizeof(struct in6_addr
));
186 memset(buff
, 0, sizeof(buff
));
187 radvert
= (struct nd_router_advert
*) buff
;
189 radvert
->nd_ra_type
= ND_ROUTER_ADVERT
;
190 radvert
->nd_ra_code
= 0;
191 radvert
->nd_ra_cksum
= 0;
193 radvert
->nd_ra_curhoplimit
= iface
->AdvCurHopLimit
;
194 radvert
->nd_ra_flags_reserved
=
195 (iface
->AdvManagedFlag
)?ND_RA_FLAG_MANAGED
:0;
196 radvert
->nd_ra_flags_reserved
|=
197 (iface
->AdvOtherConfigFlag
)?ND_RA_FLAG_OTHER
:0;
198 /* Mobile IPv6 ext */
199 radvert
->nd_ra_flags_reserved
|=
200 (iface
->AdvHomeAgentFlag
)?ND_RA_FLAG_HOME_AGENT
:0;
202 if (iface
->cease_adv
) {
203 radvert
->nd_ra_router_lifetime
= 0;
205 /* if forwarding is disabled, send zero router lifetime */
206 radvert
->nd_ra_router_lifetime
= !check_ip6_forwarding() ? htons(iface
->AdvDefaultLifetime
) : 0;
208 radvert
->nd_ra_flags_reserved
|=
209 (iface
->AdvDefaultPreference
<< ND_OPT_RI_PRF_SHIFT
) & ND_OPT_RI_PRF_MASK
;
211 radvert
->nd_ra_reachable
= htonl(iface
->AdvReachableTime
);
212 radvert
->nd_ra_retransmit
= htonl(iface
->AdvRetransTimer
);
214 len
= sizeof(struct nd_router_advert
);
216 prefix
= iface
->AdvPrefixList
;
224 if( prefix
->enabled
&& prefix
->curr_preferredlft
> 0 )
226 struct nd_opt_prefix_info
*pinfo
;
228 pinfo
= (struct nd_opt_prefix_info
*) (buff
+ len
);
230 pinfo
->nd_opt_pi_type
= ND_OPT_PREFIX_INFORMATION
;
231 pinfo
->nd_opt_pi_len
= 4;
232 pinfo
->nd_opt_pi_prefix_len
= prefix
->PrefixLen
;
234 pinfo
->nd_opt_pi_flags_reserved
=
235 (prefix
->AdvOnLinkFlag
)?ND_OPT_PI_FLAG_ONLINK
:0;
236 pinfo
->nd_opt_pi_flags_reserved
|=
237 (prefix
->AdvAutonomousFlag
)?ND_OPT_PI_FLAG_AUTO
:0;
238 /* Mobile IPv6 ext */
239 pinfo
->nd_opt_pi_flags_reserved
|=
240 (prefix
->AdvRouterAddr
)?ND_OPT_PI_FLAG_RADDR
:0;
242 if (iface
->cease_adv
&& prefix
->DeprecatePrefixFlag
) {
243 /* RFC4862, 5.5.3, step e) */
244 pinfo
->nd_opt_pi_valid_time
= htonl(MIN_AdvValidLifetime
);
245 pinfo
->nd_opt_pi_preferred_time
= 0;
247 if (prefix
->DecrementLifetimesFlag
) {
248 decrement_lifetime(secs_since_last_ra
,
249 &prefix
->curr_validlft
);
251 decrement_lifetime(secs_since_last_ra
,
252 &prefix
->curr_preferredlft
);
253 if (prefix
->curr_preferredlft
== 0)
254 cease_adv_pfx_msg(iface
->Name
, &prefix
->Prefix
, prefix
->PrefixLen
);
256 pinfo
->nd_opt_pi_valid_time
= htonl(prefix
->curr_validlft
);
257 pinfo
->nd_opt_pi_preferred_time
= htonl(prefix
->curr_preferredlft
);
260 pinfo
->nd_opt_pi_reserved2
= 0;
262 memcpy(&pinfo
->nd_opt_pi_prefix
, &prefix
->Prefix
,
263 sizeof(struct in6_addr
));
265 send_ra_inc_len(&len
, sizeof(*pinfo
));
268 prefix
= prefix
->next
;
271 route
= iface
->AdvRouteList
;
279 struct nd_opt_route_info_local
*rinfo
;
281 rinfo
= (struct nd_opt_route_info_local
*) (buff
+ len
);
283 rinfo
->nd_opt_ri_type
= ND_OPT_ROUTE_INFORMATION
;
284 /* XXX: the prefixes are allowed to be sent in smaller chunks as well */
285 rinfo
->nd_opt_ri_len
= 3;
286 rinfo
->nd_opt_ri_prefix_len
= route
->PrefixLen
;
288 rinfo
->nd_opt_ri_flags_reserved
=
289 (route
->AdvRoutePreference
<< ND_OPT_RI_PRF_SHIFT
) & ND_OPT_RI_PRF_MASK
;
290 if (iface
->cease_adv
&& route
->RemoveRouteFlag
) {
291 rinfo
->nd_opt_ri_lifetime
= 0;
293 rinfo
->nd_opt_ri_lifetime
= htonl(route
->AdvRouteLifetime
);
296 memcpy(&rinfo
->nd_opt_ri_prefix
, &route
->Prefix
,
297 sizeof(struct in6_addr
));
298 send_ra_inc_len(&len
, sizeof(*rinfo
));
303 rdnss
= iface
->AdvRDNSSList
;
311 struct nd_opt_rdnss_info_local
*rdnssinfo
;
313 rdnssinfo
= (struct nd_opt_rdnss_info_local
*) (buff
+ len
);
315 rdnssinfo
->nd_opt_rdnssi_type
= ND_OPT_RDNSS_INFORMATION
;
316 rdnssinfo
->nd_opt_rdnssi_len
= 1 + 2*rdnss
->AdvRDNSSNumber
;
317 rdnssinfo
->nd_opt_rdnssi_pref_flag_reserved
= 0;
319 if (iface
->cease_adv
&& rdnss
->FlushRDNSSFlag
) {
320 rdnssinfo
->nd_opt_rdnssi_lifetime
= 0;
322 rdnssinfo
->nd_opt_rdnssi_lifetime
= htonl(rdnss
->AdvRDNSSLifetime
);
325 memcpy(&rdnssinfo
->nd_opt_rdnssi_addr1
, &rdnss
->AdvRDNSSAddr1
,
326 sizeof(struct in6_addr
));
327 memcpy(&rdnssinfo
->nd_opt_rdnssi_addr2
, &rdnss
->AdvRDNSSAddr2
,
328 sizeof(struct in6_addr
));
329 memcpy(&rdnssinfo
->nd_opt_rdnssi_addr3
, &rdnss
->AdvRDNSSAddr3
,
330 sizeof(struct in6_addr
));
331 send_ra_inc_len(&len
, sizeof(*rdnssinfo
) - (3-rdnss
->AdvRDNSSNumber
)*sizeof(struct in6_addr
));
336 dnssl
= iface
->AdvDNSSLList
;
344 struct nd_opt_dnssl_info_local
*dnsslinfo
;
348 dnsslinfo
= (struct nd_opt_dnssl_info_local
*) (buff
+ len
);
350 dnsslinfo
->nd_opt_dnssli_type
= ND_OPT_DNSSL_INFORMATION
;
351 dnsslinfo
->nd_opt_dnssli_len
= 1; /* more further down */
352 dnsslinfo
->nd_opt_dnssli_reserved
= 0;
354 if (iface
->cease_adv
&& dnssl
->FlushDNSSLFlag
) {
355 dnsslinfo
->nd_opt_dnssli_lifetime
= 0;
357 dnsslinfo
->nd_opt_dnssli_lifetime
= htonl(dnssl
->AdvDNSSLLifetime
);
360 buff_ptr
= dnsslinfo
->nd_opt_dnssli_suffixes
;
361 for (i
= 0; i
< dnssl
->AdvDNSSLNumber
; i
++) {
365 label
= dnssl
->AdvDNSSLSuffixes
[i
];
367 while (label
[0] != '\0') {
368 if (strchr(label
, '.') == NULL
)
369 label_len
= strlen(label
);
371 label_len
= strchr(label
, '.') - label
;
373 *buff_ptr
++ = label_len
;
375 memcpy(buff_ptr
, label
, label_len
);
376 buff_ptr
+= label_len
;
387 dnsslinfo
->nd_opt_dnssli_len
+= ((buff_ptr
-dnsslinfo
->nd_opt_dnssli_suffixes
)+7)/8;
389 send_ra_inc_len(&len
, dnsslinfo
->nd_opt_dnssli_len
* 8);
398 if (iface
->AdvLinkMTU
!= 0) {
399 struct nd_opt_mtu
*mtu
;
401 mtu
= (struct nd_opt_mtu
*) (buff
+ len
);
403 mtu
->nd_opt_mtu_type
= ND_OPT_MTU
;
404 mtu
->nd_opt_mtu_len
= 1;
405 mtu
->nd_opt_mtu_reserved
= 0;
406 mtu
->nd_opt_mtu_mtu
= htonl(iface
->AdvLinkMTU
);
408 send_ra_inc_len(&len
, sizeof(*mtu
));
412 * add Source Link-layer Address option
415 if (iface
->AdvSourceLLAddress
&& iface
->if_hwaddr_len
> 0)
420 ucp
= (uint8_t *) (buff
+ len
);
422 *ucp
++ = ND_OPT_SOURCE_LINKADDR
;
423 *ucp
++ = (uint8_t) ((iface
->if_hwaddr_len
+ 16 + 63) >> 6);
425 send_ra_inc_len(&len
, 2 * sizeof(uint8_t));
427 i
= (iface
->if_hwaddr_len
+ 7) >> 3;
428 memcpy(buff
+ len
, iface
->if_hwaddr
, i
);
429 send_ra_inc_len(&len
, i
);
433 * Mobile IPv6 ext: Advertisement Interval Option to support
434 * movement detection of mobile nodes
437 if(iface
->AdvIntervalOpt
)
439 struct AdvInterval a_ival
;
441 if(iface
->MaxRtrAdvInterval
< Cautious_MaxRtrAdvInterval
){
442 ival
= ((iface
->MaxRtrAdvInterval
+
443 Cautious_MaxRtrAdvInterval_Leeway
) * 1000);
447 ival
= (iface
->MaxRtrAdvInterval
* 1000);
449 a_ival
.type
= ND_OPT_RTR_ADV_INTERVAL
;
452 a_ival
.adv_ival
= htonl(ival
);
454 memcpy(buff
+ len
, &a_ival
, sizeof(a_ival
));
455 send_ra_inc_len(&len
, sizeof(a_ival
));
459 * Mobile IPv6 ext: Home Agent Information Option to support
460 * Dynamic Home Agent Address Discovery
463 if(iface
->AdvHomeAgentInfo
&&
464 (iface
->AdvMobRtrSupportFlag
|| iface
->HomeAgentPreference
!= 0 ||
465 iface
->HomeAgentLifetime
!= iface
->AdvDefaultLifetime
))
468 struct HomeAgentInfo ha_info
;
469 ha_info
.type
= ND_OPT_HOME_AGENT_INFO
;
471 ha_info
.flags_reserved
=
472 (iface
->AdvMobRtrSupportFlag
)?ND_OPT_HAI_FLAG_SUPPORT_MR
:0;
473 ha_info
.preference
= htons(iface
->HomeAgentPreference
);
474 ha_info
.lifetime
= htons(iface
->HomeAgentLifetime
);
476 memcpy(buff
+ len
, &ha_info
, sizeof(ha_info
));
477 send_ra_inc_len(&len
, sizeof(ha_info
));
481 iov
.iov_base
= (caddr_t
) buff
;
483 memset(chdr
, 0, sizeof(chdr
));
484 cmsg
= (struct cmsghdr
*) chdr
;
486 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
487 cmsg
->cmsg_level
= IPPROTO_IPV6
;
488 cmsg
->cmsg_type
= IPV6_PKTINFO
;
490 pkt_info
= (struct in6_pktinfo
*)CMSG_DATA(cmsg
);
491 pkt_info
->ipi6_ifindex
= iface
->if_index
;
492 memcpy(&pkt_info
->ipi6_addr
, &iface
->if_addr
, sizeof(struct in6_addr
));
494 #ifdef HAVE_SIN6_SCOPE_ID
495 if (IN6_IS_ADDR_LINKLOCAL(&addr
.sin6_addr
) ||
496 IN6_IS_ADDR_MC_LINKLOCAL(&addr
.sin6_addr
))
497 addr
.sin6_scope_id
= iface
->if_index
;
500 memset(&mhdr
, 0, sizeof(mhdr
));
501 mhdr
.msg_name
= (caddr_t
)&addr
;
502 mhdr
.msg_namelen
= sizeof(struct sockaddr_in6
);
505 mhdr
.msg_control
= (void *) cmsg
;
506 mhdr
.msg_controllen
= sizeof(chdr
);
508 err
= sendmsg(sock
, &mhdr
, 0);
511 if (!iface
->IgnoreIfMissing
|| !(errno
== EINVAL
|| errno
== ENODEV
))
512 flog(LOG_WARNING
, "sendmsg: %s", strerror(errno
));
514 dlog(LOG_DEBUG
, 3, "sendmsg: %s", strerror(errno
));