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