1 /******************************************************************************
2 * Copyright (c) 2013 IBM Corporation
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
17 #include <sys/socket.h>
18 #include <netlib/ethernet.h>
19 #include <netlib/ipv6.h>
20 #include <netlib/icmpv6.h>
21 #include <netlib/ndp.h>
22 #include <netlib/dhcpv6.h>
24 static int ra_received = 0;
31 send_router_solicitation (int fd)
34 uint8_t ether_packet[ETH_MTU_SIZE];
35 struct packeth headers;
37 headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr));
38 headers.icmp6h = (struct icmp6hdr *) (ether_packet +
39 sizeof(struct ethhdr) +
40 sizeof(struct ip6hdr));
42 /* Destination is "All routers multicast address" (link-local) */
43 dest_addr.part.prefix = all_routers_ll.addr.part.prefix;
44 dest_addr.part.interface_id = all_routers_ll.addr.part.interface_id;
47 /* Fill IPv6 header */
48 fill_ip6hdr (ether_packet + sizeof(struct ethhdr),
49 ICMPv6_HEADER_SIZE + sizeof(struct router_solicitation),
51 get_ipv6_address(), &dest_addr);
53 /* Fill ICMPv6 message */
54 headers.icmp6h->type = ICMPV6_ROUTER_SOLICITATION;
55 headers.icmp6h->code = 0;
56 headers.icmp6h->icmp6body.router_solicit.lladdr.type = 1;
57 headers.icmp6h->icmp6body.router_solicit.lladdr.length = 1;
58 memcpy( &(headers.icmp6h->icmp6body.router_solicit.lladdr.mac),
59 get_mac_address(), 6);
61 send_ip (fd, headers.ip6h, sizeof(struct ip6hdr) +
62 ICMPv6_HEADER_SIZE + sizeof(struct router_solicitation));
66 * NET: Process prefix option in Router Advertisements
68 * @param ip6_packet pointer to an IPv6 packet
71 handle_prefixoption (uint8_t *option)
74 struct ip6addr_list_entry *new_address;
75 struct option_prefix *prefix_option;
76 struct prefix_info *prfx_info;
78 prefix_option = (struct option_prefix *) option;
79 memcpy( &(prefix.addr), &(prefix_option->prefix.addr), IPV6_ADDR_LENGTH);
81 /* Link-local adresses in RAs are nonsense */
82 if ( (IPV6_LL_PREFIX & (prefix_option->prefix.part.prefix)) == IPV6_LL_PREFIX )
85 if (prefix_option->preferred_lifetime > prefix_option->valid_lifetime)
88 /* Add address created from prefix to IPv6 address list */
89 new_address = ip6_prefix2addr (prefix);
93 /* Process only prefixes we don't already have an adress from */
94 if (!unknown_prefix (&new_address->addr)) {
98 /* Fill struct prefix_info from data in RA and store it in new_address */
99 prfx_info = ip6_create_prefix_info();
102 memcpy (&(new_address->prfx_info), prfx_info, sizeof(struct prefix_info));
104 /* Add prefix received in RA to list of known prefixes */
105 ip6addr_add (new_address);
109 * NET: Process source link layer addresses in Router Advertisements
111 * @param ip6_packet pointer to an IPv6 packet
114 handle_source_lladdr ( struct option_ll_address *option, struct router *rtr)
116 memcpy (&(rtr->mac), &(option->mac), 6);
120 * NET: Process ICMPv6 options in Router Advertisements
122 * @param ip6_packet pointer to an IPv6 packet
125 process_ra_options (uint8_t *option, int32_t option_length, struct router *r)
127 while (option_length > 0) {
129 case ND_OPTION_SOURCE_LL_ADDR:
130 handle_source_lladdr ((struct option_ll_address *) option, r);
132 case ND_OPTION_PREFIX_INFO:
133 handle_prefixoption(option);
138 //option+1 is the length field. length is in units of 8 bytes
139 option_length = option_length - (*(option+1) * 8);
140 option = option + (*(option+1) * 8);
147 * NET: Process Router Advertisements
149 * @param ip6_packet pointer to an IPv6 packet
152 handle_ra (struct icmp6hdr *icmp6h, uint8_t *ip6_packet)
154 uint8_t *first_option;
155 int32_t option_length;
157 struct router_advertisement *ra;
160 uint8_t rtr_mac[] = {0, 0, 0, 0, 0, 0};
162 ip6h = (struct ip6hdr *) ip6_packet;
163 ra = (struct router_advertisement *) &icmp6h->icmp6body.ra;
164 rtr_ip = (ip6_addr_t *) &ip6h->src;
166 rtr = find_router (&(ip6h->src));
168 rtr = router_create (rtr_mac, rtr_ip);
172 /* store info from router advertisement in router struct */
173 rtr->lifetime = ra->router_lifetime;
174 rtr->reachable_time = ra->reachable_time;
175 rtr->retrans_timer = ra->retrans_timer;
177 /* save flags concerning address (auto-) configuration */
178 ip6_state.managed_mode = ra->flags.managed;
179 ip6_state.other_config = ra->flags.other;
181 /* Process ICMPv6 options in Router Advertisement */
182 first_option = (uint8_t *) icmp6h + ICMPv6_HEADER_SIZE + 12;
183 option_length = (uint8_t *) icmp6h + ip6h->pl - first_option;
184 process_ra_options( (uint8_t *) first_option, option_length, rtr);
189 int is_ra_received(void)
197 * @param fd socket fd
198 * @param ip6_addr_t *dest_ip6
201 send_neighbour_solicitation (int fd, ip6_addr_t *dest_ip6)
205 uint8_t ether_packet[ETH_MTU_SIZE];
206 struct packeth headers;
208 memset(ether_packet, 0, ETH_MTU_SIZE);
209 headers.ethh = (struct ethhdr *) ether_packet;
210 headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr));
211 headers.icmp6h = (struct icmp6hdr *) (ether_packet +
212 sizeof(struct ethhdr) +
213 sizeof(struct ip6hdr));
215 /* Fill IPv6 header */
216 snma.part.prefix = IPV6_SOLIC_NODE_PREFIX;
217 snma.part.interface_id = IPV6_SOLIC_NODE_IFACE_ID;
218 snma.addr[13] = dest_ip6->addr[13];
219 snma.addr[14] = dest_ip6->addr[14];
220 snma.addr[15] = dest_ip6->addr[15];
221 fill_ip6hdr((uint8_t *) headers.ip6h,
223 sizeof(struct neighbour_solicitation),
225 get_ipv6_address(), &snma);
227 /* Fill ICMPv6 message */
228 headers.icmp6h->type = ICMPV6_NEIGHBOUR_SOLICITATION;
229 headers.icmp6h->code = 0;
230 memcpy( &(headers.icmp6h->icmp6body.nghb_solicit.target),
231 dest_ip6, IPV6_ADDR_LENGTH );
232 headers.icmp6h->icmp6body.nghb_solicit.lladdr.type = 1;
233 headers.icmp6h->icmp6body.nghb_solicit.lladdr.length = 1;
234 memcpy( &(headers.icmp6h->icmp6body.nghb_solicit.lladdr.mac),
235 get_mac_address(), 6);
237 send_ip (fd, ether_packet + sizeof(struct ethhdr),
238 sizeof(struct ip6hdr) + ICMPv6_HEADER_SIZE +
239 sizeof(struct neighbour_solicitation));
245 * @param fd socket fd
246 * @param ip6_packet pointer to an IPv6 packet
247 * @param icmp6hdr pointer to the icmp6 header in ip6_packet
248 * @param na_flags Neighbour advertisment flags
251 send_neighbour_advertisement (int fd, struct neighbor *target)
253 struct na_flags na_adv_flags;
254 uint8_t ether_packet[ETH_MTU_SIZE];
255 struct packeth headers;
258 headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr));
259 headers.icmp6h = (struct icmp6hdr *) (ether_packet +
260 sizeof(struct ethhdr) +
261 sizeof(struct ip6hdr));
263 /* Fill IPv6 header */
264 fill_ip6hdr(ether_packet + sizeof(struct ethhdr),
266 sizeof(struct neighbour_advertisement),
268 get_ipv6_address(), (ip6_addr_t *) &(target->ip.addr));
270 /* Fill ICMPv6 message */
271 memcpy( &(headers.icmp6h->icmp6body.nghb_adv.target),
272 &(target->ip.addr), IPV6_ADDR_LENGTH );
273 headers.icmp6h->icmp6body.nghb_adv.lladdr.type = 1;
274 headers.icmp6h->icmp6body.nghb_adv.lladdr.length = 1;
275 memcpy( &(headers.icmp6h->icmp6body.nghb_adv.lladdr.mac),
276 get_mac_address(), 6);
278 na_adv_flags.is_router = 0;
279 na_adv_flags.na_is_solicited = 1;
280 na_adv_flags.override = 1;
282 headers.icmp6h->type = ICMPV6_NEIGHBOUR_ADVERTISEMENT;
283 headers.icmp6h->code = 0;
284 headers.icmp6h->icmp6body.nghb_adv.router = na_adv_flags.is_router;
286 headers.icmp6h->icmp6body.nghb_adv.solicited = na_adv_flags.na_is_solicited;
287 headers.icmp6h->icmp6body.nghb_adv.override = na_adv_flags.override;
288 headers.icmp6h->icmp6body.nghb_adv.lladdr.type = 2;
289 headers.icmp6h->icmp6body.nghb_adv.lladdr.length = 1;
291 memset( &(headers.icmp6h->icmp6body.nghb_adv.target), 0,
294 if( na_adv_flags.na_is_solicited ) {
295 memcpy( &(headers.icmp6h->icmp6body.nghb_adv.target),
296 get_ipv6_address(), IPV6_ADDR_LENGTH);
299 memcpy( &(headers.icmp6h->icmp6body.nghb_adv.lladdr.mac),
300 get_mac_address(), 6);
302 send_ip (fd, ether_packet + sizeof(struct ethhdr),
303 sizeof(struct ip6hdr) + ICMPv6_HEADER_SIZE +
304 sizeof(struct neighbour_advertisement));
310 * @param fd socket fd
311 * @param ip6_packet pointer to an IPv6 packet
314 handle_na (int fd, uint8_t *packet)
316 struct neighbor *n = NULL;
317 struct packeth headers;
320 headers.ethh = (struct ethhdr *) packet;
321 headers.ip6h = (struct ip6hdr *) ((unsigned char *) headers.ethh +
322 sizeof(struct ethhdr));
323 headers.icmp6h = (struct icmp6hdr *) (packet +
324 sizeof(struct ethhdr) +
325 sizeof(struct ip6hdr));
327 memcpy(&(ip.addr), &(headers.ip6h->src), IPV6_ADDR_LENGTH);
329 n = find_neighbor (&ip);
332 n= (struct neighbor *)
333 neighbor_create( packet, &headers );
336 if (!neighbor_add(n))
339 memcpy (&(n->mac), &(headers.ethh->src_mac[0]), 6);
341 if (n->eth_len > 0) {
342 struct ethhdr * ethh = (struct ethhdr *) &(n->eth_frame);
343 memcpy(ethh->dest_mac, &(n->mac), 6);
344 send_ether (fd, &(n->eth_frame), n->eth_len + sizeof(struct ethhdr));
353 * NET: Handles ICMPv6 messages
355 * @param fd socket fd
356 * @param ip6_packet pointer to an IPv6 packet
357 * @param packetsize size of ipv6_packet
360 handle_icmpv6 (int fd, struct ethhdr *etherhdr,
364 struct icmp6hdr *received_icmp6 = NULL;
365 struct ip6hdr *received_ip6 = NULL;
366 struct neighbor target;
368 received_ip6 = (struct ip6hdr *) ip6_packet;
369 received_icmp6 = (struct icmp6hdr *) (ip6_packet +
370 sizeof(struct ip6hdr));
371 memcpy( &(target.ip.addr), &(received_ip6->src),
373 memcpy( &(target.mac), etherhdr->src_mac, 6);
375 /* process ICMPv6 types */
376 switch(received_icmp6->type) {
377 case ICMPV6_NEIGHBOUR_SOLICITATION:
378 send_neighbour_advertisement(fd, &target);
380 case ICMPV6_NEIGHBOUR_ADVERTISEMENT:
381 handle_na(fd, (uint8_t *) ip6_packet - sizeof(struct ethhdr));
383 case ICMPV6_ROUTER_ADVERTISEMENT:
384 handle_ra(received_icmp6, (uint8_t *) received_ip6);