OSDN Git Service

Add MS7619SE
[uclinux-h8/uClinux-dist.git] / user / radvd / send.c
1 /*
2  *   $Id: send.c,v 1.12 2002/10/28 17:28:37 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 <lutchann@litech.org>.
14  *
15  */
16
17 #include <config.h>
18 #include <includes.h>
19 #include <radvd.h>
20
21 void
22 send_ra(int sock, struct Interface *iface, struct in6_addr *dest)
23 {
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;
27         struct msghdr mhdr;
28         struct cmsghdr *cmsg;
29         struct iovec iov;
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];
34         int len = 0;
35         int err;
36
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);
40
41         dlog(LOG_DEBUG, 3, "sending RA on %s", iface->Name);
42
43         if (dest == NULL)
44         {
45                 struct timeval tv;
46
47                 dest = (struct in6_addr *)all_hosts_addr;
48                 gettimeofday(&tv, NULL);
49
50                 iface->last_multicast = tv.tv_sec;
51         }
52         
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));
57
58         radvert = (struct nd_router_advert *) buff;
59
60         radvert->nd_ra_type  = ND_ROUTER_ADVERT;
61         radvert->nd_ra_code  = 0;
62         radvert->nd_ra_cksum = 0;
63
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;
69         /* Mobile IPv6 ext */
70         radvert->nd_ra_flags_reserved   |=
71                 (iface->AdvHomeAgentFlag)?ND_RA_FLAG_HOME_AGENT:0;
72         
73         radvert->nd_ra_router_lifetime  = htons(iface->AdvDefaultLifetime);
74
75         radvert->nd_ra_reachable  = htonl(iface->AdvReachableTime);
76         radvert->nd_ra_retransmit = htonl(iface->AdvRetransTimer);
77
78         len = sizeof(struct nd_router_advert);
79
80         prefix = iface->AdvPrefixList;
81
82         /*
83          *      add prefix options
84          */
85
86         while(prefix)
87         {
88                 if( prefix->enabled )
89                 {
90                         struct nd_opt_prefix_info *pinfo;
91                         
92                         pinfo = (struct nd_opt_prefix_info *) (buff + len);
93
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;
97                         
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;
105
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;
109                         
110                         memcpy(&pinfo->nd_opt_pi_prefix, &prefix->Prefix,
111                                sizeof(struct in6_addr));
112
113                         len += sizeof(*pinfo);
114                 }
115
116                 prefix = prefix->next;
117         }
118         
119         /*
120          *      add MTU option
121          */
122
123         if (iface->AdvLinkMTU != 0) {
124                 struct nd_opt_mtu *mtu;
125                 
126                 mtu = (struct nd_opt_mtu *) (buff + len);
127         
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);
132
133                 len += sizeof(*mtu);
134         }
135
136         /*
137          * add Source Link-layer Address option
138          */
139
140         if (iface->AdvSourceLLAddress && iface->if_hwaddr_len != -1)
141         {
142                 uint8_t *ucp;
143                 int i;
144
145                 ucp = (uint8_t *) (buff + len);
146         
147                 *ucp++  = ND_OPT_SOURCE_LINKADDR;
148                 *ucp++  = (uint8_t) ((iface->if_hwaddr_len + 16 + 63) >> 6);
149
150                 len += 2 * sizeof(uint8_t);
151
152                 i = (iface->if_hwaddr_len + 7) >> 3;
153                 memcpy(buff + len, iface->if_hwaddr, i);
154                 len += i;
155         }
156
157         /*
158          * Mobile IPv6 ext: Advertisement Interval Option to support
159          * movement detection of mobile nodes
160          */
161
162         if(iface->AdvIntervalOpt)
163         {
164                 struct AdvInterval a_ival;
165                 uint32_t ival = (iface->MaxRtrAdvInterval * 1000);
166                 a_ival.type     = ND_OPT_RTR_ADV_INTERVAL;
167                 a_ival.length   = 1;
168                 a_ival.reserved = 0;
169                 a_ival.adv_ival = htonl(ival);
170
171                 memcpy(buff + len, &a_ival, sizeof(a_ival));
172                 len += sizeof(a_ival);
173         }
174
175         /*
176          * Mobile IPv6 ext: Home Agent Information Option to support
177          * Dynamic Home Agent Address Discovery
178          */
179
180         if(iface->AdvHomeAgentInfo && (iface->HomeAgentPreference != 0 ||
181                 iface->HomeAgentLifetime != iface->AdvDefaultLifetime))
182         {
183                 struct HomeAgentInfo ha_info;
184                 ha_info.type            = ND_OPT_HOME_AGENT_INFO;
185                 ha_info.length          = 1;
186                 ha_info.reserved        = 0;
187                 ha_info.preference      = htons(iface->HomeAgentPreference);
188                 ha_info.lifetime        = htons(iface->HomeAgentLifetime);
189
190                 memcpy(buff + len, &ha_info, sizeof(ha_info));
191                 len += sizeof(ha_info);
192         }
193         
194         iov.iov_len  = len;
195         iov.iov_base = (caddr_t) buff;
196         
197         memset(chdr, 0, sizeof(chdr));
198         cmsg = (struct cmsghdr *) chdr;
199         
200         cmsg->cmsg_len   = CMSG_LEN(sizeof(struct in6_pktinfo));
201         cmsg->cmsg_level = IPPROTO_IPV6;
202         cmsg->cmsg_type  = IPV6_PKTINFO;
203         
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));
207
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;
212 #endif
213
214         mhdr.msg_name = (caddr_t)&addr;
215         mhdr.msg_namelen = sizeof(struct sockaddr_in6);
216         mhdr.msg_iov = &iov;
217         mhdr.msg_iovlen = 1;
218         mhdr.msg_control = (void *) cmsg;
219         mhdr.msg_controllen = sizeof(chdr);
220
221         err = sendmsg(sock, &mhdr, 0);
222         
223         if (err < 0) {
224                 log(LOG_WARNING, "sendmsg: %s", strerror(errno));
225         }
226 }