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
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