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