]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/LinkConfiguration.c
configd-130.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / LinkConfiguration.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, 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 <SystemConfiguration/SCValidation.h>
46
47 #include <IOKit/IOKitLib.h>
48 #include <IOKit/network/IONetworkInterface.h>
49 #include <IOKit/network/IONetworkController.h>
50 #include "dy_framework.h"
51
52
53 static const struct ifmedia_description ifm_subtype_shared_descriptions[] =
54 IFM_SUBTYPE_SHARED_DESCRIPTIONS;
55
56 static const struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
57 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
58
59 static const struct ifmedia_description ifm_shared_option_descriptions[] =
60 IFM_SHARED_OPTION_DESCRIPTIONS;
61
62 static const struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
63 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
64
65
66 static CFDictionaryRef
67 __createMediaDictionary(int media_options, Boolean filter)
68 {
69 CFMutableDictionaryRef dict = NULL;
70 int i;
71 CFMutableArrayRef options = NULL;
72 CFStringRef val;
73
74 if (IFM_TYPE(media_options) != IFM_ETHER) {
75 return NULL;
76 }
77
78 if (filter && (IFM_SUBTYPE(media_options) == IFM_NONE)) {
79 return NULL; /* filter */
80 }
81
82 dict = CFDictionaryCreateMutable(NULL,
83 0,
84 &kCFTypeDictionaryKeyCallBacks,
85 &kCFTypeDictionaryValueCallBacks);
86
87 /* subtype */
88
89 val = NULL;
90 for (i = 0; !val && ifm_subtype_shared_descriptions[i].ifmt_string; i++) {
91 if (IFM_SUBTYPE(media_options) == ifm_subtype_shared_descriptions[i].ifmt_word) {
92 val = CFStringCreateWithCString(NULL,
93 ifm_subtype_shared_descriptions[i].ifmt_string,
94 kCFStringEncodingASCII);
95 break;
96 }
97 }
98
99 for (i = 0; !val && ifm_subtype_ethernet_descriptions[i].ifmt_string; i++) {
100 if (IFM_SUBTYPE(media_options) == ifm_subtype_ethernet_descriptions[i].ifmt_word) {
101 val = CFStringCreateWithCString(NULL,
102 ifm_subtype_ethernet_descriptions[i].ifmt_string,
103 kCFStringEncodingASCII);
104 break;
105 }
106 }
107
108 if (val) {
109 CFDictionaryAddValue(dict, kSCPropNetEthernetMediaSubType, val);
110 CFRelease(val);
111 }
112
113 /* options */
114
115 options = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
116
117 while (IFM_OPTIONS(media_options) != 0) {
118 if (filter && (IFM_OPTIONS(media_options) & IFM_LOOP)) {
119 media_options &= ~IFM_LOOP; /* filter */
120 continue;
121 }
122
123 val = NULL;
124 for (i = 0; !val && ifm_shared_option_descriptions[i].ifmt_string; i++) {
125 if (IFM_OPTIONS(media_options) & ifm_shared_option_descriptions[i].ifmt_word) {
126 val = CFStringCreateWithCString(NULL,
127 ifm_shared_option_descriptions[i].ifmt_string,
128 kCFStringEncodingASCII);
129 media_options &= ~ifm_shared_option_descriptions[i].ifmt_word;
130 break;
131 }
132 }
133
134 for (i = 0; !val && ifm_subtype_ethernet_option_descriptions[i].ifmt_string; i++) {
135 if (IFM_OPTIONS(media_options) & ifm_subtype_ethernet_option_descriptions[i].ifmt_word) {
136 val = CFStringCreateWithCString(NULL,
137 ifm_subtype_ethernet_option_descriptions[i].ifmt_string,
138 kCFStringEncodingASCII);
139 media_options &= ~ifm_shared_option_descriptions[i].ifmt_word;
140 break;
141 }
142 }
143
144 if (val) {
145 CFArrayAppendValue(options, val);
146 CFRelease(val);
147 }
148 }
149
150 CFDictionaryAddValue(dict, kSCPropNetEthernetMediaOptions, options);
151 CFRelease(options);
152
153 return dict;
154 }
155
156
157 int
158 __createMediaOptions(CFDictionaryRef media_options)
159 {
160 CFIndex i;
161 Boolean match;
162 int ifm_new = IFM_ETHER;
163 CFIndex n;
164 CFArrayRef options;
165 char *str;
166 CFStringRef val;
167
168 /* set subtype */
169
170 val = CFDictionaryGetValue(media_options, kSCPropNetEthernetMediaSubType);
171 if (!isA_CFString(val)) {
172 return -1;
173 }
174
175 str = _SC_cfstring_to_cstring(val, NULL, 0, kCFStringEncodingASCII);
176 if (str == NULL) {
177 return -1;
178 }
179
180 match = FALSE;
181 for (i = 0; !match && ifm_subtype_shared_descriptions[i].ifmt_string; i++) {
182 if (strcasecmp(str, ifm_subtype_shared_descriptions[i].ifmt_string) == 0) {
183 ifm_new |= ifm_subtype_shared_descriptions[i].ifmt_word;
184 match = TRUE;
185 break;
186 }
187 }
188
189 for (i = 0; !match && ifm_subtype_ethernet_descriptions[i].ifmt_string; i++) {
190 if (strcasecmp(str, ifm_subtype_ethernet_descriptions[i].ifmt_string) == 0) {
191 ifm_new |= ifm_subtype_ethernet_descriptions[i].ifmt_word;
192 match = TRUE;
193 break;
194 }
195 }
196
197 CFAllocatorDeallocate(NULL, str);
198
199 if (!match) {
200 return -1; /* if no subtype */
201 }
202
203 /* set options */
204
205 options = CFDictionaryGetValue(media_options, kSCPropNetEthernetMediaOptions);
206 if (!isA_CFArray(options)) {
207 return -1;
208 }
209
210 n = CFArrayGetCount(options);
211 for (i = 0; i < n; i++) {
212 CFIndex j;
213
214 val = CFArrayGetValueAtIndex(options, i);
215 if (!isA_CFString(val)) {
216 return -1;
217 }
218
219 str = _SC_cfstring_to_cstring(val, NULL, 0, kCFStringEncodingASCII);
220 if (str == NULL) {
221 return -1;
222 }
223
224
225 match = FALSE;
226 for (j = 0; !match && ifm_shared_option_descriptions[j].ifmt_string; j++) {
227 if (strcasecmp(str, ifm_shared_option_descriptions[j].ifmt_string) == 0) {
228 ifm_new |= ifm_shared_option_descriptions[j].ifmt_word;
229 match = TRUE;
230 break;
231 }
232 }
233
234 for (j = 0; !match && ifm_subtype_ethernet_option_descriptions[j].ifmt_string; j++) {
235 if (strcasecmp(str, ifm_subtype_ethernet_option_descriptions[j].ifmt_string) == 0) {
236 ifm_new |= ifm_subtype_ethernet_option_descriptions[j].ifmt_word;
237 match = TRUE;
238 break;
239 }
240 }
241
242 CFAllocatorDeallocate(NULL, str);
243
244 if (!match) {
245 return -1; /* if no option */
246 }
247 }
248
249 return ifm_new;
250 }
251
252
253 Boolean
254 NetworkInterfaceCopyMediaOptions(CFStringRef interface,
255 CFDictionaryRef *current,
256 CFDictionaryRef *active,
257 CFArrayRef *available,
258 Boolean filter)
259 {
260 int i;
261 struct ifmediareq ifm;
262 int *media_list = NULL;
263 Boolean ok = FALSE;
264 int sock = -1;
265
266 bzero((void *)&ifm, sizeof(ifm));
267
268 if (_SC_cfstring_to_cstring(interface, ifm.ifm_name, sizeof(ifm.ifm_name), kCFStringEncodingASCII) == NULL) {
269 SCLog(TRUE, LOG_ERR, CFSTR("could not convert inteface name"));
270 goto done;
271 }
272
273 sock = socket(AF_INET, SOCK_DGRAM, 0);
274 if (sock < 0) {
275 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
276 goto done;
277 }
278
279 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) < 0) {
280 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
281 goto done;
282 }
283
284 if (ifm.ifm_count > 0) {
285 media_list = (int *)CFAllocatorAllocate(NULL, ifm.ifm_count * sizeof(int), 0);
286 ifm.ifm_ulist = media_list;
287 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) < 0) {
288 SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
289 goto done;
290 }
291 }
292
293 if (active) *active = NULL;
294 if (current) *current = NULL;
295 if (available) {
296 CFMutableArrayRef media_options;
297
298 media_options = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
299 for (i = 0; i < ifm.ifm_count; i++) {
300 CFDictionaryRef options;
301
302 options = __createMediaDictionary(media_list[i], filter);
303 if (!options) {
304 continue;
305 }
306
307 if (active && (*active == NULL) && (ifm.ifm_active == media_list[i])) {
308 *active = CFRetain(options);
309 }
310
311 if (current && (*current == NULL) && (ifm.ifm_current == media_list[i])) {
312 *current = CFRetain(options);
313 }
314
315 if (!CFArrayContainsValue(media_options, CFRangeMake(0, CFArrayGetCount(media_options)), options)) {
316 CFArrayAppendValue(media_options, options);
317 }
318
319 CFRelease(options);
320 }
321 *available = (CFArrayRef)media_options;
322 }
323
324 if (active && (*active == NULL)) {
325 *active = __createMediaDictionary(ifm.ifm_active, FALSE);
326 }
327
328 if (current && (*current == NULL)) {
329 if (active && (ifm.ifm_active == ifm.ifm_current)) {
330 if (*active) *current = CFRetain(active);
331 } else {
332 *current = __createMediaDictionary(ifm.ifm_current, FALSE);
333 }
334 }
335
336 ok = TRUE;
337
338 done :
339
340 if (sock >= 0) (void)close(sock);
341 if (media_list) CFAllocatorDeallocate(NULL, media_list);
342
343 return ok;
344 }
345
346
347 CFArrayRef
348 NetworkInterfaceCopyMediaSubTypes(CFArrayRef available)
349 {
350 CFIndex i;
351 CFIndex n;
352 CFMutableArrayRef subTypes;
353
354 if (!isA_CFArray(available)) {
355 return NULL;
356 }
357
358 subTypes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
359
360 n = CFArrayGetCount(available);
361 for (i = 0; i < n; i++) {
362 CFDictionaryRef options;
363 CFStringRef subType;
364
365 options = CFArrayGetValueAtIndex(available, i);
366 if (!isA_CFDictionary(options)) {
367 continue;
368 }
369
370 subType = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType);
371 if (!isA_CFString(subType)) {
372 continue;
373 }
374
375 if (!CFArrayContainsValue(subTypes, CFRangeMake(0, CFArrayGetCount(subTypes)), subType)) {
376 CFArrayAppendValue(subTypes, subType);
377 }
378 }
379
380 if (CFArrayGetCount(subTypes) == 0) {
381 CFRelease(subTypes);
382 subTypes = NULL;
383 }
384
385 return subTypes;
386 }
387
388
389 CFArrayRef
390 NetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available,
391 CFStringRef subType)
392 {
393 CFIndex i;
394 CFIndex n;
395 CFMutableArrayRef subTypeOptions;
396
397 if (!isA_CFArray(available)) {
398 return NULL;
399 }
400
401 subTypeOptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
402
403 n = CFArrayGetCount(available);
404 for (i = 0; i < n; i++) {
405 CFDictionaryRef options;
406 CFArrayRef mediaOptions;
407 CFStringRef mediaSubType;
408
409 options = CFArrayGetValueAtIndex(available, i);
410 if (!isA_CFDictionary(options)) {
411 continue;
412 }
413
414 mediaSubType = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType);
415 if (!isA_CFString(mediaSubType) || !CFEqual(subType, mediaSubType)) {
416 continue;
417 }
418
419 mediaOptions = CFDictionaryGetValue(options, kSCPropNetEthernetMediaOptions);
420 if (!isA_CFArray(mediaOptions)) {
421 continue;
422 }
423
424 if (!CFArrayContainsValue(subTypeOptions, CFRangeMake(0, CFArrayGetCount(subTypeOptions)), mediaOptions)) {
425 CFArrayAppendValue(subTypeOptions, mediaOptions);
426 }
427 }
428
429 if (CFArrayGetCount(subTypeOptions) == 0) {
430 CFRelease(subTypeOptions);
431 subTypeOptions = NULL;
432 }
433
434 return subTypeOptions;
435 }
436
437
438 static Boolean
439 __getMTULimits(char ifr_name[IFNAMSIZ],
440 int *mtu_min,
441 int *mtu_max)
442 {
443 int ifType = 0;
444 io_iterator_t io_iter = 0;
445 io_registry_entry_t io_interface = 0;
446 io_registry_entry_t io_controller = 0;
447 kern_return_t kr;
448 static mach_port_t masterPort = MACH_PORT_NULL;
449 CFMutableDictionaryRef matchingDict;
450
451 /* look for a matching interface in the IORegistry */
452
453 if (masterPort == MACH_PORT_NULL) {
454 kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
455 if (kr != KERN_SUCCESS) {
456 return FALSE;
457 }
458 }
459
460 matchingDict = IOBSDNameMatching(masterPort, 0, ifr_name);
461 if (matchingDict) {
462 /* Note: IOServiceGetMatchingServices consumes a reference on the 'matchingDict' */
463 kr = IOServiceGetMatchingServices(masterPort, matchingDict, &io_iter);
464 if ((kr == KERN_SUCCESS) && io_iter) {
465 /* should only have a single match */
466 io_interface = IOIteratorNext(io_iter);
467 }
468 if (io_iter) IOObjectRelease(io_iter);
469 }
470
471 if (io_interface) {
472 CFNumberRef num;
473
474 /*
475 * found an interface, get the interface type
476 */
477 num = IORegistryEntryCreateCFProperty(io_interface, CFSTR(kIOInterfaceType), NULL, kNilOptions);
478 if (num) {
479 if (isA_CFNumber(num)) {
480 CFNumberGetValue(num, kCFNumberIntType, &ifType);
481 }
482 CFRelease(num);
483 }
484
485 /*
486 * ...and the property we are REALLY interested is in the controller,
487 * which is the parent of the interface object.
488 */
489 (void)IORegistryEntryGetParentEntry(io_interface, kIOServicePlane, &io_controller);
490 IOObjectRelease(io_interface);
491 } else {
492 /* if no matching interface */
493 return FALSE;
494 }
495
496 if (io_controller) {
497 CFNumberRef num;
498
499 num = IORegistryEntryCreateCFProperty(io_controller, CFSTR(kIOMaxPacketSize), NULL, kNilOptions);
500 if (num) {
501 if (isA_CFNumber(num)) {
502 int value;
503
504 /*
505 * Get the value and subtract the FCS bytes and Ethernet header
506 * sizes from the maximum frame size reported by the controller
507 * to get the MTU size. The 14 byte media header can be found
508 * in the registry, but not the size for the trailing FCS bytes.
509 */
510 CFNumberGetValue(num, kCFNumberIntType, &value);
511
512 if (ifType == IFT_ETHER) {
513 value -= (ETHER_HDR_LEN + ETHER_CRC_LEN);
514 }
515
516 if (mtu_min) *mtu_min = IF_MINMTU;
517 if (mtu_max) *mtu_max = value;
518 }
519 CFRelease(num);
520 }
521
522 IOObjectRelease(io_controller);
523 }
524
525 return TRUE;
526 }
527
528
529 Boolean
530 NetworkInterfaceCopyMTU(CFStringRef interface,
531 int *mtu_cur,
532 int *mtu_min,
533 int *mtu_max)
534 {
535 struct ifreq ifr;
536 Boolean ok = FALSE;
537 int sock = -1;
538
539 bzero((void *)&ifr, sizeof(ifr));
540 if (_SC_cfstring_to_cstring(interface, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII) == NULL) {
541 SCLog(TRUE, LOG_ERR, CFSTR("could not convert interface name"));
542 goto done;
543 }
544
545 sock = socket(AF_INET, SOCK_DGRAM, 0);
546 if (sock < 0) {
547 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
548 goto done;
549 }
550
551 if (ioctl(sock, SIOCGIFMTU, (caddr_t)&ifr) < 0) {
552 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMTU) failed: %s"), strerror(errno));
553 goto done;
554 }
555
556 if (mtu_cur) *mtu_cur = ifr.ifr_mtu;
557 if (mtu_min) *mtu_min = ifr.ifr_mtu;
558 if (mtu_max) *mtu_max = ifr.ifr_mtu;
559
560 /* get valid MTU range */
561
562 if (mtu_min != NULL || mtu_max != NULL) {
563 if (ioctl(sock, SIOCGIFDEVMTU, (caddr_t)&ifr) == 0) {
564 struct ifdevmtu * devmtu_p;
565
566 devmtu_p = &ifr.ifr_devmtu;
567 if (mtu_min != NULL) {
568 *mtu_min = (devmtu_p->ifdm_min > IF_MINMTU)
569 ? devmtu_p->ifdm_min : IF_MINMTU;
570 }
571 if (mtu_max != NULL) {
572 *mtu_max = devmtu_p->ifdm_max;
573 }
574 }
575 else {
576 (void)__getMTULimits(ifr.ifr_name, mtu_min, mtu_max);
577 }
578 }
579
580 ok = TRUE;
581
582 done :
583
584 if (sock >= 0) (void)close(sock);
585
586 return ok;
587 }