]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/LinkConfiguration.c
configd-212.2.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / LinkConfiguration.c
1 /*
2 * Copyright (c) 2002-2007 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
43 #include <SystemConfiguration/SystemConfiguration.h>
44 #include <SystemConfiguration/SCPrivate.h> // for SCLog()
45 #include "SCNetworkConfigurationInternal.h" // for __SCNetworkInterfaceCreatePrivate
46 #include <SystemConfiguration/SCValidation.h>
47
48 #include <IOKit/IOKitLib.h>
49 #include <IOKit/network/IONetworkInterface.h>
50 #include <IOKit/network/IONetworkController.h>
51 #include "dy_framework.h"
52
53
54 static const struct ifmedia_description ifm_subtype_shared_descriptions[] =
55 IFM_SUBTYPE_SHARED_DESCRIPTIONS;
56
57 static const struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
58 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
59
60 static const struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
61 IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
62
63 static const struct ifmedia_description ifm_shared_option_descriptions[] =
64 IFM_SHARED_OPTION_DESCRIPTIONS;
65
66 static const struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
67 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
68
69 static const struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
70 IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
71
72
73 static void
74 __freeMediaList(struct ifmediareq *ifm)
75 {
76 if (ifm->ifm_ulist != NULL) CFAllocatorDeallocate(NULL, ifm->ifm_ulist);
77 CFAllocatorDeallocate(NULL, ifm);
78 return;
79 }
80
81
82 static struct ifmediareq *
83 __copyMediaList(CFStringRef interfaceName)
84 {
85 struct ifmediareq *ifm;
86 Boolean ok = FALSE;
87 int sock = -1;
88
89 ifm = (struct ifmediareq *)CFAllocatorAllocate(NULL, sizeof(struct ifmediareq), 0);
90 bzero((void *)ifm, sizeof(*ifm));
91
92 if (_SC_cfstring_to_cstring(interfaceName, ifm->ifm_name, sizeof(ifm->ifm_name), kCFStringEncodingASCII) == NULL) {
93 SCLog(TRUE, LOG_ERR, CFSTR("could not convert interface name"));
94 goto done;
95 }
96
97 sock = socket(AF_INET, SOCK_DGRAM, 0);
98 if (sock == -1) {
99 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
100 goto done;
101 }
102
103 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)ifm) == -1) {
104 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
105 goto done;
106 }
107
108 if (ifm->ifm_count > 0) {
109 ifm->ifm_ulist = (int *)CFAllocatorAllocate(NULL, ifm->ifm_count * sizeof(int), 0);
110 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)ifm) == -1) {
111 SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
112 goto done;
113 }
114 }
115
116 ok = TRUE;
117
118 done :
119
120 if (sock != -1) (void)close(sock);
121 if (!ok) {
122 __freeMediaList(ifm);
123 ifm = NULL;
124 _SCErrorSet(kSCStatusFailed);
125 }
126 return ifm;
127 }
128
129
130 static CFDictionaryRef
131 __createMediaDictionary(int media_options, Boolean filter)
132 {
133 CFMutableDictionaryRef dict = NULL;
134 int i;
135 const struct ifmedia_description *option_descriptions = NULL;
136 CFMutableArrayRef options = NULL;
137 const struct ifmedia_description *subtype_descriptions = NULL;
138 CFStringRef val;
139
140 if (filter &&
141 ((IFM_SUBTYPE(media_options) == IFM_NONE) ||
142 ((IFM_OPTIONS(media_options) & IFM_LOOP) != 0))) {
143 return NULL; /* filter */
144 }
145
146 switch (IFM_TYPE(media_options)) {
147 case IFM_ETHER :
148 option_descriptions = ifm_subtype_ethernet_option_descriptions;
149 subtype_descriptions = ifm_subtype_ethernet_descriptions;
150 break;
151 case IFM_IEEE80211 :
152 option_descriptions = ifm_subtype_ieee80211_option_descriptions;
153 subtype_descriptions = ifm_subtype_ieee80211_descriptions;
154 break;
155 default :
156 return NULL;
157 }
158
159 dict = CFDictionaryCreateMutable(NULL,
160 0,
161 &kCFTypeDictionaryKeyCallBacks,
162 &kCFTypeDictionaryValueCallBacks);
163
164 /* subtype */
165
166 val = NULL;
167 for (i = 0; !val && ifm_subtype_shared_descriptions[i].ifmt_string; i++) {
168 if (IFM_SUBTYPE(media_options) == ifm_subtype_shared_descriptions[i].ifmt_word) {
169 val = CFStringCreateWithCString(NULL,
170 ifm_subtype_shared_descriptions[i].ifmt_string,
171 kCFStringEncodingASCII);
172 break;
173 }
174 }
175
176 if (subtype_descriptions != NULL) {
177 for (i = 0; !val && subtype_descriptions[i].ifmt_string; i++) {
178 if (IFM_SUBTYPE(media_options) == subtype_descriptions[i].ifmt_word) {
179 val = CFStringCreateWithCString(NULL,
180 subtype_descriptions[i].ifmt_string,
181 kCFStringEncodingASCII);
182 break;
183 }
184 }
185 }
186
187 if (val) {
188 CFDictionaryAddValue(dict, kSCPropNetEthernetMediaSubType, val);
189 CFRelease(val);
190 }
191
192 /* options */
193
194 options = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
195
196 while (IFM_OPTIONS(media_options) != 0) {
197 val = NULL;
198 for (i = 0; !val && ifm_shared_option_descriptions[i].ifmt_string; i++) {
199 if (IFM_OPTIONS(media_options) & ifm_shared_option_descriptions[i].ifmt_word) {
200 val = CFStringCreateWithCString(NULL,
201 ifm_shared_option_descriptions[i].ifmt_string,
202 kCFStringEncodingASCII);
203 media_options &= ~ifm_shared_option_descriptions[i].ifmt_word;
204 break;
205 }
206 }
207
208 if (option_descriptions != NULL) {
209 for (i = 0; !val && option_descriptions[i].ifmt_string; i++) {
210 if (IFM_OPTIONS(media_options) & option_descriptions[i].ifmt_word) {
211 val = CFStringCreateWithCString(NULL,
212 option_descriptions[i].ifmt_string,
213 kCFStringEncodingASCII);
214 media_options &= ~option_descriptions[i].ifmt_word;
215 break;
216 }
217 }
218 }
219
220 if (val) {
221 CFArrayAppendValue(options, val);
222 CFRelease(val);
223 }
224 }
225
226 CFDictionaryAddValue(dict, kSCPropNetEthernetMediaOptions, options);
227 CFRelease(options);
228
229 return dict;
230 }
231
232
233 int
234 __createMediaOptions(CFStringRef interfaceName, CFDictionaryRef media_options)
235 {
236 CFIndex i;
237 struct ifmediareq *ifm;
238 int ifm_new = -1;
239 Boolean match;
240 CFIndex n;
241 const struct ifmedia_description *option_descriptions = NULL;
242 CFArrayRef options;
243 char *str;
244 const struct ifmedia_description *subtype_descriptions = NULL;
245 CFStringRef val;
246
247 /* set type */
248
249 ifm = __copyMediaList(interfaceName);
250 if (ifm != NULL) {
251 if (ifm->ifm_count > 0) {
252 ifm_new = IFM_TYPE(ifm->ifm_ulist[0]);
253 }
254 __freeMediaList(ifm);
255 }
256
257 if (ifm_new == -1) {
258 // if we cannot determine the media type for the interface
259 return -1;
260 }
261
262 switch (IFM_TYPE(ifm_new)) {
263 case IFM_ETHER :
264 option_descriptions = ifm_subtype_ethernet_option_descriptions;
265 subtype_descriptions = ifm_subtype_ethernet_descriptions;
266 break;
267 case IFM_IEEE80211 :
268 option_descriptions = ifm_subtype_ieee80211_option_descriptions;
269 subtype_descriptions = ifm_subtype_ieee80211_descriptions;
270 break;
271 }
272
273 /* set subtype */
274
275 val = CFDictionaryGetValue(media_options, kSCPropNetEthernetMediaSubType);
276 if (!isA_CFString(val)) {
277 return -1;
278 }
279
280 str = _SC_cfstring_to_cstring(val, NULL, 0, kCFStringEncodingASCII);
281 if (str == NULL) {
282 return -1;
283 }
284
285 match = FALSE;
286 for (i = 0; !match && ifm_subtype_shared_descriptions[i].ifmt_string; i++) {
287 if (strcasecmp(str, ifm_subtype_shared_descriptions[i].ifmt_string) == 0) {
288 ifm_new |= ifm_subtype_shared_descriptions[i].ifmt_word;
289 match = TRUE;
290 break;
291 }
292 }
293
294 if (subtype_descriptions != NULL) {
295 for (i = 0; !match && subtype_descriptions[i].ifmt_string; i++) {
296 if (strcasecmp(str, subtype_descriptions[i].ifmt_string) == 0) {
297 ifm_new |= subtype_descriptions[i].ifmt_word;
298 match = TRUE;
299 break;
300 }
301 }
302 }
303
304 CFAllocatorDeallocate(NULL, str);
305
306 if (!match) {
307 return -1; /* if no subtype */
308 }
309
310 /* set options */
311
312 options = CFDictionaryGetValue(media_options, kSCPropNetEthernetMediaOptions);
313 if (!isA_CFArray(options)) {
314 return -1;
315 }
316
317 n = CFArrayGetCount(options);
318 for (i = 0; i < n; i++) {
319 CFIndex j;
320
321 val = CFArrayGetValueAtIndex(options, i);
322 if (!isA_CFString(val)) {
323 return -1;
324 }
325
326 str = _SC_cfstring_to_cstring(val, NULL, 0, kCFStringEncodingASCII);
327 if (str == NULL) {
328 return -1;
329 }
330
331
332 match = FALSE;
333 for (j = 0; !match && ifm_shared_option_descriptions[j].ifmt_string; j++) {
334 if (strcasecmp(str, ifm_shared_option_descriptions[j].ifmt_string) == 0) {
335 ifm_new |= ifm_shared_option_descriptions[j].ifmt_word;
336 match = TRUE;
337 break;
338 }
339 }
340
341 if (option_descriptions != NULL) {
342 for (j = 0; !match && option_descriptions[j].ifmt_string; j++) {
343 if (strcasecmp(str, option_descriptions[j].ifmt_string) == 0) {
344 ifm_new |= option_descriptions[j].ifmt_word;
345 match = TRUE;
346 break;
347 }
348 }
349 }
350
351 CFAllocatorDeallocate(NULL, str);
352
353 if (!match) {
354 return -1; /* if no option */
355 }
356 }
357
358 return ifm_new;
359 }
360
361
362 Boolean
363 SCNetworkInterfaceCopyMediaOptions(SCNetworkInterfaceRef interface,
364 CFDictionaryRef *current,
365 CFDictionaryRef *active,
366 CFArrayRef *available,
367 Boolean filter)
368 {
369 int i;
370 struct ifmediareq *ifm;
371 CFStringRef interfaceName;
372
373 if (!isA_SCNetworkInterface(interface)) {
374 _SCErrorSet(kSCStatusInvalidArgument);
375 return FALSE;
376 }
377
378 interfaceName = SCNetworkInterfaceGetBSDName(interface);
379 if (interfaceName == NULL) {
380 SCLog(TRUE, LOG_ERR, CFSTR("no interface name"));
381 _SCErrorSet(kSCStatusInvalidArgument);
382 return FALSE;
383 }
384
385 ifm = __copyMediaList(interfaceName);
386 if (ifm == NULL) {
387 return FALSE;
388 }
389
390 if (active != NULL) *active = NULL;
391 if (current != NULL) *current = NULL;
392 if (available != NULL) {
393 CFMutableArrayRef media_options;
394
395 media_options = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
396 for (i = 0; i < ifm->ifm_count; i++) {
397 CFDictionaryRef options;
398
399 options = __createMediaDictionary(ifm->ifm_ulist[i], filter);
400 if (options == NULL) {
401 continue;
402 }
403
404 if ((active != NULL) && (*active == NULL) && (ifm->ifm_active == ifm->ifm_ulist[i])) {
405 *active = CFRetain(options);
406 }
407
408 if ((current != NULL) && (*current == NULL) && (ifm->ifm_current == ifm->ifm_ulist[i])) {
409 *current = CFRetain(options);
410 }
411
412 if (!CFArrayContainsValue(media_options, CFRangeMake(0, CFArrayGetCount(media_options)), options)) {
413 CFArrayAppendValue(media_options, options);
414 }
415
416 CFRelease(options);
417 }
418 *available = (CFArrayRef)media_options;
419 }
420
421 if ((active != NULL) && (*active == NULL)) {
422 *active = __createMediaDictionary(ifm->ifm_active, FALSE);
423 }
424
425 if ((current != NULL) && (*current == NULL)) {
426 if ((active != NULL) && (ifm->ifm_active == ifm->ifm_current)) {
427 if (*active != NULL) *current = CFRetain(*active);
428 } else {
429 *current = __createMediaDictionary(ifm->ifm_current, FALSE);
430 }
431 }
432
433 __freeMediaList(ifm);
434 return TRUE;
435 }
436
437
438 CFArrayRef
439 SCNetworkInterfaceCopyMediaSubTypes(CFArrayRef available)
440 {
441 CFIndex i;
442 CFIndex n;
443 CFMutableArrayRef subTypes;
444
445 if (!isA_CFArray(available)) {
446 _SCErrorSet(kSCStatusInvalidArgument);
447 return NULL;
448 }
449
450 subTypes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
451
452 n = CFArrayGetCount(available);
453 for (i = 0; i < n; i++) {
454 CFDictionaryRef options;
455 CFStringRef subType;
456
457 options = CFArrayGetValueAtIndex(available, i);
458 if (!isA_CFDictionary(options)) {
459 continue;
460 }
461
462 subType = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType);
463 if (!isA_CFString(subType)) {
464 continue;
465 }
466
467 if (!CFArrayContainsValue(subTypes, CFRangeMake(0, CFArrayGetCount(subTypes)), subType)) {
468 CFArrayAppendValue(subTypes, subType);
469 }
470 }
471
472 if (CFArrayGetCount(subTypes) == 0) {
473 CFRelease(subTypes);
474 subTypes = NULL;
475 _SCErrorSet(kSCStatusOK);
476 }
477
478 return subTypes;
479 }
480
481
482 CFArrayRef
483 SCNetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available,
484 CFStringRef subType)
485 {
486 CFIndex i;
487 CFIndex n;
488 CFMutableArrayRef subTypeOptions;
489
490 if (!isA_CFArray(available)) {
491 _SCErrorSet(kSCStatusInvalidArgument);
492 return NULL;
493 }
494
495 subTypeOptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
496
497 n = CFArrayGetCount(available);
498 for (i = 0; i < n; i++) {
499 CFDictionaryRef options;
500 CFArrayRef mediaOptions;
501 CFStringRef mediaSubType;
502
503 options = CFArrayGetValueAtIndex(available, i);
504 if (!isA_CFDictionary(options)) {
505 continue;
506 }
507
508 mediaSubType = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType);
509 if (!isA_CFString(mediaSubType) || !CFEqual(subType, mediaSubType)) {
510 continue;
511 }
512
513 mediaOptions = CFDictionaryGetValue(options, kSCPropNetEthernetMediaOptions);
514 if (!isA_CFArray(mediaOptions)) {
515 continue;
516 }
517
518 if (!CFArrayContainsValue(subTypeOptions, CFRangeMake(0, CFArrayGetCount(subTypeOptions)), mediaOptions)) {
519 CFArrayAppendValue(subTypeOptions, mediaOptions);
520 }
521 }
522
523 if (CFArrayGetCount(subTypeOptions) == 0) {
524 CFRelease(subTypeOptions);
525 subTypeOptions = NULL;
526 _SCErrorSet(kSCStatusOK);
527 }
528
529 return subTypeOptions;
530 }
531
532
533 static Boolean
534 __getMTULimits(char ifr_name[IFNAMSIZ],
535 int *mtu_min,
536 int *mtu_max)
537 {
538 int ifType = 0;
539 io_iterator_t io_iter = 0;
540 io_registry_entry_t io_interface = 0;
541 io_registry_entry_t io_controller = 0;
542 kern_return_t kr;
543 static mach_port_t masterPort = MACH_PORT_NULL;
544 CFMutableDictionaryRef matchingDict;
545
546 /* look for a matching interface in the IORegistry */
547
548 if (masterPort == MACH_PORT_NULL) {
549 kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
550 if (kr != KERN_SUCCESS) {
551 return FALSE;
552 }
553 }
554
555 matchingDict = IOBSDNameMatching(masterPort, 0, ifr_name);
556 if (matchingDict) {
557 /* Note: IOServiceGetMatchingServices consumes a reference on the 'matchingDict' */
558 kr = IOServiceGetMatchingServices(masterPort, matchingDict, &io_iter);
559 if ((kr == KERN_SUCCESS) && io_iter) {
560 /* should only have a single match */
561 io_interface = IOIteratorNext(io_iter);
562 }
563 if (io_iter) IOObjectRelease(io_iter);
564 }
565
566 if (io_interface) {
567 CFNumberRef num;
568
569 /*
570 * found an interface, get the interface type
571 */
572 num = IORegistryEntryCreateCFProperty(io_interface, CFSTR(kIOInterfaceType), NULL, kNilOptions);
573 if (num) {
574 if (isA_CFNumber(num)) {
575 CFNumberGetValue(num, kCFNumberIntType, &ifType);
576 }
577 CFRelease(num);
578 }
579
580 /*
581 * ...and the property we are REALLY interested is in the controller,
582 * which is the parent of the interface object.
583 */
584 (void)IORegistryEntryGetParentEntry(io_interface, kIOServicePlane, &io_controller);
585 IOObjectRelease(io_interface);
586 } else {
587 /* if no matching interface */
588 return FALSE;
589 }
590
591 if (io_controller) {
592 CFNumberRef num;
593
594 num = IORegistryEntryCreateCFProperty(io_controller, CFSTR(kIOMaxPacketSize), NULL, kNilOptions);
595 if (num) {
596 if (isA_CFNumber(num)) {
597 int value;
598
599 /*
600 * Get the value and subtract the FCS bytes and Ethernet header
601 * sizes from the maximum frame size reported by the controller
602 * to get the MTU size. The 14 byte media header can be found
603 * in the registry, but not the size for the trailing FCS bytes.
604 */
605 CFNumberGetValue(num, kCFNumberIntType, &value);
606
607 if (ifType == IFT_ETHER) {
608 value -= (ETHER_HDR_LEN + ETHER_CRC_LEN);
609 }
610
611 if (mtu_min) *mtu_min = IF_MINMTU;
612 if (mtu_max) *mtu_max = value;
613 }
614 CFRelease(num);
615 }
616
617 IOObjectRelease(io_controller);
618 }
619
620 return TRUE;
621 }
622
623
624 Boolean
625 SCNetworkInterfaceCopyMTU(SCNetworkInterfaceRef interface,
626 int *mtu_cur,
627 int *mtu_min,
628 int *mtu_max)
629 {
630 struct ifreq ifr;
631 CFStringRef interfaceName;
632 Boolean ok = FALSE;
633 int sock = -1;
634
635 if (!isA_SCNetworkInterface(interface)) {
636 _SCErrorSet(kSCStatusInvalidArgument);
637 return FALSE;
638 }
639
640 interfaceName = SCNetworkInterfaceGetBSDName(interface);
641 if (interfaceName == NULL) {
642 SCLog(TRUE, LOG_ERR, CFSTR("no interface name"));
643 goto done;
644 }
645
646 bzero((void *)&ifr, sizeof(ifr));
647 if (_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII) == NULL) {
648 SCLog(TRUE, LOG_ERR, CFSTR("could not convert interface name"));
649 _SCErrorSet(kSCStatusInvalidArgument);
650 goto done;
651 }
652
653 sock = socket(AF_INET, SOCK_DGRAM, 0);
654 if (sock == -1) {
655 _SCErrorSet(errno);
656 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
657 goto done;
658 }
659
660 if (ioctl(sock, SIOCGIFMTU, (caddr_t)&ifr) == -1) {
661 _SCErrorSet(errno);
662 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMTU) failed: %s"), strerror(errno));
663 goto done;
664 }
665
666 if (mtu_cur) *mtu_cur = ifr.ifr_mtu;
667 if (mtu_min) *mtu_min = ifr.ifr_mtu;
668 if (mtu_max) *mtu_max = ifr.ifr_mtu;
669
670 /* get valid MTU range */
671
672 if (mtu_min != NULL || mtu_max != NULL) {
673 if (ioctl(sock, SIOCGIFDEVMTU, (caddr_t)&ifr) == 0) {
674 struct ifdevmtu * devmtu_p;
675
676 devmtu_p = &ifr.ifr_devmtu;
677 if (mtu_min != NULL) {
678 *mtu_min = (devmtu_p->ifdm_min > IF_MINMTU)
679 ? devmtu_p->ifdm_min : IF_MINMTU;
680 }
681 if (mtu_max != NULL) {
682 *mtu_max = devmtu_p->ifdm_max;
683 }
684 } else {
685 (void)__getMTULimits(ifr.ifr_name, mtu_min, mtu_max);
686 }
687 }
688
689 ok = TRUE;
690
691 done :
692
693 if (sock != -1) (void)close(sock);
694
695 return ok;
696 }
697
698
699 Boolean
700 SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface,
701 CFStringRef subtype,
702 CFArrayRef options)
703 {
704 CFDictionaryRef configuration;
705 CFMutableDictionaryRef newConfiguration = NULL;
706 Boolean ok = FALSE;
707
708 if (!isA_SCNetworkInterface(interface)) {
709 _SCErrorSet(kSCStatusInvalidArgument);
710 return FALSE;
711 }
712
713 configuration = SCNetworkInterfaceGetConfiguration(interface);
714 if (configuration == NULL) {
715 newConfiguration = CFDictionaryCreateMutable(NULL,
716 0,
717 &kCFTypeDictionaryKeyCallBacks,
718 &kCFTypeDictionaryValueCallBacks);
719 } else {
720 newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
721 CFDictionaryRemoveValue(newConfiguration, kSCResvInactive);
722 }
723
724 if (subtype != NULL) {
725 CFArrayRef available = NULL;
726 CFArrayRef config_options = options;
727 CFArrayRef subtypes = NULL;
728 CFArrayRef subtype_options = NULL;
729
730 if (options == NULL) {
731 config_options = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
732 }
733
734 if (!SCNetworkInterfaceCopyMediaOptions(interface, NULL, NULL, &available, FALSE)) {
735 SCLog(_sc_debug, LOG_DEBUG, CFSTR("media type / options not available"));
736 goto checked;
737 }
738
739 if (available == NULL) {
740 _SCErrorSet(kSCStatusInvalidArgument);
741 goto checked;
742 }
743
744 subtypes = SCNetworkInterfaceCopyMediaSubTypes(available);
745 if ((subtypes == NULL) ||
746 !CFArrayContainsValue(subtypes,
747 CFRangeMake(0, CFArrayGetCount(subtypes)),
748 subtype)) {
749 SCLog(_sc_debug, LOG_DEBUG, CFSTR("media type not valid"));
750 _SCErrorSet(kSCStatusInvalidArgument);
751 goto checked;
752 }
753
754 subtype_options = SCNetworkInterfaceCopyMediaSubTypeOptions(available, subtype);
755 if ((subtype_options == NULL) ||
756 !CFArrayContainsValue(subtype_options,
757 CFRangeMake(0, CFArrayGetCount(subtype_options)),
758 config_options)) {
759 SCLog(_sc_debug, LOG_DEBUG, CFSTR("media options not valid for \"%@\""), subtype);
760 _SCErrorSet(kSCStatusInvalidArgument);
761 goto checked;
762 }
763
764 CFDictionarySetValue(newConfiguration, kSCPropNetEthernetMediaSubType, subtype);
765 CFDictionarySetValue(newConfiguration,
766 kSCPropNetEthernetMediaOptions,
767 (options != NULL) ? options : config_options);
768
769 ok = TRUE;
770
771 checked :
772
773 if (available != NULL) CFRelease(available);
774 if (subtypes != NULL) CFRelease(subtypes);
775 if (subtype_options != NULL) CFRelease(subtype_options);
776 if (options == NULL) CFRelease(config_options);
777 } else if (options == NULL) {
778 CFDictionaryRemoveValue(newConfiguration, kSCPropNetEthernetMediaSubType);
779 CFDictionaryRemoveValue(newConfiguration, kSCPropNetEthernetMediaOptions);
780 if (CFDictionaryGetCount(newConfiguration) == 0) {
781 CFRelease(newConfiguration);
782 newConfiguration = NULL;
783 }
784 ok = TRUE;
785 } else {
786 SCLog(_sc_debug, LOG_DEBUG, CFSTR("media type must be specified with options"));
787 _SCErrorSet(kSCStatusInvalidArgument);
788 }
789
790 if (ok) {
791 ok = SCNetworkInterfaceSetConfiguration(interface, newConfiguration);
792 }
793
794 if (newConfiguration != NULL) CFRelease(newConfiguration);
795 return ok;
796 }
797
798
799 Boolean
800 SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface,
801 int mtu)
802 {
803 CFDictionaryRef configuration;
804 int mtu_max;
805 int mtu_min;
806 CFMutableDictionaryRef newConfiguration = NULL;
807 Boolean ok = FALSE;
808
809 if (!isA_SCNetworkInterface(interface)) {
810 _SCErrorSet(kSCStatusInvalidArgument);
811 return FALSE;
812 }
813
814 if (!SCNetworkInterfaceCopyMTU(interface, NULL, &mtu_min, &mtu_max)) {
815 SCLog(_sc_debug, LOG_DEBUG, CFSTR("MTU bounds not available"));
816 return FALSE;
817 }
818
819 configuration = SCNetworkInterfaceGetConfiguration(interface);
820 if (configuration == NULL) {
821 newConfiguration = CFDictionaryCreateMutable(NULL,
822 0,
823 &kCFTypeDictionaryKeyCallBacks,
824 &kCFTypeDictionaryValueCallBacks);
825 } else {
826 newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
827 CFDictionaryRemoveValue(newConfiguration, kSCResvInactive);
828 }
829
830 if ((mtu >= mtu_min) && (mtu <= mtu_max)) {
831 CFNumberRef num;
832
833 num = CFNumberCreate(NULL, kCFNumberIntType, &mtu);
834 CFDictionarySetValue(newConfiguration, kSCPropNetEthernetMTU, num);
835 CFRelease(num);
836 ok = TRUE;
837 } else if (mtu == 0) {
838 CFDictionaryRemoveValue(newConfiguration, kSCPropNetEthernetMTU);
839 if (CFDictionaryGetCount(newConfiguration) == 0) {
840 CFRelease(newConfiguration);
841 newConfiguration = NULL;
842 }
843 ok = TRUE;
844 } else {
845 SCLog(_sc_debug, LOG_DEBUG, CFSTR("MTU out of range"));
846 _SCErrorSet(kSCStatusInvalidArgument);
847 }
848
849 if (ok) {
850 ok = SCNetworkInterfaceSetConfiguration(interface, newConfiguration);
851 }
852
853 if (newConfiguration != NULL) CFRelease(newConfiguration);
854 return ok;
855 }
856
857
858 // XXXXX
859 // XXXXX Remove the following SPIs as soon as we have migrated all
860 // XXXXX internal users
861 // XXXXX
862
863 /* DEPRECATED */ Boolean
864 NetworkInterfaceCopyMediaOptions(CFStringRef interfaceName,
865 CFDictionaryRef *current,
866 CFDictionaryRef *active,
867 CFArrayRef *available,
868 Boolean filter)
869 {
870 SCNetworkInterfacePrivateRef interfacePrivate;
871 Boolean ok;
872
873 interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL, NULL);
874 if (interfacePrivate == NULL) {
875 return FALSE;
876 }
877 interfacePrivate->entity_device = CFRetain(interfaceName);
878 ok = SCNetworkInterfaceCopyMediaOptions((SCNetworkInterfaceRef)interfacePrivate,
879 current,
880 active,
881 available,
882 filter);
883 CFRelease(interfacePrivate);
884 return ok;
885 }
886
887
888 /* DEPRECATED */ CFArrayRef
889 NetworkInterfaceCopyMediaSubTypes(CFArrayRef available)
890 {
891 return SCNetworkInterfaceCopyMediaSubTypes(available);
892 }
893
894
895 /* DEPRECATED */ CFArrayRef
896 NetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available,
897 CFStringRef subType)
898 {
899 return SCNetworkInterfaceCopyMediaSubTypeOptions(available, subType);
900 }
901
902
903 /* DEPRECATED */ Boolean
904 NetworkInterfaceCopyMTU(CFStringRef interfaceName,
905 int *mtu_cur,
906 int *mtu_min,
907 int *mtu_max)
908 {
909 SCNetworkInterfacePrivateRef interfacePrivate;
910 Boolean ok;
911
912 interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL, NULL);
913 if (interfacePrivate == NULL) {
914 return FALSE;
915 }
916 interfacePrivate->entity_device = CFRetain(interfaceName);
917 ok = SCNetworkInterfaceCopyMTU((SCNetworkInterfaceRef)interfacePrivate,
918 mtu_cur,
919 mtu_min,
920 mtu_max);
921 CFRelease(interfacePrivate);
922 return ok;
923 }