1/* 2 * Copyright (c) 2000 Apple Computer, 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 * Display the link status properties of a network interface. 25 * 26 * To build: 27 * cc monitorlink.c -o monitorlink -framework IOKit -Wall 28 */ 29 30#include <assert.h> 31 32#include <CoreFoundation/CoreFoundation.h> 33#include <IOKit/IOCFSerialize.h> 34#include <IOKit/IOKitLib.h> 35 36#include <IOKit/network/IONetworkLib.h> 37 38#include <ctype.h> 39#include <stdlib.h> 40#include <stdio.h> 41#include <unistd.h> 42 43#include <mach/mach.h> 44 45//--------------------------------------------------------------------------- 46// Property table keys. 47 48#define IF_NAME_KEY "BSD Name" 49#define kIOMediumDictionary "IOMediumDictionary" 50#define kIODefaultMedium "IODefaultMedium" 51#define kIOCurrentMedium "IOCurrentMedium" 52#define kIOActiveMedium "IOActiveMedium" 53#define kIOLinkSpeed "IOLinkSpeed" 54#define kIOLinkStatus "IOLinkStatus" 55#define kIOLinkData "IOLinkData" 56 57//--------------------------------------------------------------------------- 58// Utilities functions to print CFNumber and CFString. 59 60static void CFNumberShow(CFNumberRef object) 61{ 62 long long number = 0; 63 64 if (CFNumberGetValue(object, kCFNumberLongLongType, &number)) 65 { 66 printf("%qd", number); 67 } 68} 69 70static void CFStringShow(CFStringRef object) 71{ 72 const char * c = CFStringGetCStringPtr(object, 73 kCFStringEncodingMacRoman); 74 75 if (c) 76 printf(c); 77 else 78 { 79 CFIndex bufferSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(object), 80 kCFStringEncodingMacRoman) + sizeof('\0'); 81 char * buffer = (char *) malloc(bufferSize); 82 83 if (buffer) 84 { 85 if ( CFStringGetCString( 86 /* string */ object, 87 /* buffer */ buffer, 88 /* bufferSize */ bufferSize, 89 /* encoding */ kCFStringEncodingMacRoman) ) 90 printf(buffer); 91 92 free(buffer); 93 } 94 } 95} 96 97//--------------------------------------------------------------------------- 98// Returns non zero if the property table of the object has a "BSD Name" 99// string entry, and the string matches the provided string argument. 100 101static int matchBSDNameProperty(io_object_t obj, CFStringRef ifname) 102{ 103 int match = 0; 104 kern_return_t kr; 105 CFMutableDictionaryRef properties; 106 CFStringRef string; 107 108 kr = IORegistryEntryCreateCFProperties(obj, 109 &properties, 110 kCFAllocatorDefault, 111 kNilOptions); 112 113 if ((kr != KERN_SUCCESS) || !properties) { 114 printf("IORegistryEntryCreateCFProperties error %x\n", kr); 115 return false; 116 } 117 118 // Look up the interface "BSD Name" property and perform matching. 119 // 120 string = (CFStringRef) CFDictionaryGetValue(properties, 121 CFSTR(IF_NAME_KEY)); 122 if (string) { 123 if (CFStringCompare(ifname, string, kNilOptions) == kCFCompareEqualTo) 124 { 125 printf("[ "); 126 CFStringShow(string); 127 printf(" ]\n"); 128 match = 1; 129 } 130 } 131 132 CFRelease(properties); 133 134 return match; // true if matched 135} 136 137//--------------------------------------------------------------------------- 138// Searches the IOKit registry and return an interface object with the 139// given BSD interface name, i.e. en0. 140 141static io_object_t 142getInterfaceWithBSDName(mach_port_t masterPort, CFStringRef ifname) 143{ 144 kern_return_t kr; 145 io_iterator_t ite; 146 io_object_t obj = 0; 147 const char * className = "IONetworkInterface"; 148 149 kr = IORegistryCreateIterator(masterPort, 150 kIOServicePlane, 151 true, /* recursive */ 152 &ite); 153 154 if (kr != kIOReturnSuccess) { 155 printf("IORegistryCreateIterator() error %x\n", kr); 156 return 0; 157 } 158 159 while ((obj = IOIteratorNext(ite))) { 160 if (IOObjectConformsTo(obj, (char *) className) && 161 (matchBSDNameProperty(obj, ifname))) 162 break; 163 164 IOObjectRelease(obj); 165 obj = 0; 166 } 167 168 IORegistryDisposeEnumerator(ite); 169 170 return obj; 171} 172 173//--------------------------------------------------------------------------- 174// Display the link related properties for an IONetworkController object. 175 176static void 177printLinkProperties(io_object_t controller) 178{ 179 kern_return_t kr; 180 CFMutableDictionaryRef properties = 0; 181 CFStringRef string; 182 CFNumberRef number; 183 184 do { 185 kr = IORegistryEntryCreateCFProperties(controller, 186 &properties, 187 kCFAllocatorDefault, 188 kNilOptions); 189 if (kr != kIOReturnSuccess) { 190 printf("Error: cannot get properties %x\n", kr); 191 break; 192 } 193 194 // Print kIOActiveMedium string. 195 // 196 string = (CFStringRef) CFDictionaryGetValue(properties, 197 CFSTR(kIOActiveMedium)); 198 printf("Active medium : "); 199 if (string) { 200 CFStringShow(string); 201 printf("\n"); 202 } 203 else { 204 printf("None\n"); 205 } 206 207 // Print kIOCurrentMedium string. 208 // 209 string = (CFStringRef) CFDictionaryGetValue(properties, 210 CFSTR(kIOCurrentMedium)); 211 printf("Current medium : "); 212 if (string) { 213 CFStringShow(string); 214 printf("\n"); 215 } 216 else { 217 printf("None\n"); 218 } 219 220 // Print kIOLinkSpeed number. 221 // 222 number = (CFNumberRef) CFDictionaryGetValue(properties, 223 CFSTR(kIOLinkSpeed)); 224 if (number) { 225 printf("Link speed bps : "); 226 CFNumberShow(number); 227 printf("\n"); 228 } 229 230 // Print kIOLinkSpeed number. 231 // 232 number = (CFNumberRef) CFDictionaryGetValue(properties, 233 CFSTR(kIOLinkStatus)); 234 if (number) { 235 long status; 236 237 if (CFNumberGetValue(number, kCFNumberLongType, &status)) 238 { 239 printf("Link status : "); 240 241 if (status & kIONetworkLinkValid) 242 { 243 printf("%s\n", (status & kIONetworkLinkActive) ? "Active" : 244 "Inactive"); 245 } 246 else 247 printf("Not reported\n"); 248 } 249 } 250 } 251 while (0); 252 253 if (properties) 254 CFRelease(properties); 255} 256 257//--------------------------------------------------------------------------- 258// Get the parent object (a network controller) of an interface object. 259 260static io_object_t 261getControllerForInterface(io_object_t netif) 262{ 263 io_iterator_t ite; 264 kern_return_t kr; 265 io_object_t controller = 0; 266 267 // We have the interface, we need its parent, the network controller. 268 269 kr = IORegistryEntryGetParentIterator(netif, kIOServicePlane, &ite); 270 if (kr == kIOReturnSuccess) { 271 controller = IOIteratorNext(ite); // the first entry 272 IORegistryDisposeEnumerator(ite); 273 } 274 275 return controller; // caller must release this object 276} 277 278//--------------------------------------------------------------------------- 279// Returns when a mach message is received on the port specified. 280 281static void 282waitForNotification(mach_port_t port) 283{ 284 kern_return_t kr; 285 286 struct { 287 IONetworkNotifyMsg hdr; 288 mach_msg_trailer_t trailer; 289 } msg; 290 291 // Now wait for a notification. 292 // 293 kr = mach_msg(&msg.hdr.h, MACH_RCV_MSG, 294 0, sizeof(msg), port, 0, MACH_PORT_NULL); 295 296 if (kr != KERN_SUCCESS) 297 printf("Error: mach_msg %x\n", kr); 298// else 299// printf("\n\n[message id=%x]\n", msg.hdr.h.msgh_id); 300} 301 302//--------------------------------------------------------------------------- 303// Display usage and quit. 304 305static void usage(void) 306{ 307 /* 308 * Print usage and exit. 309 */ 310 printf("usage: monitorlink [-i ifname] [-w]\n"); 311 printf("option flags:\n"); 312 printf(" -i ifname : specify interface. Default is en0.\n"); 313 printf(" -w : wait for link event notification.\n"); 314 printf("\n"); 315 exit(1); 316} 317 318//--------------------------------------------------------------------------- 319// Main function. 320 321int 322main(int argc, char ** argv) 323{ 324 mach_port_t masterPort; 325 mach_port_t notifyPort; 326 kern_return_t kr; 327 io_object_t netif; 328 io_object_t controller; 329 io_connect_t con; 330 int ch; 331 const char * name = "en0"; // default interface name 332 CFStringRef ifname; 333 int wait = 0; 334 335 while ((ch = getopt(argc, argv, ":i:w")) != -1) 336 { 337 switch ((char) ch) 338 { 339 case 'i': /* specify interface */ 340 if (!optarg) 341 usage(); 342 name = optarg; 343 break; 344 345 case 'w': /* specify interface */ 346 wait = 1; 347 break; 348 349 default: 350 usage(); 351 } 352 } 353 354 if (name == 0) 355 usage(); 356 357 // Get master device port 358 // 359 kr = IOMasterPort(bootstrap_port, &masterPort); 360 if (kr != KERN_SUCCESS) 361 printf("IOMasterPort() failed: %x\n", kr); 362 363 364 // Create a mach port to receive media/link change notifications. 365 // 366 kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, 367 ¬ifyPort); 368 if (kr != KERN_SUCCESS) { 369 printf("Error: mach_port_allocate %x\n", kr); 370 exit(1); 371 } 372 373 ifname = CFStringCreateWithCString(kCFAllocatorDefault, 374 name, 375 kCFStringEncodingMacRoman); 376 377 netif = getInterfaceWithBSDName(masterPort, ifname); 378 379 if (netif) 380 { 381 kr = IONetworkOpen(netif, &con); 382 if (kr != kIOReturnSuccess) 383 { 384 printf("Error: IONetworkOpen error %x\n", kr); 385 exit(1); 386 } 387 388 kr = IOConnectSetNotificationPort(con, 389 kIONUCNotificationTypeLinkChange, notifyPort, 0); 390 if (kr != kIOReturnSuccess) { 391 printf("Error: IOConnectSetNotificationPort %x\n", kr); 392 exit(1); 393 } 394 395 controller = getControllerForInterface(netif); 396 397 if (controller) 398 { 399 do { 400 printLinkProperties(controller); 401 printf("\n"); 402 403 if (wait) 404 waitForNotification(notifyPort); 405 } 406 while (wait); 407 408 IOObjectRelease(controller); 409 } 410 411 IONetworkClose(con); 412 IOObjectRelease(netif); 413 } 414 415 exit(0); 416 return 0; 417} 418