2 * $Id: send.c,v 1.12 2002/10/28 17:28:37 psavola 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 <lutchann@litech.org>.
22 send_ra(int sock, struct Interface *iface, struct in6_addr *dest)
24 uint8_t all_hosts_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
25 struct sockaddr_in6 addr;
26 struct in6_pktinfo *pkt_info;
30 char chdr[CMSG_SPACE(sizeof(struct in6_pktinfo))];
31 struct nd_router_advert *radvert;
32 struct AdvPrefix *prefix;
33 unsigned char buff[MSG_SIZE];
37 /* Make sure that we've joined the all-routers multicast group */
38 if (check_allrouters_membership(sock, iface) < 0)
39 log(LOG_WARNING, "problem checking all-routers membership on %s", iface->Name);
41 dlog(LOG_DEBUG, 3, "sending RA on %s", iface->Name);
47 dest = (struct in6_addr *)all_hosts_addr;
48 gettimeofday(&tv, NULL);
50 iface->last_multicast = tv.tv_sec;
53 memset((void *)&addr, 0, sizeof(addr));
54 addr.sin6_family = AF_INET6;
55 addr.sin6_port = htons(IPPROTO_ICMPV6);
56 memcpy(&addr.sin6_addr, dest, sizeof(struct in6_addr));
58 radvert = (struct nd_router_advert *) buff;
60 radvert->nd_ra_type = ND_ROUTER_ADVERT;
61 radvert->nd_ra_code = 0;
62 radvert->nd_ra_cksum = 0;
64 radvert->nd_ra_curhoplimit = iface->AdvCurHopLimit;
65 radvert->nd_ra_flags_reserved =
66 (iface->AdvManagedFlag)?ND_RA_FLAG_MANAGED:0;
67 radvert->nd_ra_flags_reserved |=
68 (iface->AdvOtherConfigFlag)?ND_RA_FLAG_OTHER:0;
70 radvert->nd_ra_flags_reserved |=
71 (iface->AdvHomeAgentFlag)?ND_RA_FLAG_HOME_AGENT:0;
73 radvert->nd_ra_router_lifetime = htons(iface->AdvDefaultLifetime);
75 radvert->nd_ra_reachable = htonl(iface->AdvReachableTime);
76 radvert->nd_ra_retransmit = htonl(iface->AdvRetransTimer);
78 len = sizeof(struct nd_router_advert);
80 prefix = iface->AdvPrefixList;
90 struct nd_opt_prefix_info *pinfo;
92 pinfo = (struct nd_opt_prefix_info *) (buff + len);
94 pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
95 pinfo->nd_opt_pi_len = 4;
96 pinfo->nd_opt_pi_prefix_len = prefix->PrefixLen;
98 pinfo->nd_opt_pi_flags_reserved =
99 (prefix->AdvOnLinkFlag)?ND_OPT_PI_FLAG_ONLINK:0;
100 pinfo->nd_opt_pi_flags_reserved |=
101 (prefix->AdvAutonomousFlag)?ND_OPT_PI_FLAG_AUTO:0;
102 /* Mobile IPv6 ext */
103 pinfo->nd_opt_pi_flags_reserved |=
104 (prefix->AdvRouterAddr)?ND_OPT_PI_FLAG_RADDR:0;
106 pinfo->nd_opt_pi_valid_time = htonl(prefix->AdvValidLifetime);
107 pinfo->nd_opt_pi_preferred_time = htonl(prefix->AdvPreferredLifetime);
108 pinfo->nd_opt_pi_reserved2 = 0;
110 memcpy(&pinfo->nd_opt_pi_prefix, &prefix->Prefix,
111 sizeof(struct in6_addr));
113 len += sizeof(*pinfo);
116 prefix = prefix->next;
123 if (iface->AdvLinkMTU != 0) {
124 struct nd_opt_mtu *mtu;
126 mtu = (struct nd_opt_mtu *) (buff + len);
128 mtu->nd_opt_mtu_type = ND_OPT_MTU;
129 mtu->nd_opt_mtu_len = 1;
130 mtu->nd_opt_mtu_reserved = 0;
131 mtu->nd_opt_mtu_mtu = htonl(iface->AdvLinkMTU);
137 * add Source Link-layer Address option
140 if (iface->AdvSourceLLAddress && iface->if_hwaddr_len != -1)
145 ucp = (uint8_t *) (buff + len);
147 *ucp++ = ND_OPT_SOURCE_LINKADDR;
148 *ucp++ = (uint8_t) ((iface->if_hwaddr_len + 16 + 63) >> 6);
150 len += 2 * sizeof(uint8_t);
152 i = (iface->if_hwaddr_len + 7) >> 3;
153 memcpy(buff + len, iface->if_hwaddr, i);
158 * Mobile IPv6 ext: Advertisement Interval Option to support
159 * movement detection of mobile nodes
162 if(iface->AdvIntervalOpt)
164 struct AdvInterval a_ival;
165 uint32_t ival = (iface->MaxRtrAdvInterval * 1000);
166 a_ival.type = ND_OPT_RTR_ADV_INTERVAL;
169 a_ival.adv_ival = htonl(ival);
171 memcpy(buff + len, &a_ival, sizeof(a_ival));
172 len += sizeof(a_ival);
176 * Mobile IPv6 ext: Home Agent Information Option to support
177 * Dynamic Home Agent Address Discovery
180 if(iface->AdvHomeAgentInfo && (iface->HomeAgentPreference != 0 ||
181 iface->HomeAgentLifetime != iface->AdvDefaultLifetime))
183 struct HomeAgentInfo ha_info;
184 ha_info.type = ND_OPT_HOME_AGENT_INFO;
186 ha_info.reserved = 0;
187 ha_info.preference = htons(iface->HomeAgentPreference);
188 ha_info.lifetime = htons(iface->HomeAgentLifetime);
190 memcpy(buff + len, &ha_info, sizeof(ha_info));
191 len += sizeof(ha_info);
195 iov.iov_base = (caddr_t) buff;
197 memset(chdr, 0, sizeof(chdr));
198 cmsg = (struct cmsghdr *) chdr;
200 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
201 cmsg->cmsg_level = IPPROTO_IPV6;
202 cmsg->cmsg_type = IPV6_PKTINFO;
204 pkt_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
205 pkt_info->ipi6_ifindex = iface->if_index;
206 memcpy(&pkt_info->ipi6_addr, &iface->if_addr, sizeof(struct in6_addr));
208 #ifdef HAVE_SIN6_SCOPE_ID
209 if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr) ||
210 IN6_IS_ADDR_MC_LINKLOCAL(&addr.sin6_addr))
211 addr.sin6_scope_id = iface->if_index;
214 mhdr.msg_name = (caddr_t)&addr;
215 mhdr.msg_namelen = sizeof(struct sockaddr_in6);
218 mhdr.msg_control = (void *) cmsg;
219 mhdr.msg_controllen = sizeof(chdr);
221 err = sendmsg(sock, &mhdr, 0);
224 log(LOG_WARNING, "sendmsg: %s", strerror(errno));