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