1/* 2 * Copyright (c) 2009-2013 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/* 25 * InterestNotification.c 26 * - register for IOKit interest notification on a particular BSD name 27 */ 28 29/* 30 * Modification History 31 * 32 * March 10, 2009 Dieter Siegmund (dieter@apple) 33 * - created 34 */ 35 36#include <IOKit/IOKitLib.h> 37#include <IOKit/IOMessage.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <unistd.h> 41#include <string.h> 42#include "EAPLog.h" 43#include "InterestNotification.h" 44 45struct InterestNotification { 46 IONotificationPortRef notify; 47 io_object_t if_change; 48 InterestNotificationCallbackRef callback; 49 const void * arg; 50}; 51 52static void 53InterestNotificationHandleMessage(void * refcon, io_service_t service, 54 natural_t message_type, 55 void * messageArgument) 56{ 57 InterestNotificationRef interest_p = (InterestNotificationRef)refcon; 58 59 if (message_type == kIOMessageServicePropertyChange) { 60 InterestNotificationCallbackRef callback = interest_p->callback; 61 const void * arg = interest_p->arg; 62 63 (*callback)(interest_p, arg); 64 } 65 return; 66} 67 68static void 69InterestNotificationInit(InterestNotificationRef interest_p) 70{ 71 bzero(interest_p, sizeof(*interest_p)); 72 return; 73} 74 75void 76InterestNotificationRelease(InterestNotificationRef interest_p) 77{ 78 if (interest_p->if_change != MACH_PORT_NULL) { 79 IOObjectRelease(interest_p->if_change); 80 } 81 if (interest_p->notify != MACH_PORT_NULL) { 82 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), 83 IONotificationPortGetRunLoopSource(interest_p->notify), 84 kCFRunLoopDefaultMode); 85 IONotificationPortDestroy(interest_p->notify); 86 } 87 InterestNotificationInit(interest_p); 88 free(interest_p); 89 return; 90} 91 92static boolean_t 93InterestNotificationStart(InterestNotificationRef interest_p, 94 const char * if_name, 95 InterestNotificationCallbackRef callback, 96 const void * arg) 97{ 98 io_object_t if_change = MACH_PORT_NULL; 99 kern_return_t kr; 100 io_iterator_t list = MACH_PORT_NULL; 101 CFDictionaryRef matching; 102 IONotificationPortRef notify = NULL; 103 io_object_t obj = MACH_PORT_NULL; 104 boolean_t ok = FALSE; 105 106 matching = IOBSDNameMatching(kIOMasterPortDefault, 0, if_name); 107 kr = IOServiceGetMatchingServices(kIOMasterPortDefault, 108 matching, &list); 109 if (kr != KERN_SUCCESS) { 110 EAPLOG_FL(LOG_NOTICE, "No such interface %s\n", if_name); 111 goto done; 112 } 113 notify = IONotificationPortCreate(kIOMasterPortDefault); 114 if (notify == NULL) { 115 EAPLOG_FL(LOG_NOTICE, "IONotificationPortCreate failed\n"); 116 goto done; 117 } 118 obj = IOIteratorNext(list); 119 if (obj == MACH_PORT_NULL) { 120 EAPLOG_FL(LOG_NOTICE, "IOIteratorNext no object\n"); 121 goto done; 122 } 123 kr = IOServiceAddInterestNotification(notify, 124 obj, 125 kIOGeneralInterest, 126 &InterestNotificationHandleMessage, 127 (void *)interest_p, 128 &if_change); 129 if (kr != KERN_SUCCESS) { 130 EAPLOG_FL(LOG_NOTICE, "IOServiceAddInterestNotification failed, 0x%x\n", 131 kr); 132 goto done; 133 } 134 CFRunLoopAddSource(CFRunLoopGetCurrent(), 135 IONotificationPortGetRunLoopSource(notify), 136 kCFRunLoopDefaultMode); 137 interest_p->notify = notify; 138 interest_p->if_change = if_change; 139 interest_p->callback = callback; 140 interest_p->arg = arg; 141 ok = TRUE; 142 143 done: 144 if (list != MACH_PORT_NULL) { 145 IOObjectRelease(list); 146 } 147 if (obj != MACH_PORT_NULL) { 148 IOObjectRelease(obj); 149 } 150 if (ok == FALSE) { 151 if (notify != NULL) { 152 IONotificationPortDestroy(notify); 153 } 154 if (if_change != MACH_PORT_NULL) { 155 IOObjectRelease(if_change); 156 } 157 } 158 return (ok); 159} 160 161InterestNotificationRef 162InterestNotificationCreate(const char * if_name, 163 InterestNotificationCallbackRef callback, 164 const void * arg) 165{ 166 InterestNotificationRef interest_p; 167 168 if (callback == NULL) { 169 return (NULL); 170 } 171 interest_p = (InterestNotificationRef)malloc(sizeof(*interest_p)); 172 InterestNotificationInit(interest_p); 173 if (InterestNotificationStart(interest_p, if_name, callback, arg) 174 == FALSE) { 175 free(interest_p); 176 return (NULL); 177 } 178 return (interest_p); 179} 180 181#ifdef TEST_INTERESTNOTIFICATION 182 183static void 184change_callback(InterestNotificationRef interest_p, 185 const void * arg) 186{ 187 printf("Change, all done\n"); 188 InterestNotificationRelease(interest_p); 189 return; 190} 191 192int 193main(int argc, char * argv[]) 194{ 195 InterestNotificationRef interest_p; 196 197 if (argc < 2) { 198 fprintf(stderr, "usage: ioregwatch <ifname>\n"); 199 exit(1); 200 } 201 interest_p = InterestNotificationCreate(argv[1], 202 change_callback, NULL); 203 if (interest_p == NULL) { 204 fprintf(stderr, "Create failed\n"); 205 exit(2); 206 } 207 CFRunLoopRun(); 208 exit(0); 209 return (0); 210} 211 212#endif /* TEST_INTERESTNOTIFICATION */ 213