]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/LinkConfiguration.c
configd-395.10.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / LinkConfiguration.c
1 /*
2 * Copyright (c) 2002-2007, 2010, 2011 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 /*
25 * Modification History
26 *
27 * October 21, 2000 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32 #include <unistd.h>
33 #define KERNEL_PRIVATE
34 #include <sys/ioctl.h>
35 #undef KERNEL_PRIVATE
36 #include <sys/socket.h>
37 #include <net/ethernet.h>
38 #include <net/if.h>
39 #include <net/if_vlan_var.h>
40 #include <net/if_media.h>
41 #include <net/if_types.h>
42 #include <netinet/in.h>
43 #include <netinet/ip6.h> // for IPV6_MMTU
44
45 #include <SystemConfiguration/SystemConfiguration.h>
46 #include <SystemConfiguration/SCPrivate.h> // for SCLog()
47 #include "SCNetworkConfigurationInternal.h" // for __SCNetworkInterfaceCreatePrivate
48 #include <SystemConfiguration/SCValidation.h>
49
50 #include <IOKit/IOKitLib.h>
51 #include <IOKit/network/IONetworkInterface.h>
52 #include <IOKit/network/IONetworkController.h>
53 #include "dy_framework.h"
54
55
56 #pragma mark -
57 #pragma mark Capabilities
58
59
60 // the following table needs to keep the capabilitiy names and values
61 // between the <SystemConfiguration/SCSchemaDefinitionsPrivate.h> and
62 // <net/if.h> headers in sync.
63 static const struct {
64 const CFStringRef *name;
65 Boolean readwrite;
66 int val;
67 } capabilityMappings[] = {
68 #ifdef SIOCGIFCAP
69 { &kSCPropNetEthernetCapabilityRXCSUM, TRUE, IFCAP_RXCSUM }, // can offload checksum on RX
70 { &kSCPropNetEthernetCapabilityTXCSUM, TRUE, IFCAP_TXCSUM }, // can offload checksum on TX
71 { &kSCPropNetEthernetCapabilityVLAN_MTU, FALSE, IFCAP_VLAN_MTU }, // VLAN-compatible MTU
72 { &kSCPropNetEthernetCapabilityVLAN_HWTAGGING, FALSE, IFCAP_VLAN_HWTAGGING }, // hardware VLAN tag support
73 { &kSCPropNetEthernetCapabilityJUMBO_MTU, FALSE, IFCAP_JUMBO_MTU }, // 9000 byte MTU supported
74 { &kSCPropNetEthernetCapabilityTSO, TRUE, IFCAP_TSO }, // can do TCP/TCP6 Segmentation Offload
75 { &kSCPropNetEthernetCapabilityTSO4, FALSE, IFCAP_TSO4 }, // can do TCP Segmentation Offload
76 { &kSCPropNetEthernetCapabilityTSO6, FALSE, IFCAP_TSO6 }, // can do TCP6 Segmentation Offload
77 { &kSCPropNetEthernetCapabilityLRO, TRUE, IFCAP_LRO }, // can do Large Receive Offload
78 { &kSCPropNetEthernetCapabilityAV, TRUE, IFCAP_AV }, // can do 802.1 AV Bridging
79 #endif // SIOCGIFCAP
80 };
81
82
83 static CFIndex
84 findCapability(CFStringRef capability)
85 {
86 CFIndex i;
87
88 for (i = 0; i < sizeof(capabilityMappings) / sizeof(capabilityMappings[0]); i++) {
89 if (CFEqual(capability, *capabilityMappings[i].name)) {
90 return i;
91 }
92 }
93
94 return kCFNotFound;
95 }
96
97
98 static Boolean
99 __getCapabilities(CFStringRef interfaceName,
100 int *current,
101 int *available)
102 {
103 #ifdef SIOCGIFCAP
104 struct ifreq ifr;
105 Boolean ok = FALSE;
106 int sock = -1;
107
108 bzero((void *)&ifr, sizeof(ifr));
109 if (_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII) == NULL) {
110 SCLog(TRUE, LOG_ERR, CFSTR("could not convert interface name"));
111 _SCErrorSet(kSCStatusInvalidArgument);
112 return FALSE;
113 }
114
115 sock = socket(AF_INET, SOCK_DGRAM, 0);
116 if (sock == -1) {
117 _SCErrorSet(errno);
118 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
119 return FALSE;
120 }
121
122 if (ioctl(sock, SIOCGIFCAP, (caddr_t)&ifr) == -1) {
123 _SCErrorSet(errno);
124 SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCGIFCAP) failed: %s"), strerror(errno));
125 goto done;
126 }
127
128 if (current != NULL) *current = ifr.ifr_curcap;
129 if (available != NULL) *available = ifr.ifr_reqcap;
130
131 ok = TRUE;
132
133 done :
134
135 (void)close(sock);
136 return ok;
137 #else // SIOCGIFCAP
138 if (current != NULL) *current = 0;
139 if (available != NULL) *available = 0;
140 return TRUE;
141 #endif // SIOCGIFCAP
142 }
143
144
145 int
146 __SCNetworkInterfaceCreateCapabilities(SCNetworkInterfaceRef interface,
147 int capability_base,
148 CFDictionaryRef capability_options)
149 {
150 int cap_available = 0;
151 int cap_current = capability_base;
152 CFIndex i;
153 CFStringRef interfaceName;
154
155 if (!isA_SCNetworkInterface(interface)) {
156 _SCErrorSet(kSCStatusInvalidArgument);
157 goto done;
158 }
159
160 interfaceName = SCNetworkInterfaceGetBSDName(interface);
161 if (interfaceName == NULL) {
162 _SCErrorSet(kSCStatusInvalidArgument);
163 goto done;
164 }
165
166 if (!__getCapabilities(interfaceName,
167 (capability_base == -1) ? &cap_current : NULL,
168 &cap_available)) {
169 goto done;
170 }
171
172 if (cap_available == 0) {
173 goto done;
174 }
175
176 if (capability_options == NULL) {
177 goto done;
178 }
179
180 for (i = 0; i < sizeof(capabilityMappings) / sizeof(capabilityMappings[0]); i++) {
181 int cap_val;
182 CFTypeRef val;
183
184 if (((cap_available & capabilityMappings[i].val) != 0) &&
185 capabilityMappings[i].readwrite &&
186 CFDictionaryGetValueIfPresent(capability_options,
187 *capabilityMappings[i].name,
188 &val) &&
189 isA_CFNumber(val) &&
190 CFNumberGetValue(val, kCFNumberIntType, &cap_val)) {
191 // update capability
192 if (cap_val != 0) {
193 cap_current |= (cap_available & capabilityMappings[i].val);
194 } else {
195 cap_current &= ~capabilityMappings[i].val;
196 }
197
198 // don't process again
199 cap_available &= ~capabilityMappings[i].val;
200 }
201 }
202
203 done :
204
205 return cap_current;
206 }
207
208
209 CFTypeRef
210 SCNetworkInterfaceCopyCapability(SCNetworkInterfaceRef interface,
211 CFStringRef capability)
212 {
213 int cap_current = 0;
214 int cap_available = 0;
215 int cap_val;
216 CFIndex i;
217 CFStringRef interfaceName;
218 CFTypeRef val = NULL;
219
220 if (!isA_SCNetworkInterface(interface)) {
221 _SCErrorSet(kSCStatusInvalidArgument);
222 return NULL;
223 }
224
225 interfaceName = SCNetworkInterfaceGetBSDName(interface);
226 if (interfaceName == NULL) {
227 _SCErrorSet(kSCStatusInvalidArgument);
228 return NULL;
229 }
230
231 if (!__getCapabilities(interfaceName, &cap_current, &cap_available)) {
232 return NULL;
233 }
234
235 if (capability == NULL) {
236 CFMutableDictionaryRef all = NULL;
237
238 // if ALL capabilities requested
239 for (i = 0; i < sizeof(capabilityMappings) / sizeof(capabilityMappings[0]); i++) {
240 if ((cap_available & capabilityMappings[i].val) == capabilityMappings[i].val) {
241 if (all == NULL) {
242 all = CFDictionaryCreateMutable(NULL,
243 0,
244 &kCFTypeDictionaryKeyCallBacks,
245 &kCFTypeDictionaryValueCallBacks);
246 }
247 cap_val = ((cap_current & capabilityMappings[i].val) == capabilityMappings[i].val) ? 1 : 0;
248 val = CFNumberCreate(NULL, kCFNumberIntType, &cap_val);
249 CFDictionarySetValue(all, *capabilityMappings[i].name, val);
250 CFRelease(val);
251 cap_available &= ~capabilityMappings[i].val;
252 }
253 }
254
255 val = all;
256 } else {
257 i = findCapability(capability);
258 if (i == kCFNotFound) {
259 // if unknown capability
260 _SCErrorSet(kSCStatusInvalidArgument);
261 return NULL;
262 }
263
264 if ((cap_available & capabilityMappings[i].val) != capabilityMappings[i].val) {
265 // if capability not available
266 _SCErrorSet(kSCStatusInvalidArgument);
267 return NULL;
268 }
269
270 cap_val = ((cap_current & capabilityMappings[i].val) == capabilityMappings[i].val) ? 1 : 0;
271 val = CFNumberCreate(NULL, kCFNumberIntType, &cap_val);
272 }
273
274 return val;
275 }
276
277
278 Boolean
279 SCNetworkInterfaceSetCapability(SCNetworkInterfaceRef interface,
280 CFStringRef capability,
281 CFTypeRef newValue)
282 {
283 int cap_available = 0;
284 CFDictionaryRef configuration;
285 CFIndex i;
286 CFStringRef interfaceName;
287 CFMutableDictionaryRef newConfiguration = NULL;
288 Boolean ok = FALSE;
289
290 if (!isA_SCNetworkInterface(interface)) {
291 _SCErrorSet(kSCStatusInvalidArgument);
292 return FALSE;
293 }
294
295 interfaceName = SCNetworkInterfaceGetBSDName(interface);
296 if (interfaceName == NULL) {
297 // if no interface name
298 _SCErrorSet(kSCStatusInvalidArgument);
299 return FALSE;
300 }
301
302 i = findCapability(capability);
303 if (i == kCFNotFound) {
304 // if unknown capability
305 _SCErrorSet(kSCStatusInvalidArgument);
306 return FALSE;
307 }
308
309 if (!capabilityMappings[i].readwrite) {
310 // if not read-write
311 _SCErrorSet(kSCStatusInvalidArgument);
312 return FALSE;
313 }
314
315 if ((newValue != NULL) && !isA_CFNumber(newValue)) {
316 // all values must (for now) be CFNumber[0 or 1]'s
317 _SCErrorSet(kSCStatusInvalidArgument);
318 return FALSE;
319 }
320
321 if (!__getCapabilities(interfaceName, NULL, &cap_available)) {
322 return FALSE;
323 }
324
325 if ((cap_available & capabilityMappings[i].val) == 0) {
326 // if capability not available
327 _SCErrorSet(kSCStatusInvalidArgument);
328 return FALSE;
329 }
330
331 configuration = SCNetworkInterfaceGetConfiguration(interface);
332 if (configuration == NULL) {
333 newConfiguration = CFDictionaryCreateMutable(NULL,
334 0,
335 &kCFTypeDictionaryKeyCallBacks,
336 &kCFTypeDictionaryValueCallBacks);
337 } else {
338 newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
339 CFDictionaryRemoveValue(newConfiguration, kSCResvInactive);
340 }
341
342 if ((newValue != NULL)) {
343 CFDictionarySetValue(newConfiguration, capability, newValue);
344 } else {
345 CFDictionaryRemoveValue(newConfiguration, capability);
346 if (CFDictionaryGetCount(newConfiguration) == 0) {
347 CFRelease(newConfiguration);
348 newConfiguration = NULL;
349 }
350 }
351
352 ok = SCNetworkInterfaceSetConfiguration(interface, newConfiguration);
353 if (newConfiguration != NULL) CFRelease(newConfiguration);
354
355 return ok;
356 }
357
358
359 #pragma mark -
360 #pragma mark Media Options
361
362
363 static const struct ifmedia_description ifm_subtype_shared_descriptions[] =
364 IFM_SUBTYPE_SHARED_DESCRIPTIONS;
365
366 static const struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
367 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
368
369 static const struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
370 IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
371
372 static const struct ifmedia_description ifm_shared_option_descriptions[] =
373 IFM_SHARED_OPTION_DESCRIPTIONS;
374
375 static const struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
376 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
377
378 static const struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
379 IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
380
381
382 static void
383 __freeMediaList(struct ifmediareq *ifm)
384 {
385 if (ifm->ifm_ulist != NULL) CFAllocatorDeallocate(NULL, ifm->ifm_ulist);
386 CFAllocatorDeallocate(NULL, ifm);
387 return;
388 }
389
390
391 static struct ifmediareq *
392 __copyMediaList(CFStringRef interfaceName)
393 {
394 struct ifmediareq *ifm;
395 Boolean ok = FALSE;
396 int sock = -1;
397
398 ifm = (struct ifmediareq *)CFAllocatorAllocate(NULL, sizeof(struct ifmediareq), 0);
399 bzero((void *)ifm, sizeof(*ifm));
400
401 if (_SC_cfstring_to_cstring(interfaceName, ifm->ifm_name, sizeof(ifm->ifm_name), kCFStringEncodingASCII) == NULL) {
402 SCLog(TRUE, LOG_ERR, CFSTR("could not convert interface name"));
403 goto done;
404 }
405
406 sock = socket(AF_INET, SOCK_DGRAM, 0);
407 if (sock == -1) {
408 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
409 goto done;
410 }
411
412 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)ifm) == -1) {
413 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
414 goto done;
415 }
416
417 if (ifm->ifm_count > 0) {
418 ifm->ifm_ulist = (int *)CFAllocatorAllocate(NULL, ifm->ifm_count * sizeof(int), 0);
419 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)ifm) == -1) {
420 SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
421 goto done;
422 }
423 }
424
425 ok = TRUE;
426
427 done :
428
429 if (sock != -1) (void)close(sock);
430 if (!ok) {
431 __freeMediaList(ifm);
432 ifm = NULL;
433 _SCErrorSet(kSCStatusFailed);
434 }
435 return ifm;
436 }
437
438
439 static CFDictionaryRef
440 __createMediaDictionary(int media_options, Boolean filter)
441 {
442 CFMutableDictionaryRef dict = NULL;
443 int i;
444 const struct ifmedia_description *option_descriptions = NULL;
445 CFMutableArrayRef options = NULL;
446 const struct ifmedia_description *subtype_descriptions = NULL;
447 CFStringRef val;
448
449 if (filter &&
450 ((IFM_SUBTYPE(media_options) == IFM_NONE) ||
451 ((IFM_OPTIONS(media_options) & IFM_LOOP) != 0))) {
452 return NULL; /* filter */
453 }
454
455 switch (IFM_TYPE(media_options)) {
456 case IFM_ETHER :
457 option_descriptions = ifm_subtype_ethernet_option_descriptions;
458 subtype_descriptions = ifm_subtype_ethernet_descriptions;
459 break;
460 case IFM_IEEE80211 :
461 option_descriptions = ifm_subtype_ieee80211_option_descriptions;
462 subtype_descriptions = ifm_subtype_ieee80211_descriptions;
463 break;
464 default :
465 return NULL;
466 }
467
468 dict = CFDictionaryCreateMutable(NULL,
469 0,
470 &kCFTypeDictionaryKeyCallBacks,
471 &kCFTypeDictionaryValueCallBacks);
472
473 /* subtype */
474
475 val = NULL;
476 for (i = 0; !val && ifm_subtype_shared_descriptions[i].ifmt_string; i++) {
477 if (IFM_SUBTYPE(media_options) == ifm_subtype_shared_descriptions[i].ifmt_word) {
478 val = CFStringCreateWithCString(NULL,
479 ifm_subtype_shared_descriptions[i].ifmt_string,
480 kCFStringEncodingASCII);
481 break;
482 }
483 }
484
485 if (subtype_descriptions != NULL) {
486 for (i = 0; !val && subtype_descriptions[i].ifmt_string; i++) {
487 if (IFM_SUBTYPE(media_options) == subtype_descriptions[i].ifmt_word) {
488 val = CFStringCreateWithCString(NULL,
489 subtype_descriptions[i].ifmt_string,
490 kCFStringEncodingASCII);
491 break;
492 }
493 }
494 }
495
496 if (val) {
497 CFDictionaryAddValue(dict, kSCPropNetEthernetMediaSubType, val);
498 CFRelease(val);
499 }
500
501 /* options */
502
503 options = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
504
505 for (i = 0; (IFM_OPTIONS(media_options) != 0) && (ifm_shared_option_descriptions[i].ifmt_string != NULL); i++) {
506 if ((media_options & ifm_shared_option_descriptions[i].ifmt_word) != 0) {
507 val = CFStringCreateWithCString(NULL,
508 ifm_shared_option_descriptions[i].ifmt_string,
509 kCFStringEncodingASCII);
510 CFArrayAppendValue(options, val);
511 CFRelease(val);
512
513 media_options &= ~ifm_shared_option_descriptions[i].ifmt_word;
514 }
515 }
516
517 if (option_descriptions != NULL) {
518 for (i = 0; (IFM_OPTIONS(media_options) != 0) && (option_descriptions[i].ifmt_string != NULL); i++) {
519 if ((media_options & option_descriptions[i].ifmt_word) != 0) {
520 val = CFStringCreateWithCString(NULL,
521 option_descriptions[i].ifmt_string,
522 kCFStringEncodingASCII);
523 CFArrayAppendValue(options, val);
524 CFRelease(val);
525
526 media_options &= ~option_descriptions[i].ifmt_word;
527 }
528 }
529 }
530
531 CFDictionaryAddValue(dict, kSCPropNetEthernetMediaOptions, options);
532 CFRelease(options);
533
534 return dict;
535 }
536
537
538 int
539 __SCNetworkInterfaceCreateMediaOptions(SCNetworkInterfaceRef interface, CFDictionaryRef media_options)
540 {
541 CFIndex i;
542 struct ifmediareq *ifm;
543 int ifm_new = -1;
544 CFStringRef interfaceName;
545 Boolean match;
546 CFIndex n;
547 const struct ifmedia_description *option_descriptions = NULL;
548 CFArrayRef options;
549 char *str;
550 const struct ifmedia_description *subtype_descriptions = NULL;
551 CFStringRef val;
552
553 if (!isA_SCNetworkInterface(interface)) {
554 _SCErrorSet(kSCStatusInvalidArgument);
555 return -1;
556 }
557
558 interfaceName = SCNetworkInterfaceGetBSDName(interface);
559 if (interfaceName == NULL) {
560 _SCErrorSet(kSCStatusInvalidArgument);
561 return -1;
562 }
563
564 /* set type */
565
566 ifm = __copyMediaList(interfaceName);
567 if (ifm != NULL) {
568 if (ifm->ifm_count > 0) {
569 ifm_new = IFM_TYPE(ifm->ifm_ulist[0]);
570 }
571 __freeMediaList(ifm);
572 }
573
574 if (ifm_new == -1) {
575 // if we cannot determine the media type for the interface
576 return -1;
577 }
578
579 switch (IFM_TYPE(ifm_new)) {
580 case IFM_ETHER :
581 option_descriptions = ifm_subtype_ethernet_option_descriptions;
582 subtype_descriptions = ifm_subtype_ethernet_descriptions;
583 break;
584 case IFM_IEEE80211 :
585 option_descriptions = ifm_subtype_ieee80211_option_descriptions;
586 subtype_descriptions = ifm_subtype_ieee80211_descriptions;
587 break;
588 }
589
590 /* set subtype */
591
592 val = CFDictionaryGetValue(media_options, kSCPropNetEthernetMediaSubType);
593 if (!isA_CFString(val)) {
594 return -1;
595 }
596
597 str = _SC_cfstring_to_cstring(val, NULL, 0, kCFStringEncodingASCII);
598 if (str == NULL) {
599 return -1;
600 }
601
602 match = FALSE;
603 for (i = 0; !match && ifm_subtype_shared_descriptions[i].ifmt_string; i++) {
604 if (strcasecmp(str, ifm_subtype_shared_descriptions[i].ifmt_string) == 0) {
605 ifm_new |= ifm_subtype_shared_descriptions[i].ifmt_word;
606 match = TRUE;
607 break;
608 }
609 }
610
611 if (subtype_descriptions != NULL) {
612 for (i = 0; !match && subtype_descriptions[i].ifmt_string; i++) {
613 if (strcasecmp(str, subtype_descriptions[i].ifmt_string) == 0) {
614 ifm_new |= subtype_descriptions[i].ifmt_word;
615 match = TRUE;
616 break;
617 }
618 }
619 }
620
621 CFAllocatorDeallocate(NULL, str);
622
623 if (!match) {
624 return -1; /* if no subtype */
625 }
626
627 /* set options */
628
629 options = CFDictionaryGetValue(media_options, kSCPropNetEthernetMediaOptions);
630 if (!isA_CFArray(options)) {
631 return -1;
632 }
633
634 n = CFArrayGetCount(options);
635 for (i = 0; i < n; i++) {
636 CFIndex j;
637
638 val = CFArrayGetValueAtIndex(options, i);
639 if (!isA_CFString(val)) {
640 return -1;
641 }
642
643 str = _SC_cfstring_to_cstring(val, NULL, 0, kCFStringEncodingASCII);
644 if (str == NULL) {
645 return -1;
646 }
647
648
649 match = FALSE;
650 for (j = 0; !match && ifm_shared_option_descriptions[j].ifmt_string; j++) {
651 if (strcasecmp(str, ifm_shared_option_descriptions[j].ifmt_string) == 0) {
652 ifm_new |= ifm_shared_option_descriptions[j].ifmt_word;
653 match = TRUE;
654 break;
655 }
656 }
657
658 if (option_descriptions != NULL) {
659 for (j = 0; !match && option_descriptions[j].ifmt_string; j++) {
660 if (strcasecmp(str, option_descriptions[j].ifmt_string) == 0) {
661 ifm_new |= option_descriptions[j].ifmt_word;
662 match = TRUE;
663 break;
664 }
665 }
666 }
667
668 CFAllocatorDeallocate(NULL, str);
669
670 if (!match) {
671 return -1; /* if no option */
672 }
673 }
674
675 return ifm_new;
676 }
677
678
679 Boolean
680 SCNetworkInterfaceCopyMediaOptions(SCNetworkInterfaceRef interface,
681 CFDictionaryRef *current,
682 CFDictionaryRef *active,
683 CFArrayRef *available,
684 Boolean filter)
685 {
686 int i;
687 struct ifmediareq *ifm;
688 CFStringRef interfaceName;
689
690 if (!isA_SCNetworkInterface(interface)) {
691 _SCErrorSet(kSCStatusInvalidArgument);
692 return FALSE;
693 }
694
695 interfaceName = SCNetworkInterfaceGetBSDName(interface);
696 if (interfaceName == NULL) {
697 _SCErrorSet(kSCStatusInvalidArgument);
698 return FALSE;
699 }
700
701 ifm = __copyMediaList(interfaceName);
702 if (ifm == NULL) {
703 return FALSE;
704 }
705
706 if (active != NULL) *active = NULL;
707 if (current != NULL) *current = NULL;
708 if (available != NULL) {
709 CFMutableArrayRef media_options;
710
711 media_options = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
712 for (i = 0; i < ifm->ifm_count; i++) {
713 CFDictionaryRef options;
714
715 options = __createMediaDictionary(ifm->ifm_ulist[i], filter);
716 if (options == NULL) {
717 continue;
718 }
719
720 if ((active != NULL) && (*active == NULL) && (ifm->ifm_active == ifm->ifm_ulist[i])) {
721 *active = CFRetain(options);
722 }
723
724 if ((current != NULL) && (*current == NULL) && (ifm->ifm_current == ifm->ifm_ulist[i])) {
725 *current = CFRetain(options);
726 }
727
728 if (!CFArrayContainsValue(media_options, CFRangeMake(0, CFArrayGetCount(media_options)), options)) {
729 CFArrayAppendValue(media_options, options);
730 }
731
732 CFRelease(options);
733 }
734 *available = (CFArrayRef)media_options;
735 }
736
737 if ((active != NULL) && (*active == NULL)) {
738 *active = __createMediaDictionary(ifm->ifm_active, FALSE);
739 }
740
741 if ((current != NULL) && (*current == NULL)) {
742 if ((active != NULL) && (ifm->ifm_active == ifm->ifm_current)) {
743 if (*active != NULL) *current = CFRetain(*active);
744 } else {
745 *current = __createMediaDictionary(ifm->ifm_current, FALSE);
746 }
747 }
748
749 __freeMediaList(ifm);
750 return TRUE;
751 }
752
753
754 CFArrayRef
755 SCNetworkInterfaceCopyMediaSubTypes(CFArrayRef available)
756 {
757 CFIndex i;
758 CFIndex n;
759 CFMutableArrayRef subTypes;
760
761 if (!isA_CFArray(available)) {
762 _SCErrorSet(kSCStatusInvalidArgument);
763 return NULL;
764 }
765
766 subTypes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
767
768 n = CFArrayGetCount(available);
769 for (i = 0; i < n; i++) {
770 CFDictionaryRef options;
771 CFStringRef subType;
772
773 options = CFArrayGetValueAtIndex(available, i);
774 if (!isA_CFDictionary(options)) {
775 continue;
776 }
777
778 subType = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType);
779 if (!isA_CFString(subType)) {
780 continue;
781 }
782
783 if (!CFArrayContainsValue(subTypes, CFRangeMake(0, CFArrayGetCount(subTypes)), subType)) {
784 CFArrayAppendValue(subTypes, subType);
785 }
786 }
787
788 if (CFArrayGetCount(subTypes) == 0) {
789 CFRelease(subTypes);
790 subTypes = NULL;
791 _SCErrorSet(kSCStatusOK);
792 }
793
794 return subTypes;
795 }
796
797
798 CFArrayRef
799 SCNetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available,
800 CFStringRef subType)
801 {
802 CFIndex i;
803 CFIndex n;
804 CFMutableArrayRef subTypeOptions;
805
806 if (!isA_CFArray(available)) {
807 _SCErrorSet(kSCStatusInvalidArgument);
808 return NULL;
809 }
810
811 subTypeOptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
812
813 n = CFArrayGetCount(available);
814 for (i = 0; i < n; i++) {
815 CFDictionaryRef options;
816 CFArrayRef mediaOptions;
817 CFStringRef mediaSubType;
818
819 options = CFArrayGetValueAtIndex(available, i);
820 if (!isA_CFDictionary(options)) {
821 continue;
822 }
823
824 mediaSubType = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType);
825 if (!isA_CFString(mediaSubType) || !CFEqual(subType, mediaSubType)) {
826 continue;
827 }
828
829 mediaOptions = CFDictionaryGetValue(options, kSCPropNetEthernetMediaOptions);
830 if (!isA_CFArray(mediaOptions)) {
831 continue;
832 }
833
834 if (!CFArrayContainsValue(subTypeOptions, CFRangeMake(0, CFArrayGetCount(subTypeOptions)), mediaOptions)) {
835 CFArrayAppendValue(subTypeOptions, mediaOptions);
836 }
837 }
838
839 if (CFArrayGetCount(subTypeOptions) == 0) {
840 CFRelease(subTypeOptions);
841 subTypeOptions = NULL;
842 _SCErrorSet(kSCStatusOK);
843 }
844
845 return subTypeOptions;
846 }
847
848
849 Boolean
850 _SCNetworkInterfaceIsPhysicalEthernet(SCNetworkInterfaceRef interface)
851 {
852 int i;
853 struct ifmediareq *ifm;
854 CFStringRef interfaceName;
855 Boolean realEthernet = FALSE;
856
857 if (!isA_SCNetworkInterface(interface)) {
858 _SCErrorSet(kSCStatusInvalidArgument);
859 return FALSE;
860 }
861
862 interfaceName = SCNetworkInterfaceGetBSDName(interface);
863 if (interfaceName == NULL) {
864 _SCErrorSet(kSCStatusInvalidArgument);
865 return FALSE;
866 }
867
868 ifm = __copyMediaList(interfaceName);
869 if (ifm == NULL) {
870 return FALSE;
871 }
872 _SCErrorSet(kSCStatusOK);
873 if (IFM_TYPE(ifm->ifm_current) != IFM_ETHER) {
874 goto done;
875 }
876 if (ifm->ifm_count == 1
877 && IFM_SUBTYPE(ifm->ifm_ulist[0]) == IFM_AUTO) {
878 /* only support autoselect, not really ethernet */
879 goto done;
880 }
881 for (i = 0; i < ifm->ifm_count; i++) {
882 if ((ifm->ifm_ulist[i] & IFM_FDX) != 0) {
883 realEthernet = TRUE;
884 break;
885 }
886 }
887 done:
888 __freeMediaList(ifm);
889 return (realEthernet);
890 }
891
892 static Boolean
893 __getMTULimits(char ifr_name[IFNAMSIZ],
894 int *mtu_min,
895 int *mtu_max)
896 {
897 int ifType = 0;
898 io_iterator_t io_iter = 0;
899 io_registry_entry_t io_interface = 0;
900 io_registry_entry_t io_controller = 0;
901 kern_return_t kr;
902 static mach_port_t masterPort = MACH_PORT_NULL;
903 CFMutableDictionaryRef matchingDict;
904
905 /* look for a matching interface in the IORegistry */
906
907 if (masterPort == MACH_PORT_NULL) {
908 kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
909 if (kr != KERN_SUCCESS) {
910 return FALSE;
911 }
912 }
913
914 matchingDict = IOBSDNameMatching(masterPort, 0, ifr_name);
915 if (matchingDict) {
916 /* Note: IOServiceGetMatchingServices consumes a reference on the 'matchingDict' */
917 kr = IOServiceGetMatchingServices(masterPort, matchingDict, &io_iter);
918 if ((kr == KERN_SUCCESS) && io_iter) {
919 /* should only have a single match */
920 io_interface = IOIteratorNext(io_iter);
921 }
922 if (io_iter) IOObjectRelease(io_iter);
923 }
924
925 if (io_interface) {
926 CFNumberRef num;
927
928 /*
929 * found an interface, get the interface type
930 */
931 num = IORegistryEntryCreateCFProperty(io_interface, CFSTR(kIOInterfaceType), NULL, kNilOptions);
932 if (num) {
933 if (isA_CFNumber(num)) {
934 CFNumberGetValue(num, kCFNumberIntType, &ifType);
935 }
936 CFRelease(num);
937 }
938
939 /*
940 * ...and the property we are REALLY interested is in the controller,
941 * which is the parent of the interface object.
942 */
943 (void)IORegistryEntryGetParentEntry(io_interface, kIOServicePlane, &io_controller);
944 IOObjectRelease(io_interface);
945 } else {
946 /* if no matching interface */
947 return FALSE;
948 }
949
950 if (io_controller) {
951 CFNumberRef num;
952
953 num = IORegistryEntryCreateCFProperty(io_controller, CFSTR(kIOMaxPacketSize), NULL, kNilOptions);
954 if (num) {
955 if (isA_CFNumber(num)) {
956 int value;
957
958 /*
959 * Get the value and subtract the FCS bytes and Ethernet header
960 * sizes from the maximum frame size reported by the controller
961 * to get the MTU size. The 14 byte media header can be found
962 * in the registry, but not the size for the trailing FCS bytes.
963 */
964 CFNumberGetValue(num, kCFNumberIntType, &value);
965
966 if (ifType == IFT_ETHER) {
967 value -= (ETHER_HDR_LEN + ETHER_CRC_LEN);
968 }
969
970 if (mtu_min) *mtu_min = IF_MINMTU;
971 if (mtu_max) *mtu_max = value;
972 }
973 CFRelease(num);
974 }
975
976 IOObjectRelease(io_controller);
977 }
978
979 return TRUE;
980 }
981
982
983 Boolean
984 SCNetworkInterfaceCopyMTU(SCNetworkInterfaceRef interface,
985 int *mtu_cur,
986 int *mtu_min,
987 int *mtu_max)
988 {
989 struct ifreq ifr;
990 CFStringRef interfaceName;
991 Boolean ok = FALSE;
992 int sock = -1;
993
994 if (!isA_SCNetworkInterface(interface)) {
995 _SCErrorSet(kSCStatusInvalidArgument);
996 return FALSE;
997 }
998
999 interfaceName = SCNetworkInterfaceGetBSDName(interface);
1000 if (interfaceName == NULL) {
1001 _SCErrorSet(kSCStatusInvalidArgument);
1002 return FALSE;
1003 }
1004
1005 bzero((void *)&ifr, sizeof(ifr));
1006 if (_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII) == NULL) {
1007 SCLog(TRUE, LOG_ERR, CFSTR("could not convert interface name"));
1008 _SCErrorSet(kSCStatusInvalidArgument);
1009 return FALSE;
1010 }
1011
1012 sock = socket(AF_INET, SOCK_DGRAM, 0);
1013 if (sock == -1) {
1014 _SCErrorSet(errno);
1015 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
1016 return FALSE;
1017 }
1018
1019 if (ioctl(sock, SIOCGIFMTU, (caddr_t)&ifr) == -1) {
1020 _SCErrorSet(errno);
1021 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMTU) failed: %s"), strerror(errno));
1022 goto done;
1023 }
1024
1025 if (mtu_cur) *mtu_cur = ifr.ifr_mtu;
1026 if (mtu_min) *mtu_min = ifr.ifr_mtu;
1027 if (mtu_max) *mtu_max = ifr.ifr_mtu;
1028
1029 /* get valid MTU range */
1030
1031 if (mtu_min != NULL || mtu_max != NULL) {
1032 if (ioctl(sock, SIOCGIFDEVMTU, (caddr_t)&ifr) == 0) {
1033 struct ifdevmtu * devmtu_p;
1034
1035 devmtu_p = &ifr.ifr_devmtu;
1036 if (mtu_min != NULL) {
1037 *mtu_min = (devmtu_p->ifdm_min > IF_MINMTU)
1038 ? devmtu_p->ifdm_min : IF_MINMTU;
1039 }
1040 if (mtu_max != NULL) {
1041 *mtu_max = devmtu_p->ifdm_max;
1042 }
1043 } else {
1044 (void)__getMTULimits(ifr.ifr_name, mtu_min, mtu_max);
1045 }
1046
1047 if (mtu_min != NULL) {
1048 #if IP_MSS > IPV6_MMTU
1049 if (*mtu_min < IP_MSS) {
1050 /* bump up the minimum MTU */
1051 *mtu_min = IP_MSS/*576*/;
1052 }
1053 #else // IP_MSS > IPV6_MMTU
1054 if (*mtu_min < IPV6_MMTU) {
1055 /* bump up the minimum MTU */
1056 *mtu_min = IPV6_MMTU;
1057 }
1058 #endif // IP_MSS > IPV6_MMTU
1059
1060 if ((mtu_cur != NULL) && (*mtu_min > *mtu_cur)) {
1061 /* min must be <= cur */
1062 *mtu_min = *mtu_cur;
1063 }
1064
1065 if ((mtu_max != NULL) && (*mtu_min > *mtu_max)) {
1066 /* min must be <= max */
1067 *mtu_min = *mtu_max;
1068 }
1069 }
1070 }
1071
1072 ok = TRUE;
1073
1074 done :
1075
1076 (void)close(sock);
1077 return ok;
1078 }
1079
1080
1081 Boolean
1082 SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface,
1083 CFStringRef subtype,
1084 CFArrayRef options)
1085 {
1086 CFDictionaryRef configuration;
1087 CFMutableDictionaryRef newConfiguration = NULL;
1088 Boolean ok = FALSE;
1089
1090 if (!isA_SCNetworkInterface(interface)) {
1091 _SCErrorSet(kSCStatusInvalidArgument);
1092 return FALSE;
1093 }
1094
1095 configuration = SCNetworkInterfaceGetConfiguration(interface);
1096 if (configuration == NULL) {
1097 newConfiguration = CFDictionaryCreateMutable(NULL,
1098 0,
1099 &kCFTypeDictionaryKeyCallBacks,
1100 &kCFTypeDictionaryValueCallBacks);
1101 } else {
1102 newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
1103 CFDictionaryRemoveValue(newConfiguration, kSCResvInactive);
1104 }
1105
1106 if (subtype != NULL) {
1107 CFArrayRef available = NULL;
1108 CFArrayRef config_options = options;
1109 CFArrayRef subtypes = NULL;
1110 CFArrayRef subtype_options = NULL;
1111
1112 if (options == NULL) {
1113 config_options = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
1114 }
1115
1116 if (!SCNetworkInterfaceCopyMediaOptions(interface, NULL, NULL, &available, FALSE)) {
1117 SCLog(_sc_debug, LOG_DEBUG, CFSTR("media type / options not available"));
1118 goto checked;
1119 }
1120
1121 if (available == NULL) {
1122 _SCErrorSet(kSCStatusInvalidArgument);
1123 goto checked;
1124 }
1125
1126 subtypes = SCNetworkInterfaceCopyMediaSubTypes(available);
1127 if ((subtypes == NULL) ||
1128 !CFArrayContainsValue(subtypes,
1129 CFRangeMake(0, CFArrayGetCount(subtypes)),
1130 subtype)) {
1131 SCLog(_sc_debug, LOG_DEBUG, CFSTR("media type not valid"));
1132 _SCErrorSet(kSCStatusInvalidArgument);
1133 goto checked;
1134 }
1135
1136 subtype_options = SCNetworkInterfaceCopyMediaSubTypeOptions(available, subtype);
1137 if ((subtype_options == NULL) ||
1138 !CFArrayContainsValue(subtype_options,
1139 CFRangeMake(0, CFArrayGetCount(subtype_options)),
1140 config_options)) {
1141 SCLog(_sc_debug, LOG_DEBUG, CFSTR("media options not valid for \"%@\""), subtype);
1142 _SCErrorSet(kSCStatusInvalidArgument);
1143 goto checked;
1144 }
1145
1146 CFDictionarySetValue(newConfiguration, kSCPropNetEthernetMediaSubType, subtype);
1147 CFDictionarySetValue(newConfiguration,
1148 kSCPropNetEthernetMediaOptions,
1149 (options != NULL) ? options : config_options);
1150
1151 ok = TRUE;
1152
1153 checked :
1154
1155 if (available != NULL) CFRelease(available);
1156 if (subtypes != NULL) CFRelease(subtypes);
1157 if (subtype_options != NULL) CFRelease(subtype_options);
1158 if (options == NULL) CFRelease(config_options);
1159 } else if (options == NULL) {
1160 CFDictionaryRemoveValue(newConfiguration, kSCPropNetEthernetMediaSubType);
1161 CFDictionaryRemoveValue(newConfiguration, kSCPropNetEthernetMediaOptions);
1162 if (CFDictionaryGetCount(newConfiguration) == 0) {
1163 CFRelease(newConfiguration);
1164 newConfiguration = NULL;
1165 }
1166 ok = TRUE;
1167 } else {
1168 SCLog(_sc_debug, LOG_DEBUG, CFSTR("media type must be specified with options"));
1169 _SCErrorSet(kSCStatusInvalidArgument);
1170 }
1171
1172 if (ok) {
1173 ok = SCNetworkInterfaceSetConfiguration(interface, newConfiguration);
1174 }
1175
1176 if (newConfiguration != NULL) CFRelease(newConfiguration);
1177 return ok;
1178 }
1179
1180
1181 Boolean
1182 SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface,
1183 int mtu)
1184 {
1185 CFDictionaryRef configuration;
1186 int mtu_max;
1187 int mtu_min;
1188 CFMutableDictionaryRef newConfiguration = NULL;
1189 Boolean ok = FALSE;
1190
1191 if (!isA_SCNetworkInterface(interface)) {
1192 _SCErrorSet(kSCStatusInvalidArgument);
1193 return FALSE;
1194 }
1195
1196 if (!SCNetworkInterfaceCopyMTU(interface, NULL, &mtu_min, &mtu_max)) {
1197 SCLog(_sc_debug, LOG_DEBUG, CFSTR("MTU bounds not available"));
1198 return FALSE;
1199 }
1200
1201 configuration = SCNetworkInterfaceGetConfiguration(interface);
1202 if (configuration == NULL) {
1203 newConfiguration = CFDictionaryCreateMutable(NULL,
1204 0,
1205 &kCFTypeDictionaryKeyCallBacks,
1206 &kCFTypeDictionaryValueCallBacks);
1207 } else {
1208 newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
1209 CFDictionaryRemoveValue(newConfiguration, kSCResvInactive);
1210 }
1211
1212 if ((mtu >= mtu_min) && (mtu <= mtu_max)) {
1213 CFNumberRef num;
1214
1215 num = CFNumberCreate(NULL, kCFNumberIntType, &mtu);
1216 CFDictionarySetValue(newConfiguration, kSCPropNetEthernetMTU, num);
1217 CFRelease(num);
1218 ok = TRUE;
1219 } else if (mtu == 0) {
1220 CFDictionaryRemoveValue(newConfiguration, kSCPropNetEthernetMTU);
1221 if (CFDictionaryGetCount(newConfiguration) == 0) {
1222 CFRelease(newConfiguration);
1223 newConfiguration = NULL;
1224 }
1225 ok = TRUE;
1226 } else {
1227 SCLog(_sc_debug, LOG_DEBUG, CFSTR("MTU out of range"));
1228 _SCErrorSet(kSCStatusInvalidArgument);
1229 }
1230
1231 if (ok) {
1232 ok = SCNetworkInterfaceSetConfiguration(interface, newConfiguration);
1233 }
1234
1235 if (newConfiguration != NULL) CFRelease(newConfiguration);
1236 return ok;
1237 }
1238
1239
1240 // XXXXX
1241 // XXXXX Remove the following SPIs as soon as we have migrated all
1242 // XXXXX internal users
1243 // XXXXX
1244
1245 /* DEPRECATED */ Boolean
1246 NetworkInterfaceCopyMediaOptions(CFStringRef interfaceName,
1247 CFDictionaryRef *current,
1248 CFDictionaryRef *active,
1249 CFArrayRef *available,
1250 Boolean filter)
1251 {
1252 SCNetworkInterfacePrivateRef interfacePrivate;
1253 Boolean ok;
1254
1255 interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL, NULL);
1256 if (interfacePrivate == NULL) {
1257 return FALSE;
1258 }
1259 interfacePrivate->entity_device = CFRetain(interfaceName);
1260 ok = SCNetworkInterfaceCopyMediaOptions((SCNetworkInterfaceRef)interfacePrivate,
1261 current,
1262 active,
1263 available,
1264 filter);
1265 CFRelease(interfacePrivate);
1266 return ok;
1267 }
1268
1269
1270 /* DEPRECATED */ CFArrayRef
1271 NetworkInterfaceCopyMediaSubTypes(CFArrayRef available)
1272 {
1273 return SCNetworkInterfaceCopyMediaSubTypes(available);
1274 }
1275
1276
1277 /* DEPRECATED */ CFArrayRef
1278 NetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available,
1279 CFStringRef subType)
1280 {
1281 return SCNetworkInterfaceCopyMediaSubTypeOptions(available, subType);
1282 }
1283
1284
1285 /* DEPRECATED */ Boolean
1286 NetworkInterfaceCopyMTU(CFStringRef interfaceName,
1287 int *mtu_cur,
1288 int *mtu_min,
1289 int *mtu_max)
1290 {
1291 SCNetworkInterfacePrivateRef interfacePrivate;
1292 Boolean ok;
1293
1294 interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL, NULL);
1295 if (interfacePrivate == NULL) {
1296 return FALSE;
1297 }
1298 interfacePrivate->entity_device = CFRetain(interfaceName);
1299 ok = SCNetworkInterfaceCopyMTU((SCNetworkInterfaceRef)interfacePrivate,
1300 mtu_cur,
1301 mtu_min,
1302 mtu_max);
1303 CFRelease(interfacePrivate);
1304 return ok;
1305 }