#include <libsa/kmod.h>
#include <libkern/c++/OSContainers.h>
#include <IOKit/IOCatalogue.h>
#include <IOKit/IOLib.h>
#include <libsa/kmod.h>
#include <libsa/catalogue.h>
extern "C" {
#include <mach-o/kld.h>
#include <libsa/vers_rsrc.h>
#include <libsa/stdlib.h>
#include <mach/kmod.h>
#include <vm/vm_kern.h>
#include <mach/kern_return.h>
#include <mach-o/fat.h>
#include <mach_loader.h>
};
#include "kld_patch.h"
extern "C" {
extern kern_return_t
kmod_create_internal(
kmod_info_t *info,
kmod_t *id);
extern kern_return_t
kmod_destroy_internal(kmod_t id);
extern kern_return_t
kmod_start_or_stop(
kmod_t id,
int start,
kmod_args_t *data,
mach_msg_type_number_t *dataCount);
extern kern_return_t kmod_retain(kmod_t id);
extern kern_return_t kmod_release(kmod_t id);
extern void flush_dcache64(addr64_t addr, unsigned cnt, int phys);
extern void invalidate_icache64(addr64_t addr, unsigned cnt, int phys);
};
#define LOG_DELAY()
#define VTYELLOW "\033[33m"
#define VTRESET "\033[0m"
bool verifyCompatibility(OSString * extName, OSString * requiredVersion)
{
OSDictionary * extensionsDict; OSDictionary * extDict; OSDictionary * extPlist; OSString * extVersion; OSString * extCompatVersion; UInt32 ext_version;
UInt32 ext_compat_version;
UInt32 required_version;
extensionsDict = getStartupExtensions();
if (!extensionsDict) {
IOLog("verifyCompatibility(): No extensions dictionary.\n");
return false;
}
extDict = OSDynamicCast(OSDictionary,
extensionsDict->getObject(extName));
if (!extDict) {
IOLog("verifyCompatibility(): "
"Extension \"%s\" cannot be found.\n",
extName->getCStringNoCopy());
return false;
}
extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
if (!extPlist) {
IOLog("verifyCompatibility(): "
"Extension \"%s\" has no property list.\n",
extName->getCStringNoCopy());
return false;
}
extVersion = OSDynamicCast(OSString,
extPlist->getObject("CFBundleVersion"));
if (!extVersion) {
IOLog("verifyCompatibility(): "
"Extension \"%s\" has no \"CFBundleVersion\" property.\n",
extName->getCStringNoCopy());
return false;
}
extCompatVersion = OSDynamicCast(OSString,
extPlist->getObject("OSBundleCompatibleVersion"));
if (!extCompatVersion) {
IOLog("verifyCompatibility(): "
"Extension \"%s\" has no \"OSBundleCompatibleVersion\" property.\n",
extName->getCStringNoCopy());
return false;
}
if (!VERS_parse_string(requiredVersion->getCStringNoCopy(),
&required_version)) {
IOLog("verifyCompatibility(): "
"Can't parse required version \"%s\" of dependency %s.\n",
requiredVersion->getCStringNoCopy(),
extName->getCStringNoCopy());
return false;
}
if (!VERS_parse_string(extVersion->getCStringNoCopy(),
&ext_version)) {
IOLog("verifyCompatibility(): "
"Can't parse version \"%s\" of dependency %s.\n",
extVersion->getCStringNoCopy(),
extName->getCStringNoCopy());
return false;
}
if (!VERS_parse_string(extCompatVersion->getCStringNoCopy(),
&ext_compat_version)) {
IOLog("verifyCompatibility(): "
"Can't parse compatible version \"%s\" of dependency %s.\n",
extCompatVersion->getCStringNoCopy(),
extName->getCStringNoCopy());
return false;
}
if (required_version > ext_version || required_version < ext_compat_version) {
return false;
}
return true;
}
static
Boolean kextIsADependency(OSString * name) {
Boolean result = true;
OSDictionary * extensionsDict = 0; OSDictionary * extDict = 0; OSDictionary * extPlist = 0; OSBoolean * isKernelResourceObj = 0; OSData * driverCode = 0; OSData * compressedCode = 0;
extensionsDict = getStartupExtensions();
if (!extensionsDict) {
IOLog("kextIsADependency(): No extensions dictionary.\n");
LOG_DELAY();
result = false;
goto finish;
}
extDict = OSDynamicCast(OSDictionary,
extensionsDict->getObject(name));
if (!extDict) {
IOLog("kextIsADependency(): "
"Extension \"%s\" cannot be found.\n",
name->getCStringNoCopy());
LOG_DELAY();
result = false;
goto finish;
}
extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
if (!extPlist) {
IOLog("getDependencyListForKmod(): "
"Extension \"%s\" has no property list.\n",
name->getCStringNoCopy());
LOG_DELAY();
result = false;
goto finish;
}
isKernelResourceObj = OSDynamicCast(OSBoolean,
extPlist->getObject("OSKernelResource"));
if (isKernelResourceObj && isKernelResourceObj->isTrue()) {
result = true;
goto finish;
}
driverCode = OSDynamicCast(OSData, extDict->getObject("code"));
compressedCode = OSDynamicCast(OSData,
extDict->getObject("compressedCode"));
if (!driverCode && !compressedCode) {
result = false;
goto finish;
}
finish:
return result;
}
static
OSArray * getDependencyListForKmod(const char * kmod_name) {
int error = 0;
OSDictionary * extensionsDict; OSDictionary * extDict; OSDictionary * extPlist; OSString * extName; OSArray * dependencyList = NULL; unsigned int i;
OSArray * originalList = NULL; OSDictionary * encounteredNames = NULL;
extensionsDict = getStartupExtensions();
if (!extensionsDict) {
IOLog("getDependencyListForKmod(): No extensions dictionary.\n");
LOG_DELAY();
error = 1;
goto finish;
}
extDict = OSDynamicCast(OSDictionary,
extensionsDict->getObject(kmod_name));
if (!extDict) {
IOLog("getDependencyListForKmod(): "
"Extension \"%s\" cannot be found.\n",
kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
if (!extPlist) {
IOLog("getDependencyListForKmod(): "
"Extension \"%s\" has no property list.\n",
kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
extName = OSDynamicCast(OSString,
extPlist->getObject("CFBundleIdentifier"));
if (!extName) {
IOLog("getDependencyListForKmod(): "
"Extension \"%s\" has no \"CFBundleIdentifier\" property.\n",
kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
dependencyList = OSArray::withCapacity(10);
if (!dependencyList) {
IOLog("getDependencyListForKmod(): "
"Couldn't allocate dependency array for extension \"%s\".\n",
kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
dependencyList->setObject(extName);
for (i = 0; i < dependencyList->getCount(); i++) {
OSString * curName;
OSDictionary * curExtDict;
OSDictionary * curExtDepDict;
OSDictionary * curExtPlist;
OSString * curDepName;
if (i > 255) {
IOLog("getDependencyListForKmod(): "
"max dependency list length exceeded for "
"extension \"%s\".\n",
kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
curName = OSDynamicCast(OSString, dependencyList->getObject(i));
curExtDict = OSDynamicCast(OSDictionary,
extensionsDict->getObject(curName));
if (!curExtDict) {
IOLog("getDependencyListForKmod(): "
"Extension \"%s\", required for extension \"%s\", "
"is not available.\n",
curName->getCStringNoCopy(), kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
curExtPlist = OSDynamicCast(OSDictionary,
curExtDict->getObject("plist"));
if (!curExtPlist) {
IOLog("getDependencyListForKmod(): "
"Extension \"%s\", required for extension \"%s\", "
"has no property list.\n",
curName->getCStringNoCopy(), kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
curExtDepDict = OSDynamicCast(OSDictionary,
curExtPlist->getObject("OSBundleLibraries"));
if (curExtDepDict) {
OSCollectionIterator * keyIterator =
OSCollectionIterator::withCollection(curExtDepDict);
if (!keyIterator) {
IOLog("getDependencyListForKmod(): "
"Couldn't allocate iterator for extension "
"\"%s\".\n", kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
while ( (curDepName =
OSDynamicCast(OSString,
keyIterator->getNextObject())) ) {
OSString * requiredVersion = OSDynamicCast(OSString,
curExtDepDict->getObject(curDepName));
if (!verifyCompatibility(curDepName, requiredVersion)) {
IOLog("getDependencyListForKmod(): "
"Dependency %s of %s is not compatible or is unavailable.\n",
curDepName->getCStringNoCopy(),
curName->getCStringNoCopy());
LOG_DELAY();
error = 1;
goto finish;
}
dependencyList->setObject(curDepName);
}
keyIterator->release();
}
}
originalList = dependencyList;
dependencyList = OSArray::withCapacity(originalList->getCount());
if (!dependencyList) {
IOLog("getDependenciesForKmod(): "
"Couldn't allocate reversal dependency list for extension "
"\"%s\".\n", kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
encounteredNames = OSDictionary::withCapacity(originalList->getCount());
if (!encounteredNames) {
IOLog("getDependenciesForKmod(): "
"Couldn't allocate list of encountered names for extension "
"\"%s\".\n", kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
i = originalList->getCount();
if (i > 0) {
do {
i--;
OSString * item = OSDynamicCast(OSString,
originalList->getObject(i));
if ( (!encounteredNames->getObject(item)) &&
kextIsADependency(item)) {
encounteredNames->setObject(item, originalList);
dependencyList->setObject(item);
}
} while (i > 0);
}
finish:
if (originalList) {
originalList->release();
}
if (encounteredNames) {
encounteredNames->release();
}
if (error) {
if (dependencyList) {
dependencyList->release();
dependencyList = NULL;
}
}
return dependencyList;
}
static kmod_info_t * g_current_kmod_info = NULL;
static const char * g_current_kmod_name = NULL;
static unsigned long link_load_address = 0;
static unsigned long link_load_size = 0;
static unsigned long link_buffer_size = 0;
static unsigned long link_header_size = 0;
static unsigned long link_buffer_address = 0;
static
unsigned long address_for_loaded_kmod(
unsigned long size,
unsigned long headers_size) {
unsigned long round_headers_size;
unsigned long headers_pad;
if (!g_current_kmod_info) {
IOLog("address_for_loaded_kmod(): No current kmod.\n");
LOG_DELAY();
link_load_address = 0; return 0;
}
round_headers_size = round_page_32(headers_size);
headers_pad = round_headers_size - headers_size;
link_load_address = (unsigned long)g_current_kmod_info->address +
headers_pad;
return link_load_address;
}
static
unsigned long alloc_for_kmod(
unsigned long size,
unsigned long headers_size) {
vm_address_t buffer = 0;
kern_return_t k_result;
unsigned long round_headers_size;
unsigned long round_segments_size;
unsigned long round_size;
unsigned long headers_pad;
round_headers_size = round_page_32(headers_size);
round_segments_size = round_page_32(size - headers_size);
round_size = round_headers_size + round_segments_size;
headers_pad = round_headers_size - headers_size;
k_result = vm_allocate(kernel_map, (vm_offset_t *)&buffer,
round_size, VM_FLAGS_ANYWHERE);
if (k_result != KERN_SUCCESS) {
IOLog("alloc_for_kmod(): Can't allocate memory.\n");
LOG_DELAY();
link_buffer_address = 0; link_load_address = 0; return 0;
}
link_load_size = size;
link_buffer_address = buffer;
link_buffer_size = round_size;
link_header_size = headers_size;
link_load_address = link_buffer_address + headers_pad;
return link_load_address;
}
static
int map_and_patch(const char * kmod_name) {
char *address;
address = (char *) kld_file_getaddr(kmod_name, NULL);
if (address)
return 1;
OSDictionary * extensionsDict;
OSDictionary * kmodDict;
OSData * compressedCode = 0;
OSData * driverCode;
extensionsDict = getStartupExtensions();
if (!extensionsDict) {
IOLog("map_and_patch(): No extensions dictionary.\n");
LOG_DELAY();
return 0;
}
kmodDict = OSDynamicCast(OSDictionary,
extensionsDict->getObject(kmod_name));
if (!kmodDict) {
IOLog("map_and_patch(): "
"Extension \"%s\" cannot be found.\n", kmod_name);
LOG_DELAY();
return 0;
}
Boolean ret = false;
driverCode = OSDynamicCast(OSData, kmodDict->getObject("code"));
if (driverCode) {
ret = kld_file_map(kmod_name,
(unsigned char *) driverCode->getBytesNoCopy(),
(size_t) driverCode->getLength(),
false);
}
else {
compressedCode = OSDynamicCast(OSData,
kmodDict->getObject("compressedCode"));
if (!compressedCode) {
IOLog("map_and_patch(): "
"Extension \"%s\" has no \"code\" property.\n", kmod_name);
LOG_DELAY();
return 0;
}
if (!uncompressModule(compressedCode, &driverCode)) {
IOLog("map_and_patch(): "
"Extension \"%s\" Couldn't uncompress code.\n", kmod_name);
LOG_DELAY();
return 0;
}
unsigned char *driver = (unsigned char *) driverCode->getBytesNoCopy();
size_t driverSize = driverCode->getLength();
ret = kld_file_map(kmod_name, driver, driverSize, true);
driverCode->release();
if (!ret)
kmem_free(kernel_map, (vm_address_t) driver, driverSize);
}
if (!ret) {
IOLog("map_and_patch(): "
"Extension \"%s\" Didn't successfully load.\n", kmod_name);
LOG_DELAY();
return 0;
}
ret = TRUE;
if (!kld_file_patch_OSObjects(kmod_name)) {
IOLog("map_and_patch(): "
"Extension \"%s\" Error binding OSObjects.\n", kmod_name);
LOG_DELAY();
ret = FALSE;
}
kld_file_prepare_for_link();
return ret;
}
bool stamp_kmod(const char * kmod_name, kmod_info_t * kmod_info) {
bool result = false;
OSDictionary * extensionsDict = NULL; OSDictionary * kmodDict = NULL; OSDictionary * plist = NULL; OSString * versionString = NULL; const char * plist_version = NULL;
if (strlen(kmod_name) + 1 > KMOD_MAX_NAME) {
IOLog("stamp_kmod(): Kext identifier \"%s\" is too long.\n",
kmod_name);
LOG_DELAY();
result = false;
goto finish;
}
strcpy(kmod_info->name, kmod_name);
extensionsDict = getStartupExtensions();
if (!extensionsDict) {
IOLog("stamp_kmod(): No extensions dictionary.\n");
LOG_DELAY();
result = false;
goto finish;
}
kmodDict = OSDynamicCast(OSDictionary,
extensionsDict->getObject(kmod_name));
if (!kmodDict) {
IOLog("stamp_kmod(): Can't find record for kmod \"%s\".\n",
kmod_name);
LOG_DELAY();
result = false;
goto finish;
}
plist = OSDynamicCast(OSDictionary,
kmodDict->getObject("plist"));
if (!kmodDict) {
IOLog("stamp_kmod(): Kmod \"%s\" has no property list.\n",
kmod_name);
LOG_DELAY();
result = false;
goto finish;
}
versionString = OSDynamicCast(OSString,
plist->getObject("CFBundleVersion"));
if (!versionString) {
IOLog("stamp_kmod(): Kmod \"%s\" has no \"CFBundleVersion\" "
"property.\n",
kmod_name);
LOG_DELAY();
result = false;
goto finish;
}
plist_version = versionString->getCStringNoCopy();
if (!plist_version) {
IOLog("stamp_kmod(): Can't get C string for kext version.\n");
LOG_DELAY();
result = false;
goto finish;
}
if (strlen(plist_version) + 1 > KMOD_MAX_NAME) {
IOLog("stamp_kmod(): Version \"%s\" of kext \"%s\" is too long.\n",
plist_version, kmod_name);
LOG_DELAY();
result = false;
goto finish;
}
strcpy(kmod_info->version, plist_version);
result = true;
finish:
return result;
}
static
kern_return_t load_kmod(OSArray * dependencyList) {
kern_return_t result = KERN_SUCCESS;
unsigned int num_dependencies = 0;
kmod_info_t ** kmod_dependencies = NULL;
unsigned int i;
OSString * requestedKmodName; const char * requested_kmod_name;
OSString * currentKmodName; char * kmod_address;
unsigned long kmod_size;
struct mach_header * kmod_header;
unsigned long kld_result;
int do_kld_unload = 0;
kmod_info_t * kmod_info_freeme = 0;
kmod_info_t * kmod_info = 0;
kmod_t kmod_id;
i = dependencyList->getCount();
if (i == 0) {
IOLog("load_kmod(): Called with empty list.\n");
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
} else {
i--; }
requestedKmodName = OSDynamicCast(OSString, dependencyList->getObject(i));
if (!requestedKmodName) {
IOLog("load_kmod(): Called with invalid list of kmod names.\n");
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
requested_kmod_name = requestedKmodName->getCStringNoCopy();
dependencyList->removeObject(i);
kmod_info_freeme = kmod_lookupbyname_locked(requested_kmod_name);
if (kmod_info_freeme) {
result = KERN_SUCCESS;
goto finish;
}
kld_address_func(&address_for_loaded_kmod);
num_dependencies = dependencyList->getCount();
kmod_dependencies = (kmod_info_t **)kalloc(num_dependencies *
sizeof(kmod_info_t *));
if (!kmod_dependencies) {
IOLog("load_kmod(): Failed to allocate memory for dependency array "
"during load of kmod \"%s\".\n", requested_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
bzero(kmod_dependencies, num_dependencies *
sizeof(kmod_info_t *));
for (i = 0; i < num_dependencies; i++) {
currentKmodName = OSDynamicCast(OSString,
dependencyList->getObject(i));
if (!currentKmodName) {
IOLog("load_kmod(): Invalid dependency name at index %d for "
"kmod \"%s\".\n", i, requested_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
const char * current_kmod_name = currentKmodName->getCStringNoCopy();
g_current_kmod_info = kmod_lookupbyname_locked(current_kmod_name);
g_current_kmod_name = current_kmod_name;
if (!g_current_kmod_info) {
IOLog("load_kmod(): Missing dependency \"%s\".\n",
current_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
kmod_dependencies[i] = g_current_kmod_info;
if (!g_current_kmod_info->size)
continue;
if (!kld_file_merge_OSObjects(current_kmod_name)) {
IOLog("load_kmod(): Can't merge OSObjects \"%s\".\n",
current_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
kmod_address = (char *)
kld_file_getaddr(current_kmod_name, (long *) &kmod_size);
if (!kmod_address) {
IOLog("load_kmod() failed for dependency kmod "
"\"%s\".\n", current_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
kld_result = kld_load_from_memory(&kmod_header,
current_kmod_name, kmod_address, kmod_size);
if (kld_result) {
do_kld_unload = 1;
}
if (!kld_result || !link_load_address) {
IOLog("kld_load_from_memory() failed for dependency kmod "
"\"%s\".\n", current_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
kld_forget_symbol("_kmod_info");
}
kld_address_func(&alloc_for_kmod);
g_current_kmod_name = requested_kmod_name;
g_current_kmod_info = 0;
if (!map_and_patch(requested_kmod_name)) {
IOLog("load_kmod: map_and_patch() failed for "
"kmod \"%s\".\n", requested_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
kmod_address = (char *)
kld_file_getaddr(requested_kmod_name, (long *) &kmod_size);
if (!kmod_address) {
IOLog("load_kmod: kld_file_getaddr() failed internal error "
"on \"%s\".\n", requested_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
kld_result = kld_load_from_memory(&kmod_header,
requested_kmod_name, kmod_address, kmod_size);
if (kld_result) {
do_kld_unload = 1;
}
if (!kld_result || !link_load_address) {
IOLog("load_kmod(): kld_load_from_memory() failed for "
"kmod \"%s\".\n", requested_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
bzero((char *)link_buffer_address, link_buffer_size);
bcopy((char *)kmod_header, (char *)link_buffer_address, link_header_size);
bcopy((char *)kmod_header + link_header_size,
(char *)link_buffer_address + round_page_32(link_header_size),
link_load_size - link_header_size);
if (!kld_lookup("_kmod_info", (unsigned long *)&kmod_info)) {
IOLog("kld_lookup() of \"_kmod_info\" failed for "
"kmod \"%s\".\n", requested_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
if (!stamp_kmod(requested_kmod_name, kmod_info)) {
result = KERN_FAILURE;
goto finish;
}
kmod_info->address = link_buffer_address;
kmod_info->size = link_buffer_size;
kmod_info->hdr_size = round_page_32(link_header_size);
flush_dcache64((addr64_t)link_buffer_address, link_buffer_size, false);
invalidate_icache64((addr64_t)link_buffer_address, link_buffer_size, false);
if (kmod_create_internal(kmod_info, &kmod_id) != KERN_SUCCESS) {
IOLog("load_kmod(): kmod_create() failed for "
"kmod \"%s\".\n", requested_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
#if DEBUG
IOLog("kmod id %d successfully created at 0x%lx, size %ld.\n",
(unsigned int)kmod_id, link_buffer_address, link_buffer_size);
LOG_DELAY();
#endif
for (i = 0; i < num_dependencies; i++) {
kmod_info_t * cur_dependency_info;
kmod_t packed_id;
cur_dependency_info = kmod_dependencies[i];
packed_id = KMOD_PACK_IDS(kmod_id, cur_dependency_info->id);
if (kmod_retain(packed_id) != KERN_SUCCESS) {
IOLog("load_kmod(): kmod_retain() failed for "
"kmod \"%s\".\n", requested_kmod_name);
LOG_DELAY();
kmod_destroy_internal(kmod_id);
result = KERN_FAILURE;
goto finish;
}
}
if (kmod_start_or_stop(kmod_id, 1, 0, 0) != KERN_SUCCESS) {
IOLog("load_kmod(): kmod_start_or_stop() failed for "
"kmod \"%s\".\n", requested_kmod_name);
LOG_DELAY();
kmod_destroy_internal(kmod_id);
result = KERN_FAILURE;
goto finish;
}
finish:
if (kmod_info_freeme) {
kfree((unsigned int)kmod_info_freeme, sizeof(kmod_info_t));
}
if (do_kld_unload) {
kld_unload_all( 1);
}
if (result != KERN_SUCCESS && link_buffer_address) {
vm_deallocate(kernel_map, link_buffer_address, link_buffer_size);
}
if (kmod_dependencies) {
for (i = 0; i < num_dependencies; i++) {
if (kmod_dependencies[i]) {
kfree((unsigned int)kmod_dependencies[i], sizeof(kmod_info_t));
}
}
kfree((unsigned int)kmod_dependencies,
num_dependencies * sizeof(kmod_info_t *));
}
g_current_kmod_name = NULL;
g_current_kmod_info = NULL;
link_buffer_address = 0;
link_load_address = 0;
link_load_size = 0;
link_buffer_size = 0;
link_header_size = 0;
return result;
}
__private_extern__
kern_return_t load_kernel_extension(char * kmod_name) {
kern_return_t result = KERN_SUCCESS;
kmod_info_t * kmod_info = 0; OSArray * dependencyList = NULL; OSArray * curDependencyList = NULL;
kmod_info = kmod_lookupbyname_locked(kmod_name);
if (kmod_info) { result = KERN_SUCCESS;
goto finish;
}
unsigned int count;
unsigned int i;
dependencyList = getDependencyListForKmod(kmod_name);
if (!dependencyList) {
IOLog("load_kernel_extension(): "
"Can't get dependencies for kernel extension \"%s\".\n",
kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
count = dependencyList->getCount();
for (i = 0; i < count; i++) {
kern_return_t load_result;
OSString * curKmodName; const char * cur_kmod_name;
curKmodName = OSDynamicCast(OSString,
dependencyList->getObject(i));
cur_kmod_name = curKmodName->getCStringNoCopy();
curDependencyList = getDependencyListForKmod(cur_kmod_name);
if (!curDependencyList) {
IOLog("load_kernel_extension(): "
"Can't get dependencies for kernel extension \"%s\".\n",
cur_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
} else {
load_result = load_kmod(curDependencyList);
if (load_result != KERN_SUCCESS) {
IOLog("load_kernel_extension(): "
"load_kmod() failed for kmod \"%s\".\n",
cur_kmod_name);
LOG_DELAY();
result = load_result;
goto finish;
}
curDependencyList->release();
curDependencyList = NULL;
}
}
finish:
if (kmod_info) {
kfree((unsigned int)kmod_info, sizeof(kmod_info_t));
}
if (dependencyList) {
dependencyList->release();
dependencyList = NULL;
}
if (curDependencyList) {
curDependencyList->release();
curDependencyList = NULL;
}
return result;
}