1/*
2 * Copyright (c) 2005-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 *  BLIsValidNetworkInterface.c
25 *  bless
26 *
27 *  Created by Shantonu Sen on 11/15/05.
28 *  Copyright 2005-2007 Apple Inc. All Rights Reserved.
29 *
30 */
31
32#import <mach/mach_error.h>
33
34#import <IOKit/IOKitLib.h>
35#import <IOKit/IOKitKeys.h>
36#import <IOKit/network/IONetworkInterface.h>
37#import <IOKit/network/IONetworkController.h>
38#import <IOKit/network/IONetworkMedium.h>
39#import <IOKit/IOBSD.h>
40
41#include <CoreFoundation/CoreFoundation.h>
42
43#include <sys/socket.h>
44#include <net/if.h>
45
46#include "bless.h"
47#include "bless_private.h"
48
49bool isInterfaceLinkUp(BLContextPtr context,
50                        io_service_t service);
51
52bool BLIsValidNetworkInterface(BLContextPtr context,
53                              const char *ifname)
54{
55
56    io_service_t    interface = IO_OBJECT_NULL;
57    CFMutableDictionaryRef  matchingDict = NULL, propDict = NULL;
58    CFStringRef     bsdName;
59
60    bsdName = CFStringCreateWithCString(kCFAllocatorDefault,
61                                        ifname,
62                                        kCFStringEncodingUTF8);
63    if(bsdName == NULL) {
64        contextprintf(context, kBLLogLevelError, "Could not get interpret interface as C string\n");
65        return false;
66    }
67
68    matchingDict = IOServiceMatching(kIONetworkInterfaceClass);
69    propDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
70                                         &kCFTypeDictionaryKeyCallBacks,
71                                         &kCFTypeDictionaryValueCallBacks);
72
73    CFDictionaryAddValue(propDict, CFSTR(kIOBSDNameKey), bsdName);
74    CFDictionaryAddValue(matchingDict, CFSTR(kIOPropertyMatchKey), propDict);
75    CFRelease(propDict);
76    CFRelease(bsdName);
77
78    interface = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict);
79    if(interface == IO_OBJECT_NULL) {
80        contextprintf(context, kBLLogLevelError, "Could not get interface for %s\n",
81                      ifname);
82        return false;
83    }
84
85    if(isInterfaceLinkUp(context, interface)) {
86        contextprintf(context, kBLLogLevelVerbose, "Interface for %s is valid\n",
87                      ifname);
88
89    } else {
90        IOObjectRelease(interface);
91
92        contextprintf(context, kBLLogLevelError, "Interface for %s is not valid\n",
93                      ifname);
94
95        return false;
96    }
97
98    IOObjectRelease(interface);
99
100    return true;
101}
102
103bool isInterfaceLinkUp(BLContextPtr context,
104                                io_service_t serv)
105{
106	CFTypeRef   linkStatus, builtin, netbootable;
107	bool        hasLink, isbootable = false;
108
109	builtin = IORegistryEntryCreateCFProperty(serv, CFSTR(kIOBuiltin),
110											  kCFAllocatorDefault, 0);
111
112	if (builtin && CFGetTypeID(builtin) == CFBooleanGetTypeID()
113		&& CFEqual(builtin, kCFBooleanTrue)) {
114		isbootable = true;
115	}
116	if (builtin) CFRelease(builtin);
117
118	if (!isbootable) {
119		netbootable = IORegistryEntrySearchCFProperty(serv, kIOServicePlane, CFSTR("ioNetBootable"),
120													  kCFAllocatorDefault, kIORegistryIterateRecursively|kIORegistryIterateParents);
121
122		if (netbootable && CFGetTypeID(netbootable) == CFDataGetTypeID()) {
123			isbootable = true;
124		}
125		if (netbootable) CFRelease(netbootable);
126	}
127
128	if(!isbootable) {
129		contextprintf(context, kBLLogLevelError, "Interface is not built-in\n");
130
131		return false;
132	}
133
134
135	linkStatus = IORegistryEntrySearchCFProperty(serv, kIOServicePlane,
136												 CFSTR(kIOLinkStatus),
137												 kCFAllocatorDefault,
138												 kIORegistryIterateRecursively|kIORegistryIterateParents);
139	if(linkStatus == NULL) {
140		hasLink = false;
141	} else {
142		if(CFGetTypeID(linkStatus) != CFNumberGetTypeID()) {
143			hasLink = false;
144		} else {
145			uint32_t    linkNum;
146
147			if(!CFNumberGetValue(linkStatus, kCFNumberSInt32Type, &linkNum)) {
148				hasLink = false;
149			} else {
150				if((linkNum & (kIONetworkLinkValid|kIONetworkLinkActive))
151				   == (kIONetworkLinkValid|kIONetworkLinkActive)) {
152					hasLink = true;
153				} else {
154					hasLink = false;
155				}
156			}
157		}
158		CFRelease(linkStatus);
159	}
160
161	contextprintf(context, kBLLogLevelVerbose, "Interface %s an active link\n",
162				  hasLink ? "has" : "does not have");
163
164	if(hasLink) {
165		return true;
166	} else {
167		return false;
168	}
169}
170
171