]> git.saurik.com Git - apple/configd.git/blob - nwi/network_information_priv.c
configd-699.30.1.tar.gz
[apple/configd.git] / nwi / network_information_priv.c
1 /*
2 * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <arpa/inet.h>
25 #include <assert.h>
26 #include <notify.h>
27 #include <string.h>
28 #include <sys/socket.h>
29 #include <stdlib.h>
30 #include <stdbool.h>
31 #include "network_information_priv.h"
32 #include <limits.h>
33 #include <stdio.h>
34
35 __private_extern__
36 const sa_family_t nwi_af_list[] = {AF_INET, AF_INET6};
37
38 static __inline__ size_t
39 nwi_state_compute_size(unsigned int n)
40 {
41 return (offsetof(nwi_state, nwi_ifstates[n]));
42
43 }
44 __private_extern__
45 nwi_state_t
46 nwi_state_copy_priv(nwi_state_t src)
47 {
48 nwi_state_t dest = NULL;
49
50 if (src == NULL) {
51 return dest;
52 }
53
54 dest = malloc(src->size);
55
56 if (dest != NULL) {
57 bcopy(src, dest, src->size);
58
59 dest->ref = 1;
60 dest->svr = FALSE;
61 }
62 return dest;
63 }
64
65 __private_extern__
66 nwi_state_t
67 nwi_state_new(nwi_state_t old_state, int elems)
68 {
69 nwi_state_t state = NULL;
70 uint32_t new_size;
71
72 if (old_state == NULL && elems == 0) {
73 return NULL;
74 }
75
76 /* Need to insert a last node for each of the v4/v6 list */
77 new_size = (elems != 0)
78 ? (uint32_t)(sizeof(nwi_state) + nwi_state_compute_size((elems+1) * 2))
79 : 0;
80
81 /* Should we reallocate? */
82 if (old_state != NULL) {
83 if (old_state->size >= new_size) {
84 return (old_state);
85 }
86 }
87
88 state = malloc(new_size);
89 bzero(state, new_size);
90 state->size = new_size;
91
92 /*
93 * v4 list is stored 0 to elems,
94 * v6 list is stored elems + 1 to 2 * elems + 2
95 */
96 state->ipv6_start = elems + 1;
97
98 if (old_state != NULL) {
99 state->ipv6_count = old_state->ipv6_count;
100 if (state->ipv6_count > 0) {
101 bcopy((void*) &old_state->nwi_ifstates[old_state->ipv6_start],
102 (void*) &state->nwi_ifstates[state->ipv6_start],
103 old_state->ipv6_count * sizeof(nwi_ifstate));
104 }
105
106 state->ipv4_count = old_state->ipv4_count;
107 if (state->ipv4_count > 0) {
108 bcopy((void*) old_state->nwi_ifstates,
109 (void*) state->nwi_ifstates,
110 old_state->ipv4_count * sizeof(nwi_ifstate));
111 }
112
113 free(old_state);
114 } else {
115 state->ipv4_count = 0;
116 state->ipv6_count = 0;
117 }
118 nwi_state_set_last(state, AF_INET);
119 nwi_state_set_last(state, AF_INET6);
120
121 state->ref = 1;
122 state->svr = FALSE;
123 return state;
124 }
125
126 static __inline__
127 nwi_ifstate_t
128 nwi_ifstate_get_last(nwi_state_t state, int af, uint32_t** last)
129 {
130 uint32_t* count;
131 int idx;
132
133 assert(state != NULL);
134
135 count = (af == AF_INET) ? &state->ipv4_count
136 : &state->ipv6_count;
137
138 idx = (af == AF_INET) ? state->ipv4_count
139 : (state->ipv6_start + state->ipv6_count);
140
141 *last = count;
142
143 return &state->nwi_ifstates[idx];
144 }
145
146 __private_extern__
147 void
148 nwi_ifstate_set_signature(nwi_ifstate_t ifstate, uint8_t * signature)
149 {
150 bcopy(signature, ifstate->signature, sizeof(ifstate->signature));
151 ifstate->flags |= NWI_IFSTATE_FLAGS_HAS_SIGNATURE;
152 return;
153 }
154
155 __private_extern__
156 nwi_ifstate_t
157 nwi_insert_ifstate(nwi_state_t state,
158 const char * ifname, int af,
159 uint64_t flags, Rank rank,
160 void * ifa,
161 struct sockaddr * vpn_server_addr,
162 uint32_t reach_flags)
163 {
164 nwi_ifstate_t ifstate;
165
166 /* Will only insert unique elements in the list */
167 ifstate = nwi_state_get_ifstate_with_name(state, af, ifname);
168
169 /* Already present, just ignore it */
170 if (ifstate != NULL) {
171 if (ifstate->rank < rank) {
172 return NULL;
173 }
174 }
175
176 if (ifstate == NULL) {
177 uint32_t *last;
178
179 /* We need to append it as the last element */
180 ifstate = nwi_ifstate_get_last(state, af, &last);
181 bzero(ifstate, sizeof(*ifstate));
182 strlcpy(ifstate->ifname, ifname, sizeof(ifstate->ifname));
183 ifstate->af = af;
184 (*last)++;
185 }
186
187 /* We need to update the address/rank/flag fields for the existing/new
188 * element */
189 if (ifa != NULL) {
190 switch (af) {
191 case AF_INET:
192 ifstate->iaddr = *((struct in_addr *) ifa);
193 break;
194 case AF_INET6:
195 ifstate->iaddr6 = *((struct in6_addr *) ifa);
196 break;
197 default:
198 break;
199 }
200
201 }
202
203 if (vpn_server_addr != NULL && vpn_server_addr->sa_family != 0) {
204 _nwi_ifstate_set_vpn_server(ifstate, vpn_server_addr);
205 } else {
206 _nwi_ifstate_set_vpn_server(ifstate, NULL);
207 }
208
209 ifstate->reach_flags = reach_flags;
210 ifstate->rank = rank;
211 ifstate->flags = flags;
212
213 return ifstate;
214 }
215
216 __private_extern__
217 void
218 nwi_state_clear(nwi_state_t state, int af)
219 {
220 uint32_t* count;
221
222 count = (af == AF_INET)
223 ?&state->ipv4_count:&state->ipv6_count;
224
225 *count = 0;
226 nwi_state_set_last(state, af);
227 return;
228
229 }
230
231 __private_extern__
232 void
233 nwi_state_set_last(nwi_state_t state, int af)
234 {
235 int last_elem_idx;
236
237 if (state == NULL) {
238 return;
239 }
240
241 /* The last element is an element with the flags set as
242 * NWI_IFSTATE_FLAGS_NOT_IN_LIST */
243 last_elem_idx = (af == AF_INET) ? state->ipv4_count
244 : (state->ipv6_start + state->ipv6_count);
245
246 state->nwi_ifstates[last_elem_idx].ifname[0] = '\0';
247 state->nwi_ifstates[last_elem_idx].flags = NWI_IFSTATE_FLAGS_NOT_IN_LIST;
248 }
249
250 #define unchanged ""
251 #define added "+"
252 #define deleted "-"
253 #define changed "!"
254 #define rank_change "R"
255
256 __private_extern__
257 void *
258 nwi_ifstate_get_address(nwi_ifstate_t ifstate)
259 {
260 return (void *)&ifstate->iaddr;
261 }
262
263 __private_extern__
264 const char *
265 nwi_ifstate_get_diff_str(nwi_ifstate_t ifstate)
266 {
267 if (strcmp(ifstate->diff_str, rank_change) == 0) {
268 return changed;
269 }
270 return ifstate->diff_str;
271 }
272
273 static
274 inline
275 boolean_t
276 nwi_ifstate_has_changed(nwi_ifstate_t ifstate1, nwi_ifstate_t ifstate2)
277 {
278 if (ifstate1->flags != ifstate2->flags) {
279 return TRUE;
280 }
281
282 if (ifstate1->af == AF_INET) {
283 if (memcmp(&ifstate1->iaddr, &ifstate2->iaddr, sizeof(struct in_addr)) != 0) {
284 return TRUE;
285 }
286 } else {
287 if (memcmp(&ifstate1->iaddr6, &ifstate2->iaddr6, sizeof(struct in6_addr)) != 0) {
288 return TRUE;
289 }
290 }
291 return FALSE;
292 }
293
294 static
295 inline
296 nwi_ifstate_t
297 nwi_ifstate_append(nwi_state_t state, nwi_ifstate_t scan)
298 {
299 nwi_ifstate_t new_ifstate = NULL;
300 uint32_t *last;
301
302 new_ifstate = nwi_ifstate_get_last(state, scan->af, &last);
303 memcpy(new_ifstate, scan, sizeof(*scan));
304 (*last)++;
305 return new_ifstate;
306 }
307
308 static
309 inline
310 void
311 nwi_ifstate_set_diff_str(nwi_ifstate_t ifstate, const char *diff_str)
312 {
313 ifstate->diff_str = diff_str;
314 }
315
316 static
317 void
318 nwi_ifstate_set_added_or_changed_str(nwi_state_t state, nwi_state_t old_state, nwi_ifstate_t ifstate)
319 {
320 nwi_ifstate_t existing_ifstate, new_ifstate;
321
322 existing_ifstate = nwi_state_get_ifstate_with_name(old_state,
323 ifstate->af,
324 nwi_ifstate_get_ifname(ifstate));
325
326 /* Add the element that is not in the store */
327 new_ifstate = nwi_ifstate_append(state, ifstate);
328
329 /* These are potentially "added" elements unless they are
330 * in the old list */
331 nwi_ifstate_set_diff_str(new_ifstate, added);
332
333 if (existing_ifstate != NULL) {
334 if (nwi_ifstate_has_changed(existing_ifstate, new_ifstate) == TRUE) {
335 nwi_ifstate_set_diff_str(new_ifstate, changed);
336 } else if (existing_ifstate->rank != new_ifstate->rank) {
337 nwi_ifstate_set_diff_str(new_ifstate, rank_change);
338 } else {
339 nwi_ifstate_set_diff_str(new_ifstate, unchanged);
340 }
341 }
342 return;
343 }
344
345 static
346 void
347 nwi_ifstate_set_removed_str(nwi_state_t state, nwi_ifstate_t ifstate)
348 {
349 nwi_ifstate_t existing_ifstate;
350
351 existing_ifstate = nwi_state_get_ifstate_with_name(state,
352 ifstate->af,
353 nwi_ifstate_get_ifname(ifstate));
354
355 /* Any elements that has not been added means that they are removed */
356 if (existing_ifstate == NULL) {
357 nwi_ifstate_t new_ifstate = nwi_ifstate_append(state, ifstate);
358 nwi_ifstate_set_diff_str(new_ifstate, deleted);
359 }
360 return;
361 }
362
363 static
364 void
365 nwi_state_merge_added(nwi_state_t state, nwi_state_t old_state,
366 nwi_state_t new_state)
367 {
368 int i;
369 nwi_ifstate_t scan;
370
371 if (new_state == NULL) {
372 return;
373 }
374
375 if (new_state->ipv4_count) {
376 for (i = 0, scan = new_state->nwi_ifstates;
377 i < new_state->ipv4_count; i++, scan++) {
378 nwi_ifstate_set_added_or_changed_str(state, old_state, scan);
379 }
380 nwi_state_set_last(state, AF_INET);
381 }
382
383 if (new_state->ipv6_count) {
384 for (i = 0, scan = new_state->nwi_ifstates + new_state->ipv6_start;
385 i < new_state->ipv6_count; i++, scan++) {
386 nwi_ifstate_set_added_or_changed_str(state, old_state, scan);
387 }
388 nwi_state_set_last(state, AF_INET6);
389 }
390 return;
391 }
392
393 void
394 nwi_state_merge_removed(nwi_state_t state, nwi_state_t old_state)
395 {
396 int i;
397 nwi_ifstate_t scan;
398
399 if (old_state == NULL) {
400 return;
401 }
402
403 if (old_state->ipv4_count) {
404 for (i = 0, scan = old_state->nwi_ifstates;
405 i < old_state->ipv4_count; i++, scan++) {
406 nwi_ifstate_set_removed_str(state, scan);
407 }
408 nwi_state_set_last(state, AF_INET);
409 }
410
411 if (old_state->ipv6_count) {
412 for (i = 0, scan = old_state->nwi_ifstates + old_state->ipv6_start;
413 i < old_state->ipv6_count; i++, scan++) {
414 nwi_ifstate_set_removed_str(state, scan);
415 }
416 nwi_state_set_last(state, AF_INET6);
417 }
418 return;
419 }
420
421 __private_extern__
422 nwi_state_t
423 nwi_state_diff(nwi_state_t old_state, nwi_state_t new_state)
424 {
425 nwi_state_t diff;
426 int total_count = 0;
427
428 if (old_state != NULL) {
429 total_count = old_state->ipv4_count + old_state->ipv6_count;
430 }
431
432 if (new_state != NULL) {
433 total_count += new_state->ipv4_count + new_state->ipv6_count;
434 }
435
436 if (total_count == 0) {
437 return NULL;
438 }
439
440 diff = nwi_state_new(NULL, total_count);
441
442 nwi_state_merge_added(diff, old_state, new_state);
443 nwi_state_merge_removed(diff, old_state);
444
445 /* Diff consists of a nwi_state_t with annotated diff_str's */
446 return diff;
447 }
448
449 static __inline__
450 void
451 _nwi_ifstate_set_generation(nwi_ifstate_t ifstate, uint64_t generation_count)
452 {
453 ifstate->if_generation_count = generation_count;
454
455 return;
456 }
457
458 static
459 boolean_t
460 _nwi_ifstate_has_changed(nwi_state_t state, const char * ifname)
461 {
462 nwi_ifstate_t ifstate;
463
464 /* If either the v4 ifstate or the v6 ifstate
465 * has changed, then report that the interface has changed */
466 ifstate = nwi_state_get_ifstate_with_name(state,
467 AF_INET,
468 ifname);
469
470 if (ifstate != NULL
471 && ifstate->diff_str != NULL
472 && strcmp(ifstate->diff_str, unchanged) != 0
473 && strcmp(ifstate->diff_str, rank_change) != 0) {
474 return (TRUE);
475 }
476
477 ifstate = nwi_state_get_ifstate_with_name(state,
478 AF_INET6,
479 ifname);
480
481 if (ifstate != NULL
482 && ifstate->diff_str != NULL
483 && strcmp(ifstate->diff_str, unchanged) != 0
484 && strcmp(ifstate->diff_str, rank_change) != 0) {
485 return (TRUE);
486 }
487 return (FALSE);
488 }
489
490 __private_extern__
491 void
492 _nwi_state_update_interface_generations(nwi_state_t old_state, nwi_state_t state, nwi_state_t changes)
493 {
494 int i;
495 uint64_t generation_count;
496 nwi_ifstate_t scan;
497
498 if (state == NULL || changes == NULL) {
499 return;
500 }
501
502 /* cache the generation count */
503 generation_count = state->generation_count;
504
505 if (state->ipv4_count) {
506 for (i = 0, scan = state->nwi_ifstates;
507 i < state->ipv4_count; i++, scan++) {
508 if (_nwi_ifstate_has_changed(changes, scan->ifname) == TRUE) {
509 /* Update the interface generation count */
510 _nwi_ifstate_set_generation(scan, generation_count);
511 } else {
512 nwi_ifstate_t old_ifstate;
513
514 old_ifstate = nwi_state_get_ifstate_with_name(old_state,
515 AF_INET,
516 scan->ifname);
517
518 /* Set the current generation count */
519 _nwi_ifstate_set_generation(scan,
520 old_ifstate->if_generation_count);
521 }
522 }
523 }
524
525 if (state->ipv6_count) {
526 for (i = 0, scan = state->nwi_ifstates + state->ipv6_start;
527 i < state->ipv6_count; i++, scan++) {
528 /* The generation count has been already updated in
529 * the ipv4 case, just skip it. */
530 if (nwi_ifstate_get_generation(scan) ==
531 generation_count) {
532 continue;
533 }
534 if (_nwi_ifstate_has_changed(changes, scan->ifname) == TRUE) {
535 /* update the interface generation count */
536 _nwi_ifstate_set_generation(scan, generation_count);
537 } else {
538 nwi_ifstate_t old_ifstate;
539
540 old_ifstate = nwi_state_get_ifstate_with_name(old_state,
541 AF_INET6,
542 scan->ifname);
543 assert(old_ifstate != NULL);
544
545 /* Set the current generation count */
546 _nwi_ifstate_set_generation(scan,
547 old_ifstate->if_generation_count);
548 }
549 }
550 }
551 return;
552 }