]> git.saurik.com Git - apple/configd.git/blob - nwi/network_information_priv.c
configd-596.13.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__ unsigned int
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 int 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 (sizeof(nwi_state) + nwi_state_compute_size((elems+1) * 2)):0;
79
80 /* Should we reallocate? */
81 if (old_state != NULL) {
82 if (old_state->size >= new_size) {
83 return (old_state);
84 }
85 }
86
87 state = malloc(new_size);
88 if (state == NULL) {
89 return NULL;
90 }
91
92 bzero(state, new_size);
93 state->size = new_size;
94
95 /*
96 * v4 list is stored 0 to elems,
97 * v6 list is stored elems + 1 to 2 * elems + 2
98 */
99 state->ipv6_start = elems + 1;
100
101 if (old_state != NULL) {
102 state->ipv6_count = old_state->ipv6_count;
103 if (state->ipv6_count > 0) {
104 bcopy((void*) &old_state->nwi_ifstates[old_state->ipv6_start],
105 (void*) &state->nwi_ifstates[state->ipv6_start],
106 old_state->ipv6_count * sizeof(nwi_ifstate));
107 }
108
109 state->ipv4_count = old_state->ipv4_count;
110 if (state->ipv4_count > 0) {
111 bcopy((void*) old_state->nwi_ifstates,
112 (void*) state->nwi_ifstates,
113 old_state->ipv4_count * sizeof(nwi_ifstate));
114 }
115
116 free(old_state);
117 } else {
118 state->ipv4_count = 0;
119 state->ipv6_count = 0;
120 }
121 nwi_state_set_last(state, AF_INET);
122 nwi_state_set_last(state, AF_INET6);
123
124 state->ref = 1;
125 state->svr = FALSE;
126 return state;
127 }
128
129 static __inline__
130 nwi_ifstate_t
131 nwi_ifstate_get_last(nwi_state_t state, int af, uint32_t** last)
132 {
133 uint32_t* count;
134 int idx;
135
136 assert(state != NULL);
137
138 count = (af == AF_INET) ? &state->ipv4_count
139 : &state->ipv6_count;
140
141 idx = (af == AF_INET) ? state->ipv4_count
142 : (state->ipv6_start + state->ipv6_count);
143
144 *last = count;
145
146 return &state->nwi_ifstates[idx];
147 }
148
149 __private_extern__
150 void
151 nwi_ifstate_set_signature(nwi_ifstate_t ifstate, uint8_t * signature)
152 {
153 bcopy(signature, ifstate->signature, sizeof(ifstate->signature));
154 ifstate->flags |= NWI_IFSTATE_FLAGS_HAS_SIGNATURE;
155 return;
156 }
157
158 __private_extern__
159 nwi_ifstate_t
160 nwi_insert_ifstate(nwi_state_t state,
161 const char * ifname, int af,
162 uint64_t flags, Rank rank,
163 void * ifa,
164 struct sockaddr * vpn_server_addr,
165 uint32_t reach_flags)
166 {
167 nwi_ifstate_t ifstate;
168
169 /* Will only insert unique elements in the list */
170 ifstate = nwi_state_get_ifstate_with_name(state, af, ifname);
171
172 /* Already present, just ignore it */
173 if (ifstate != NULL) {
174 if (ifstate->rank < rank) {
175 return NULL;
176 }
177 }
178
179 if (ifstate == NULL) {
180 uint32_t *last;
181
182 /* We need to append it as the last element */
183 ifstate = nwi_ifstate_get_last(state, af, &last);
184 bzero(ifstate, sizeof(*ifstate));
185 strlcpy(ifstate->ifname, ifname, sizeof(ifstate->ifname));
186 ifstate->af = af;
187 (*last)++;
188 }
189
190 /* We need to update the address/rank/flag fields for the existing/new
191 * element */
192 if (ifa != NULL) {
193 switch (af) {
194 case AF_INET:
195 ifstate->iaddr = *((struct in_addr *) ifa);
196 break;
197 case AF_INET6:
198 ifstate->iaddr6 = *((struct in6_addr *) ifa);
199 break;
200 default:
201 break;
202 }
203
204 }
205
206 if (vpn_server_addr != NULL && vpn_server_addr->sa_family != 0) {
207 _nwi_ifstate_set_vpn_server(ifstate, vpn_server_addr);
208 } else {
209 _nwi_ifstate_set_vpn_server(ifstate, NULL);
210 }
211
212 ifstate->reach_flags = reach_flags;
213 ifstate->rank = rank;
214 ifstate->flags = flags;
215
216 return ifstate;
217 }
218
219 __private_extern__
220 void
221 nwi_state_clear(nwi_state_t state, int af)
222 {
223 uint32_t* count;
224
225 count = (af == AF_INET)
226 ?&state->ipv4_count:&state->ipv6_count;
227
228 *count = 0;
229 nwi_state_set_last(state, af);
230 return;
231
232 }
233
234 __private_extern__
235 void
236 nwi_state_set_last(nwi_state_t state, int af)
237 {
238 int last_elem_idx;
239
240 if (state == NULL) {
241 return;
242 }
243
244 /* The last element is an element with the flags set as
245 * NWI_IFSTATE_FLAGS_NOT_IN_LIST */
246 last_elem_idx = (af == AF_INET) ? state->ipv4_count
247 : (state->ipv6_start + state->ipv6_count);
248
249 state->nwi_ifstates[last_elem_idx].ifname[0] = '\0';
250 state->nwi_ifstates[last_elem_idx].flags = NWI_IFSTATE_FLAGS_NOT_IN_LIST;
251 }
252
253 #define unchanged ""
254 #define added "+"
255 #define deleted "-"
256 #define changed "!"
257 #define rank_change "R"
258
259 __private_extern__
260 void *
261 nwi_ifstate_get_address(nwi_ifstate_t ifstate)
262 {
263 return (void *)&ifstate->iaddr;
264 }
265
266 __private_extern__
267 const char *
268 nwi_ifstate_get_diff_str(nwi_ifstate_t ifstate)
269 {
270 if (strcmp(ifstate->diff_str, rank_change) == 0) {
271 return changed;
272 }
273 return ifstate->diff_str;
274 }
275
276 static
277 inline
278 boolean_t
279 nwi_ifstate_has_changed(nwi_ifstate_t ifstate1, nwi_ifstate_t ifstate2)
280 {
281 if (ifstate1->flags != ifstate2->flags) {
282 return TRUE;
283 }
284
285 if (ifstate1->af == AF_INET) {
286 if (memcmp(&ifstate1->iaddr, &ifstate2->iaddr, sizeof(struct in_addr)) != 0) {
287 return TRUE;
288 }
289 } else {
290 if (memcmp(&ifstate1->iaddr6, &ifstate2->iaddr6, sizeof(struct in6_addr)) != 0) {
291 return TRUE;
292 }
293 }
294 return FALSE;
295 }
296
297 static
298 inline
299 nwi_ifstate_t
300 nwi_ifstate_append(nwi_state_t state, nwi_ifstate_t scan)
301 {
302 nwi_ifstate_t new_ifstate = NULL;
303 uint32_t *last;
304
305 new_ifstate = nwi_ifstate_get_last(state, scan->af, &last);
306 memcpy(new_ifstate, scan, sizeof(*scan));
307 (*last)++;
308 return new_ifstate;
309 }
310
311 static
312 inline
313 void
314 nwi_ifstate_set_diff_str(nwi_ifstate_t ifstate, const char *diff_str)
315 {
316 ifstate->diff_str = diff_str;
317 }
318
319 static
320 void
321 nwi_ifstate_set_added_or_changed_str(nwi_state_t state, nwi_state_t old_state, nwi_ifstate_t ifstate)
322 {
323 nwi_ifstate_t existing_ifstate, new_ifstate;
324
325 existing_ifstate = nwi_state_get_ifstate_with_name(old_state,
326 ifstate->af,
327 nwi_ifstate_get_ifname(ifstate));
328
329 /* Add the element that is not in the store */
330 new_ifstate = nwi_ifstate_append(state, ifstate);
331
332 /* These are potentially "added" elements unless they are
333 * in the old list */
334 nwi_ifstate_set_diff_str(new_ifstate, added);
335
336 if (existing_ifstate != NULL) {
337 if (nwi_ifstate_has_changed(existing_ifstate, new_ifstate) == TRUE) {
338 nwi_ifstate_set_diff_str(new_ifstate, changed);
339 } else if (existing_ifstate->rank != new_ifstate->rank) {
340 nwi_ifstate_set_diff_str(new_ifstate, rank_change);
341 } else {
342 nwi_ifstate_set_diff_str(new_ifstate, unchanged);
343 }
344 }
345 return;
346 }
347
348 static
349 void
350 nwi_ifstate_set_removed_str(nwi_state_t state, nwi_ifstate_t ifstate)
351 {
352 nwi_ifstate_t existing_ifstate;
353
354 existing_ifstate = nwi_state_get_ifstate_with_name(state,
355 ifstate->af,
356 nwi_ifstate_get_ifname(ifstate));
357
358 /* Any elements that has not been added means that they are removed */
359 if (existing_ifstate == NULL) {
360 nwi_ifstate_t new_ifstate = nwi_ifstate_append(state, ifstate);
361 nwi_ifstate_set_diff_str(new_ifstate, deleted);
362 }
363 return;
364 }
365
366 static
367 void
368 nwi_state_merge_added(nwi_state_t state, nwi_state_t old_state,
369 nwi_state_t new_state)
370 {
371 int i;
372 nwi_ifstate_t scan;
373
374 if (new_state == NULL) {
375 return;
376 }
377
378 if (new_state->ipv4_count) {
379 for (i = 0, scan = new_state->nwi_ifstates;
380 i < new_state->ipv4_count; i++, scan++) {
381 nwi_ifstate_set_added_or_changed_str(state, old_state, scan);
382 }
383 nwi_state_set_last(state, AF_INET);
384 }
385
386 if (new_state->ipv6_count) {
387 for (i = 0, scan = new_state->nwi_ifstates + new_state->ipv6_start;
388 i < new_state->ipv6_count; i++, scan++) {
389 nwi_ifstate_set_added_or_changed_str(state, old_state, scan);
390 }
391 nwi_state_set_last(state, AF_INET6);
392 }
393 return;
394 }
395
396 void
397 nwi_state_merge_removed(nwi_state_t state, nwi_state_t old_state)
398 {
399 int i;
400 nwi_ifstate_t scan;
401
402 if (old_state == NULL) {
403 return;
404 }
405
406 if (old_state->ipv4_count) {
407 for (i = 0, scan = old_state->nwi_ifstates;
408 i < old_state->ipv4_count; i++, scan++) {
409 nwi_ifstate_set_removed_str(state, scan);
410 }
411 nwi_state_set_last(state, AF_INET);
412 }
413
414 if (old_state->ipv6_count) {
415 for (i = 0, scan = old_state->nwi_ifstates + old_state->ipv6_start;
416 i < old_state->ipv6_count; i++, scan++) {
417 nwi_ifstate_set_removed_str(state, scan);
418 }
419 nwi_state_set_last(state, AF_INET6);
420 }
421 return;
422 }
423
424 __private_extern__
425 nwi_state_t
426 nwi_state_diff(nwi_state_t old_state, nwi_state_t new_state)
427 {
428 nwi_state_t diff;
429 int total_count = 0;
430
431 if (old_state != NULL) {
432 total_count = old_state->ipv4_count + old_state->ipv6_count;
433 }
434
435 if (new_state != NULL) {
436 total_count += new_state->ipv4_count + new_state->ipv6_count;
437 }
438
439 if (total_count == 0) {
440 return NULL;
441 }
442
443 diff = nwi_state_new(NULL, total_count);
444
445 nwi_state_merge_added(diff, old_state, new_state);
446 nwi_state_merge_removed(diff, old_state);
447
448 /* Diff consists of a nwi_state_t with annotated diff_str's */
449 return diff;
450 }
451
452 static __inline__
453 void
454 _nwi_ifstate_set_generation(nwi_ifstate_t ifstate, uint64_t generation_count)
455 {
456 ifstate->if_generation_count = generation_count;
457
458 return;
459 }
460
461 static
462 boolean_t
463 _nwi_ifstate_has_changed(nwi_state_t state, const char * ifname)
464 {
465 nwi_ifstate_t ifstate;
466
467 /* If either the v4 ifstate or the v6 ifstate
468 * has changed, then report that the interface has changed */
469 ifstate = nwi_state_get_ifstate_with_name(state,
470 AF_INET,
471 ifname);
472
473 if (ifstate != NULL
474 && ifstate->diff_str != NULL
475 && strcmp(ifstate->diff_str, unchanged) != 0
476 && strcmp(ifstate->diff_str, rank_change) != 0) {
477 return (TRUE);
478 }
479
480 ifstate = nwi_state_get_ifstate_with_name(state,
481 AF_INET6,
482 ifname);
483
484 if (ifstate != NULL
485 && ifstate->diff_str != NULL
486 && strcmp(ifstate->diff_str, unchanged) != 0
487 && strcmp(ifstate->diff_str, rank_change) != 0) {
488 return (TRUE);
489 }
490 return (FALSE);
491 }
492
493 __private_extern__
494 void
495 _nwi_state_update_interface_generations(nwi_state_t old_state, nwi_state_t state, nwi_state_t changes)
496 {
497 int i;
498 uint64_t generation_count;
499 nwi_ifstate_t scan;
500
501 if (state == NULL || changes == NULL) {
502 return;
503 }
504
505 /* cache the generation count */
506 generation_count = state->generation_count;
507
508 if (state->ipv4_count) {
509 for (i = 0, scan = state->nwi_ifstates;
510 i < state->ipv4_count; i++, scan++) {
511 if (_nwi_ifstate_has_changed(changes, scan->ifname) == TRUE) {
512 /* Update the interface generation count */
513 _nwi_ifstate_set_generation(scan, generation_count);
514 } else {
515 nwi_ifstate_t old_ifstate;
516
517 old_ifstate = nwi_state_get_ifstate_with_name(old_state,
518 AF_INET,
519 scan->ifname);
520
521 /* Set the current generation count */
522 _nwi_ifstate_set_generation(scan,
523 old_ifstate->if_generation_count);
524 }
525 }
526 }
527
528 if (state->ipv6_count) {
529 for (i = 0, scan = state->nwi_ifstates + state->ipv6_start;
530 i < state->ipv6_count; i++, scan++) {
531 /* The generation count has been already updated in
532 * the ipv4 case, just skip it. */
533 if (nwi_ifstate_get_generation(scan) ==
534 generation_count) {
535 continue;
536 }
537 if (_nwi_ifstate_has_changed(changes, scan->ifname) == TRUE) {
538 /* update the interface generation count */
539 _nwi_ifstate_set_generation(scan, generation_count);
540 } else {
541 nwi_ifstate_t old_ifstate;
542
543 old_ifstate = nwi_state_get_ifstate_with_name(old_state,
544 AF_INET6,
545 scan->ifname);
546 assert(old_ifstate != NULL);
547
548 /* Set the current generation count */
549 _nwi_ifstate_set_generation(scan,
550 old_ifstate->if_generation_count);
551 }
552 }
553 }
554 return;
555 }