1 /******************************************************************************
2 * Copyright (c) 2013 IBM Corporation
3 * All rights reserved.
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
8 *
9 * Contributors:
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
12
13 #include <stdint.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <sys/socket.h>
18 #include "ethernet.h"
19 #include "ipv6.h"
20 #include "icmpv6.h"
21 #include "ndp.h"
22 #include "dhcpv6.h"
23
24 static int ra_received = 0;
25
26 /**
27 * NET:
28 * @param fd socket fd
29 */
30 void
send_router_solicitation(int fd)31 send_router_solicitation (int fd)
32 {
33 ip6_addr_t dest_addr;
34 uint8_t *ether_packet;
35 struct packeth headers;
36
37 ether_packet = malloc(ETH_MTU_SIZE);
38 if (!ether_packet) {
39 fprintf(stderr, "send_router_solicitation: Out of memory\n");
40 return;
41 }
42
43 headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr));
44 headers.icmp6h = (struct icmp6hdr *) (ether_packet +
45 sizeof(struct ethhdr) +
46 sizeof(struct ip6hdr));
47
48 /* Destination is "All routers multicast address" (link-local) */
49 dest_addr.part.prefix = 0xff02000000000000ULL;
50 dest_addr.part.interface_id = 2;
51
52 /* Fill IPv6 header */
53 fill_ip6hdr (ether_packet + sizeof(struct ethhdr),
54 ICMPv6_HEADER_SIZE + sizeof(struct router_solicitation),
55 0x3a, //ICMPV6
56 get_ipv6_address(), &dest_addr);
57
58 /* Fill ICMPv6 message */
59 headers.icmp6h->type = ICMPV6_ROUTER_SOLICITATION;
60 headers.icmp6h->code = 0;
61 headers.icmp6h->icmp6body.router_solicit.lladdr.type = 1;
62 headers.icmp6h->icmp6body.router_solicit.lladdr.length = 1;
63 memcpy( &(headers.icmp6h->icmp6body.router_solicit.lladdr.mac),
64 get_mac_address(), 6);
65
66 send_ip (fd, headers.ip6h, sizeof(struct ip6hdr) +
67 ICMPv6_HEADER_SIZE + sizeof(struct router_solicitation));
68
69 free(ether_packet);
70 }
71
72 /**
73 * NET: Process prefix option in Router Advertisements
74 *
75 * @param ip6_packet pointer to an IPv6 packet
76 */
77 static void
handle_prefixoption(uint8_t * option)78 handle_prefixoption (uint8_t *option)
79 {
80 ip6_addr_t prefix;
81 struct ip6addr_list_entry *new_address;
82 struct option_prefix *prefix_option;
83 struct prefix_info *prfx_info;
84
85 prefix_option = (struct option_prefix *) option;
86 memcpy( &(prefix.addr), &(prefix_option->prefix.addr), IPV6_ADDR_LENGTH);
87
88 /* Link-local adresses in RAs are nonsense */
89 if (ip6_is_linklocal(&prefix))
90 return;
91
92 if (prefix_option->preferred_lifetime > prefix_option->valid_lifetime)
93 return;
94
95 /* Add address created from prefix to IPv6 address list */
96 new_address = ip6_prefix2addr (prefix);
97 if (!new_address)
98 return;
99
100 /* Process only prefixes we don't already have an adress from */
101 if (!unknown_prefix (&new_address->addr)) {
102 return;
103 }
104
105 /* Fill struct prefix_info from data in RA and store it in new_address */
106 prfx_info = ip6_create_prefix_info();
107 if (!prfx_info)
108 return;
109 memcpy (&(new_address->prfx_info), prfx_info, sizeof(struct prefix_info));
110
111 /* Add prefix received in RA to list of known prefixes */
112 ip6addr_add (new_address);
113 }
114
115 /**
116 * NET: Process source link layer addresses in Router Advertisements
117 *
118 * @param ip6_packet pointer to an IPv6 packet
119 */
120 static void
handle_source_lladdr(struct option_ll_address * option,struct router * rtr)121 handle_source_lladdr ( struct option_ll_address *option, struct router *rtr)
122 {
123 memcpy (&(rtr->mac), &(option->mac), 6);
124 }
125
126 /**
127 * NET: Process ICMPv6 options in Router Advertisements
128 *
129 * @param ip6_packet pointer to an IPv6 packet
130 */
131 static void
process_ra_options(uint8_t * option,int32_t option_length,struct router * r)132 process_ra_options (uint8_t *option, int32_t option_length, struct router *r)
133 {
134 while (option_length > 0) {
135 switch (*option) {
136 case ND_OPTION_SOURCE_LL_ADDR:
137 handle_source_lladdr ((struct option_ll_address *) option, r);
138 break;
139 case ND_OPTION_PREFIX_INFO:
140 handle_prefixoption(option);
141 break;
142 default:
143 break;
144 }
145 //option+1 is the length field. length is in units of 8 bytes
146 option_length = option_length - (*(option+1) * 8);
147 option = option + (*(option+1) * 8);
148 }
149
150 return;
151 }
152
153 /**
154 * NET: Process Router Advertisements
155 *
156 * @param ip6_packet pointer to an IPv6 packet
157 */
158 static void
handle_ra(struct icmp6hdr * icmp6h,uint8_t * ip6_packet)159 handle_ra (struct icmp6hdr *icmp6h, uint8_t *ip6_packet)
160 {
161 uint8_t *first_option;
162 int32_t option_length;
163 struct ip6hdr *ip6h;
164 struct router_advertisement *ra;
165 struct router *rtr;
166 uint8_t rtr_mac[] = {0, 0, 0, 0, 0, 0};
167
168 ip6h = (struct ip6hdr *) ip6_packet;
169 ra = (struct router_advertisement *) &icmp6h->icmp6body.ra;
170
171 rtr = find_router(ip6h->src);
172 if (!rtr) {
173 rtr = router_create (rtr_mac, ip6h->src);
174 router_add (rtr);
175 }
176
177 /* store info from router advertisement in router struct */
178 rtr->lifetime = ra->router_lifetime;
179 rtr->reachable_time = ra->reachable_time;
180 rtr->retrans_timer = ra->retrans_timer;
181
182 /* save flags concerning address (auto-) configuration */
183 ip6_state.managed_mode = ra->flags.managed;
184 ip6_state.other_config = ra->flags.other;
185
186 /* Process ICMPv6 options in Router Advertisement */
187 first_option = (uint8_t *) icmp6h + ICMPv6_HEADER_SIZE + 12;
188 option_length = (uint8_t *) icmp6h + ip6h->pl - first_option;
189 process_ra_options( (uint8_t *) first_option, option_length, rtr);
190
191 ra_received = 1;
192 }
193
is_ra_received(void)194 int is_ra_received(void)
195 {
196 return ra_received;
197 }
198
199 /**
200 * NET:
201 *
202 * @param fd socket fd
203 * @param ip6_addr_t *dest_ip6
204 */
205 void
send_neighbour_solicitation(int fd,ip6_addr_t * dest_ip6)206 send_neighbour_solicitation (int fd, ip6_addr_t *dest_ip6)
207 {
208 ip6_addr_t snma;
209 uint8_t *ether_packet;
210 struct packeth headers;
211
212 ether_packet = malloc(ETH_MTU_SIZE);
213 if (!ether_packet) {
214 fprintf(stderr, "send_neighbour_solicitation: Out of memory\n");
215 return;
216 }
217
218 memset(ether_packet, 0, ETH_MTU_SIZE);
219 headers.ethh = (struct ethhdr *) ether_packet;
220 headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr));
221 headers.icmp6h = (struct icmp6hdr *) (ether_packet +
222 sizeof(struct ethhdr) +
223 sizeof(struct ip6hdr));
224
225 /* Fill IPv6 header */
226 snma.part.prefix = IPV6_SOLIC_NODE_PREFIX;
227 snma.part.interface_id = IPV6_SOLIC_NODE_IFACE_ID;
228 snma.addr[13] = dest_ip6->addr[13];
229 snma.addr[14] = dest_ip6->addr[14];
230 snma.addr[15] = dest_ip6->addr[15];
231 fill_ip6hdr((uint8_t *) headers.ip6h,
232 ICMPv6_HEADER_SIZE + sizeof(struct neighbour_solicitation),
233 0x3a, //ICMPv6
234 get_ipv6_address(), &snma);
235
236 /* Fill ICMPv6 message */
237 headers.icmp6h->type = ICMPV6_NEIGHBOUR_SOLICITATION;
238 headers.icmp6h->code = 0;
239 memcpy( &(headers.icmp6h->icmp6body.nghb_solicit.target),
240 dest_ip6, IPV6_ADDR_LENGTH );
241 headers.icmp6h->icmp6body.nghb_solicit.lladdr.type = 1;
242 headers.icmp6h->icmp6body.nghb_solicit.lladdr.length = 1;
243 memcpy( &(headers.icmp6h->icmp6body.nghb_solicit.lladdr.mac),
244 get_mac_address(), 6);
245
246 send_ip (fd, ether_packet + sizeof(struct ethhdr),
247 sizeof(struct ip6hdr) + ICMPv6_HEADER_SIZE +
248 sizeof(struct neighbour_solicitation));
249
250 free(ether_packet);
251 }
252
253 /**
254 * NET:
255 *
256 * @param fd socket fd
257 * @param ip6_packet pointer to an IPv6 packet
258 * @param icmp6hdr pointer to the icmp6 header in ip6_packet
259 * @param na_flags Neighbour advertisment flags
260 */
261 static void
send_neighbour_advertisement(int fd,struct neighbor * target)262 send_neighbour_advertisement (int fd, struct neighbor *target)
263 {
264 struct na_flags na_adv_flags;
265 uint8_t *ether_packet;
266 struct packeth headers;
267
268 ether_packet = malloc(ETH_MTU_SIZE);
269 if (!ether_packet) {
270 fprintf(stderr, "send_neighbour_advertisement: Out of memory\n");
271 return;
272 }
273
274 headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr));
275 headers.icmp6h = (struct icmp6hdr *) (ether_packet +
276 sizeof(struct ethhdr) +
277 sizeof(struct ip6hdr));
278
279 /* Fill IPv6 header */
280 fill_ip6hdr(ether_packet + sizeof(struct ethhdr),
281 ICMPv6_HEADER_SIZE + sizeof(struct neighbour_advertisement),
282 0x3a, //ICMPv6
283 get_ipv6_address(), (ip6_addr_t *) &(target->ip.addr));
284
285 /* Fill ICMPv6 message */
286 memcpy( &(headers.icmp6h->icmp6body.nghb_adv.target),
287 &(target->ip.addr), IPV6_ADDR_LENGTH );
288 headers.icmp6h->icmp6body.nghb_adv.lladdr.type = 1;
289 headers.icmp6h->icmp6body.nghb_adv.lladdr.length = 1;
290 memcpy( &(headers.icmp6h->icmp6body.nghb_adv.lladdr.mac),
291 get_mac_address(), 6);
292
293 na_adv_flags.is_router = 0;
294 na_adv_flags.na_is_solicited = 1;
295 na_adv_flags.override = 1;
296
297 headers.icmp6h->type = ICMPV6_NEIGHBOUR_ADVERTISEMENT;
298 headers.icmp6h->code = 0;
299 headers.icmp6h->icmp6body.nghb_adv.router = na_adv_flags.is_router;
300
301 headers.icmp6h->icmp6body.nghb_adv.solicited = na_adv_flags.na_is_solicited;
302 headers.icmp6h->icmp6body.nghb_adv.override = na_adv_flags.override;
303 headers.icmp6h->icmp6body.nghb_adv.lladdr.type = 2;
304 headers.icmp6h->icmp6body.nghb_adv.lladdr.length = 1;
305
306 memset( &(headers.icmp6h->icmp6body.nghb_adv.target), 0,
307 IPV6_ADDR_LENGTH );
308
309 if( na_adv_flags.na_is_solicited ) {
310 memcpy( &(headers.icmp6h->icmp6body.nghb_adv.target),
311 get_ipv6_address(), IPV6_ADDR_LENGTH);
312 }
313
314 memcpy( &(headers.icmp6h->icmp6body.nghb_adv.lladdr.mac),
315 get_mac_address(), 6);
316
317 send_ip (fd, ether_packet + sizeof(struct ethhdr),
318 sizeof(struct ip6hdr) + ICMPv6_HEADER_SIZE +
319 sizeof(struct neighbour_advertisement));
320
321 free(ether_packet);
322 }
323
324 /**
325 * NET:
326 *
327 * @param fd socket fd
328 * @param ip6_packet pointer to an IPv6 packet
329 */
330 static int8_t
handle_na(int fd,uint8_t * packet)331 handle_na (int fd, uint8_t *packet)
332 {
333 struct neighbor *n = NULL;
334 struct packeth headers;
335 ip6_addr_t ip;
336
337 headers.ethh = (struct ethhdr *) packet;
338 headers.ip6h = (struct ip6hdr *) (packet + sizeof(struct ethhdr));
339 headers.icmp6h = (struct icmp6hdr *) (packet +
340 sizeof(struct ethhdr) +
341 sizeof(struct ip6hdr));
342
343 memcpy(&(ip.addr), &(headers.ip6h->src), IPV6_ADDR_LENGTH);
344
345 n = find_neighbor(ip);
346
347 if (!n) {
348 n= (struct neighbor *)
349 neighbor_create( packet, &headers );
350 if (!n)
351 return 0;
352 if (!neighbor_add(n))
353 return 0;
354 } else {
355 memcpy (&(n->mac), &(headers.ethh->src_mac[0]), 6);
356 n->status = NB_REACHABLE;
357 if (n->eth_len > 0) {
358 struct ethhdr * ethh = (struct ethhdr *) &(n->eth_frame);
359 memcpy(ethh->dest_mac, &(n->mac), 6);
360 send_ether (fd, &(n->eth_frame), n->eth_len + sizeof(struct ethhdr));
361 n->eth_len = 0;
362 }
363 }
364
365 return 1;
366 }
367
368 /**
369 * NET: Handles ICMPv6 messages
370 *
371 * @param fd socket fd
372 * @param ip6_packet pointer to an IPv6 packet
373 * @param packetsize size of ipv6_packet
374 */
375 int8_t
handle_icmpv6(int fd,struct ethhdr * etherhdr,uint8_t * ip6_packet)376 handle_icmpv6 (int fd, struct ethhdr *etherhdr,
377 uint8_t *ip6_packet)
378 {
379
380 struct icmp6hdr *received_icmp6 = NULL;
381 struct ip6hdr *received_ip6 = NULL;
382 struct neighbor target;
383
384 received_ip6 = (struct ip6hdr *) ip6_packet;
385 received_icmp6 = (struct icmp6hdr *) (ip6_packet +
386 sizeof(struct ip6hdr));
387 memcpy( &(target.ip.addr), &(received_ip6->src),
388 IPV6_ADDR_LENGTH );
389 memcpy( &(target.mac), etherhdr->src_mac, 6);
390
391 /* process ICMPv6 types */
392 switch(received_icmp6->type) {
393 case ICMPV6_NEIGHBOUR_SOLICITATION:
394 send_neighbour_advertisement(fd, &target);
395 break;
396 case ICMPV6_NEIGHBOUR_ADVERTISEMENT:
397 handle_na(fd, (uint8_t *) ip6_packet - sizeof(struct ethhdr));
398 break;
399 case ICMPV6_ROUTER_ADVERTISEMENT:
400 handle_ra(received_icmp6, (uint8_t *) received_ip6);
401 break;
402 default:
403 return -1;
404 }
405
406 return 1;
407 }
408