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, &current->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, &current->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