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 statistics for an Ethernet interface. 25 * 26 * To build: 27 * cc enetstat.c -o enetstat -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// NetworkInterface property table keys. 44// 45#define IF_NAME_KEY "BSD Name" 46 47//--------------------------------------------------------------------------- 48// Display generic network statistics. 49 50static IOReturn displayGenericStats(io_connect_t con) 51{ 52 IOReturn kr; 53 IONetworkStats netStat; 54 UInt32 size; 55 IONDHandle dataHandle; 56 57 size = sizeof(netStat); 58 59 kr = IONetworkGetDataHandle(con, kIONetworkStatsKey, &dataHandle); 60 if (kr != kIOReturnSuccess) 61 { 62 printf("IONetworkGetDataHandle error %x\n", kr); 63 return kr; 64 } 65 66 kr = IONetworkReadData(con, 67 dataHandle, 68 (UInt8 *) &netStat, 69 &size); 70 71 if (kr == kIOReturnSuccess) { 72 printf("TX stats\t\t\tRX stats\n"); 73 printf("----------------------------------------------------------\n"); 74 printf("Packets : %-7ld\tPackets : %-7ld\n", 75 netStat.outputPackets, netStat.inputPackets); 76 printf("Errors : %-7ld\tErrors : %-7ld\n", 77 netStat.outputErrors, netStat.inputErrors); 78 printf("Collisions : %-7ld\n", 79 netStat.collisions); 80 } 81 else { 82 printf("IONetworkDataRead error %x\n", kr); 83 } 84 85 return kr; 86} 87 88//--------------------------------------------------------------------------- 89// Display Ethernet statistics. 90 91static IOReturn displayEthernetStats(io_connect_t con) 92{ 93 IOReturn kr; 94 IOEthernetStats etherStat; 95 IODot3StatsEntry * dot3StatsEntry = ðerStat.dot3StatsEntry; 96 IODot3RxExtraEntry * dot3RxExtraEntry = ðerStat.dot3RxExtraEntry; 97 IODot3TxExtraEntry * dot3TxExtraEntry = ðerStat.dot3TxExtraEntry; 98// IODot3CollEntry * col = ðerStat.dot3CollEntry; 99 UInt32 size; 100 IONDHandle dataHandle; 101 102 size = sizeof(etherStat); 103 104 kr = IONetworkGetDataHandle(con, kIOEthernetStatsKey, &dataHandle); 105 if (kr != kIOReturnSuccess) 106 { 107 printf("IONetworkGetDataHandle error %x\n", kr); 108 return kr; 109 } 110 111 kr = IONetworkReadData(con, 112 dataHandle, 113 (UInt8 *) ðerStat, 114 &size); 115 116 if (kr == kIOReturnSuccess) { 117 printf("\n"); 118 119 printf("TX stats\t\t\tRX stats\n"); 120 printf("----------------------------------------------------------\n"); 121 122 printf("Interrupts : %-7ld\tInterrupts : %-7ld\n", 123 dot3TxExtraEntry->interrupts, 124 dot3RxExtraEntry->interrupts); 125 126 printf("Single coll. : %-7ld\tAlignment errors : %-7ld\n", 127 dot3StatsEntry->singleCollisionFrames, 128 dot3StatsEntry->alignmentErrors); 129 130 printf("Multi coll. : %-7ld\tFCS errors : %-7ld\n", 131 dot3StatsEntry->multipleCollisionFrames, 132 dot3StatsEntry->fcsErrors); 133 134 printf("Late coll. : %-7ld\tToo Longs : %-7ld\n", 135 dot3StatsEntry->lateCollisions, 136 dot3StatsEntry->frameTooLongs); 137 138 printf("Excessive coll. : %-7ld\tToo shorts : %-7ld\n", 139 dot3StatsEntry->excessiveCollisions, 140 dot3RxExtraEntry->frameTooShorts); 141 142 printf("MAC errors : %-7ld\tMAC errors : %-7ld\n", 143 dot3StatsEntry->internalMacTransmitErrors, 144 dot3StatsEntry->internalMacReceiveErrors); 145 146 printf("PHY errors : %-7ld\tPHY errors : %-7ld\n", 147 dot3TxExtraEntry->phyErrors, 148 dot3RxExtraEntry->phyErrors); 149 150 printf("Deferred : %-7ld\tWatchdog timeouts: %-7ld\n", 151 dot3StatsEntry->deferredTransmissions, 152 dot3RxExtraEntry->watchdogTimeouts); 153 154 printf("Carrier errors : %-7ld\tCollisions : %-7ld\n", 155 dot3StatsEntry->carrierSenseErrors, 156 dot3RxExtraEntry->collisionErrors); 157 158 printf("Underruns : %-7ld\tOverruns : %-7ld\n", 159 dot3TxExtraEntry->underruns, 160 dot3RxExtraEntry->overruns); 161 162 printf("Resets : %-7ld\tResets : %-7ld\n", 163 dot3TxExtraEntry->resets, 164 dot3RxExtraEntry->resets); 165 166 printf("Resource errors : %-7ld\tResource errors : %-7ld\n", 167 dot3TxExtraEntry->resourceErrors, 168 dot3RxExtraEntry->resourceErrors); 169 170 printf("Timeouts : %-7ld\tTimeouts : %-7ld\n", 171 dot3TxExtraEntry->timeouts, 172 dot3RxExtraEntry->timeouts); 173 174 printf("SQE errors : %-7ld\tMissed frames : %-7ld\n", 175 dot3StatsEntry->sqeTestErrors, 176 dot3StatsEntry->sqeTestErrors); 177 178 printf("Jabbers : %-7ld\n", 179 dot3TxExtraEntry->jabbers); 180 } 181 else { 182 printf("IONetworkDataRead error %x\n", kr); 183 } 184 185 return kr; 186} 187 188//--------------------------------------------------------------------------- 189// Display output queue statistics. 190 191static IOReturn displayOutputQueueStats(io_connect_t con) 192{ 193 IOReturn kr; 194 IOOutputQueueStats queueStat; 195 UInt32 size; 196 IONDHandle dataHandle; 197 198 size = sizeof(queueStat); 199 200 kr = IONetworkGetDataHandle(con, kIOOutputQueueStatsKey, &dataHandle); 201 if (kr != kIOReturnSuccess) 202 { 203 printf("IONetworkGetDataHandle error %x\n", kr); 204 return kr; 205 } 206 207 kr = IONetworkReadData(con, 208 dataHandle, 209 (UInt8 *) &queueStat, 210 &size); 211 212 if (kr == kIOReturnSuccess) { 213 printf("\n"); 214 215 printf("Output queue stats\n"); 216 printf("----------------------------------------------------------\n"); 217 printf("Capacity : %-7ld\n", 218 queueStat.capacity); 219 printf("Current Size : %-7ld\n", 220 queueStat.size); 221 printf("Peak Size : %-7ld\n", 222 queueStat.peakSize); 223 printf("Dropped packets : %-7ld\n", 224 queueStat.dropCount); 225 printf("Output packets : %-7ld\n", 226 queueStat.outputCount); 227 printf("Stall count : %-7ld\n", 228 queueStat.stallCount); 229 } 230 else { 231 printf("IONetworkDataRead error %x\n", kr); 232 } 233 234#if 0 // Test IONetworkGetDataCapacity 235 { 236 UInt32 capacity; 237 kr = IONetworkGetDataCapacity(con, dataHandle, &capacity); 238 if (kr != kIOReturnSuccess) { 239 printf("IONetworkGetDataCapacity error %x size %ld\n", kr, size); 240 } 241 else { 242 printf("Queue data capacity: %ld\n", capacity); 243 } 244 } 245#endif 246 247#if 0 // Test IONetworkResetData 248 kr = IONetworkResetData(con, dataHandle); 249 if (kr != kIOReturnSuccess) 250 printf("IONetworkResetData error %x\n", kr); 251#endif 252 253#if 0 254 { 255 char wrBuf[44] = {0x15, 0x14, 0x15, 0xff, 0x15, 0x14, 0x15, 0xff, 256 0x15, 0x14, 0x15, 0xff, 0x15, 0x14, 0x15, 0xff, 257 0x15, 0x14, 0x15, 0xff, 0x15, 0x14, 0x15, 0xff, 258 0x15, 0x14, 0x15, 0xff, 0x15, 0x14, 0x15, 0xff}; 259 260 kr = IONetworkWriteData(con, dataHandle, wrBuf, sizeof(wrBuf)); 261 if (kr == kIOReturnSuccess) { 262 printf("IONetworkWriteData OK\n"); 263 } 264 else { 265 printf("IONetworkWriteData error %x\n", kr); 266 } 267 } 268#endif 269 270 return kr; 271} 272 273//--------------------------------------------------------------------------- 274// Utilities functions to print CFNumber and CFString. 275 276static void CFStringShow(CFStringRef object) 277{ 278 const char * c = CFStringGetCStringPtr(object, 279 kCFStringEncodingMacRoman); 280 281 if (c) 282 printf(c); 283 else 284 { 285 CFIndex bufferSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(object), 286 kCFStringEncodingMacRoman) + sizeof('\0'); 287 char * buffer = (char *) malloc(bufferSize); 288 289 if (buffer) 290 { 291 if ( CFStringGetCString( 292 /* string */ object, 293 /* buffer */ buffer, 294 /* bufferSize */ bufferSize, 295 /* encoding */ kCFStringEncodingMacRoman) ) 296 printf(buffer); 297 298 free(buffer); 299 } 300 } 301} 302 303//--------------------------------------------------------------------------- 304// Returns non zero if the property table of the object has a "BSD Name" 305// string entry, and the string matches the provided string argument. 306 307static int matchBSDNameProperty(io_object_t obj, CFStringRef ifname) 308{ 309 int match = 0; 310 kern_return_t kr; 311 CFMutableDictionaryRef properties; 312 CFStringRef string; 313 314 kr = IORegistryEntryCreateCFProperties(obj, 315 &properties, 316 kCFAllocatorDefault, 317 kNilOptions); 318 319 if ((kr != KERN_SUCCESS) || !properties) { 320 printf("IORegistryEntryCreateCFProperties error %x\n", kr); 321 return false; 322 } 323 324 // Look up the interface "BSD Name" property and perform matching. 325 // 326 string = (CFStringRef) CFDictionaryGetValue(properties, 327 CFSTR(IF_NAME_KEY)); 328 if (string) { 329 if (CFStringCompare(ifname, string, kNilOptions) == kCFCompareEqualTo) 330 { 331 printf("[ "); 332 CFStringShow(string); 333 printf(" ]\n"); 334 match = 1; 335 } 336 } 337 338 CFRelease(properties); 339 340 return match; 341} 342 343//--------------------------------------------------------------------------- 344// Searches the IOKit registry and return an interface object with the 345// given BSD interface name, i.e. en0. 346 347io_object_t getInterfaceWithBSDName(mach_port_t masterPort, CFStringRef ifname) 348{ 349 kern_return_t kr; 350 io_iterator_t ite; 351 io_object_t obj = 0; 352 const char * className = "IONetworkInterface"; 353 354 kr = IORegistryCreateIterator(masterPort, 355 kIOServicePlane, 356 true, /* recursive */ 357 &ite); 358 359 if (kr != kIOReturnSuccess) { 360 printf("Error: IORegistryCreateIterator %x\n", kr); 361 return 0; 362 } 363 364 while ((obj = IOIteratorNext(ite))) { 365 if (IOObjectConformsTo(obj, (char *) className) && 366 (matchBSDNameProperty(obj, ifname))) 367 break; 368 369 IOObjectRelease(obj); 370 obj = 0; 371 } 372 373 IORegistryDisposeEnumerator(ite); 374 375 return obj; 376} 377 378//--------------------------------------------------------------------------- 379// Display usage and quit. 380 381static void usage(void) 382{ 383 /* 384 * Print usage and exit. 385 */ 386 printf("usage: enetstat [-i ifname]\n"); 387 printf("option flags:\n"); 388 printf(" -i ifname : specify interface. Default is en0.\n"); 389 printf(" -n : Display generic network statistics.\n"); 390 printf(" -e : Display Ethernet statistics.\n"); 391 printf(" -q : Display output queue statistics.\n"); 392 printf("\n"); 393 exit(1); 394} 395 396//--------------------------------------------------------------------------- 397// Main function. 398 399int 400main(int argc, char ** argv) 401{ 402 mach_port_t masterPort; 403 kern_return_t kr; 404 io_object_t netif; 405 io_connect_t con; 406 int ch; 407 const char * name = "en0"; 408 CFStringRef ifname; 409 int showGenericStats = 0; 410 int showEthernetStats = 0; 411 int showQueueStats = 0; 412 413 while ((ch = getopt(argc, argv, ":i:nqe")) != -1) 414 { 415 switch ((char) ch) 416 { 417 case 'i': /* specify interface */ 418 if (!optarg) 419 usage(); 420 name = optarg; 421 break; 422 423 case 'n': 424 showGenericStats = 1; 425 break; 426 427 case 'q': 428 showQueueStats = 1; 429 break; 430 431 case 'e': 432 showEthernetStats = 1; 433 break; 434 435 default: 436 usage(); 437 } 438 } 439 440 if (name == 0) 441 usage(); 442 443 if ((showGenericStats || showEthernetStats || showQueueStats) == false) 444 showGenericStats = 1; 445 446 // Get master device port 447 // 448 kr = IOMasterPort(bootstrap_port, &masterPort); 449 if (kr != KERN_SUCCESS) 450 printf("IOMasterPort() failed: %x\n", kr); 451 452 ifname = CFStringCreateWithCString(kCFAllocatorDefault, 453 name, 454 kCFStringEncodingMacRoman); 455 456 netif = getInterfaceWithBSDName(masterPort, ifname); 457 458 if (netif) 459 { 460 kr = IONetworkOpen(netif, &con); 461 462 if (kr == kIOReturnSuccess) 463 { 464 if (showGenericStats) displayGenericStats(con); 465 if (showEthernetStats) displayEthernetStats(con); 466 if (showQueueStats) displayOutputQueueStats(con); 467 } 468 469 IONetworkClose(con); 470 471 IOObjectRelease(netif); 472 } 473 474 exit(0); 475 return 0; 476} 477