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 = &etherStat.dot3StatsEntry;
96    IODot3RxExtraEntry *    dot3RxExtraEntry = &etherStat.dot3RxExtraEntry;
97    IODot3TxExtraEntry *    dot3TxExtraEntry = &etherStat.dot3TxExtraEntry;
98//  IODot3CollEntry *       col = &etherStat.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 *) &etherStat,
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