1/*
2 * Copyright (c) 1999-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 * HISTORY
25 *
26 */
27
28#include <CoreFoundation/CoreFoundation.h>
29#include <IOKit/IOKitLib.h>
30#include <IOKit/IOBSD.h>
31#include <IOKit/network/IONetworkLib.h>
32#include <IOKit/network/IONetworkInterface.h>
33#include <IOKit/network/IONetworkController.h>
34#include <ctype.h>
35#include <stdlib.h>
36#include <stdio.h>
37#include <mach/mach_interface.h>
38
39//---------------------------------------------------------------------------
40// IONetworkOpen - Open a connection to an IONetworkInterface object.
41//                 An IONetworkUserClient object is created to manage
42//                 the connection.
43
44IOReturn IONetworkOpen(io_object_t obj, io_connect_t * con)
45{
46    return IOServiceOpen(obj, mach_task_self(), kIONUCType, con);
47}
48
49//---------------------------------------------------------------------------
50// IONetworkClose - Close the connection to an IONetworkInterface object.
51
52IOReturn IONetworkClose(io_connect_t con)
53{
54    return IOServiceClose(con);
55}
56
57//---------------------------------------------------------------------------
58// IONetworkWriteData - Write to the buffer of a network data object.
59
60IOReturn IONetworkWriteData(io_connect_t  con,
61                            IONDHandle    dataHandle,
62                            UInt8 *       srcBuf,
63                            UInt32        inSize)
64{
65    IOReturn  kr;
66
67    if (!srcBuf || !inSize)
68        return kIOReturnBadArgument;
69
70    uint64_t data = dataHandle;
71    kr = IOConnectCallMethod(con,   kIONUCWriteNetworkDataIndex,
72			&data,  1,		// input[], inputCount
73			srcBuf, (size_t) inSize,// inputStruct, inputStructCnt
74			NULL,   NULL,		// output scalar
75			NULL,   NULL);		// output struct
76
77    return kr;
78}
79
80//---------------------------------------------------------------------------
81// IONetworkReadData - Read the buffer of a network data object.
82
83IOReturn IONetworkReadData(io_connect_t con,
84                           IONDHandle   dataHandle,
85                           UInt8 *      destBuf,
86                           UInt32 *     inOutSizeP)
87{
88    IOReturn               kr;
89
90    if (!destBuf || !inOutSizeP)
91        return kIOReturnBadArgument;
92
93    uint64_t data = dataHandle;
94    size_t size = *inOutSizeP;
95    kr = IOConnectCallMethod(con,   kIONUCReadNetworkDataIndex,
96			&data,  1,	// input[], inputCount
97			NULL,   0,	// inputStruct, inputStructCnt
98			NULL,   NULL,	// output scalar
99			destBuf, &size);// output struct
100    *inOutSizeP = (UInt32) size;
101
102    return kr;
103}
104
105//---------------------------------------------------------------------------
106// IONetworkResetData - Fill the buffer of a network data object with zeroes.
107
108IOReturn IONetworkResetData(io_connect_t con, IONDHandle dataHandle)
109{
110    IOReturn               kr;
111
112    uint64_t data = dataHandle;
113    kr = IOConnectCallScalarMethod(con,   kIONUCResetNetworkDataIndex,
114			       &data, 1,	// input[], inputCount
115			       NULL,  NULL);
116
117    return kr;
118}
119
120//---------------------------------------------------------------------------
121// IONetworkGetDataCapacity - Get the capacity (in bytes) of a network data
122//                            object.
123
124IOReturn IONetworkGetDataCapacity(io_connect_t con,
125                                  IONDHandle   dataHandle,
126                                  UInt32 *     capacityP)
127{
128    if (!capacityP)
129        return kIOReturnBadArgument;
130
131    uint64_t data = dataHandle;
132    uint64_t capacity = *capacityP;
133    uint32_t one = 1;
134    IOReturn kr = IOConnectCallScalarMethod(con,
135	    kIONUCGetNetworkDataCapacityIndex, &data, 1, &capacity, &one);
136    *capacityP = (UInt32) capacity;	// XXX paul?: update for 64 bit?
137    return kr;
138}
139
140//---------------------------------------------------------------------------
141// IONetworkGetDataHandle - Get the handle of a network data object with
142//                          the given name.
143
144IOReturn IONetworkGetDataHandle(io_connect_t con,
145                                const char * dataName,
146                                IONDHandle * dataHandleP)
147{
148    if (!dataName || !dataHandleP)
149        return kIOReturnBadArgument;
150
151    size_t handleSize = sizeof(*dataHandleP);
152    return IOConnectCallStructMethod(con,     kIONUCGetNetworkDataHandleIndex,
153				 dataName,    strlen(dataName) + 1,
154				 dataHandleP, &handleSize);
155}
156
157//---------------------------------------------------------------------------
158// Utility functions to manipulate nested dictionaries.
159
160#define kIONetworkInterfaceProperties   "IONetworkInterfaceProperties"
161#define kIORequiredPacketFilters        "IORequiredPacketFilters"
162
163static void
164GetDictionaryValueUsingKeysApplier( const void * value,
165                                    void *       context )
166{
167    CFDictionaryRef * dict = (CFDictionaryRef *) context;
168
169    if ( ( *dict ) &&
170         ( CFGetTypeID(*dict) == CFDictionaryGetTypeID() ) )
171        *dict = CFDictionaryGetValue( *dict, value );
172    else
173        *dict = 0;
174}
175
176static CFTypeRef
177GetDictionaryValueUsingKeys( CFDictionaryRef dict,
178                             CFArrayRef      keysArray,
179                             CFTypeID        typeID )
180{
181	CFArrayApplyFunction( keysArray,
182                          CFRangeMake(0, CFArrayGetCount(keysArray)),
183                          GetDictionaryValueUsingKeysApplier,
184                          &dict );
185
186    if ( dict && (CFGetTypeID(dict) != typeID) ) dict = 0;
187
188	return dict;
189}
190
191static CFDictionaryRef
192CreateNestedDictionariesUsingKeys( CFArrayRef keysArray,
193                                   CFTypeRef  value )
194{
195    CFDictionaryRef dict = 0;
196    CFDictionaryRef prevDict;
197    CFIndex         index, count;
198    CFStringRef     keys[1];
199    CFTypeRef       values[1];
200
201	count = CFArrayGetCount(keysArray);
202    for ( index = count - 1;
203          index >= 0;
204          index-- )
205    {
206        prevDict = dict;
207
208        keys[0]   = CFArrayGetValueAtIndex( keysArray, index );
209        values[0] = ( prevDict ) ? prevDict : value;
210
211        dict = CFDictionaryCreate( NULL,
212                                   (void *) keys,
213                                   (void *) values,
214                                   1,
215                                   &kCFCopyStringDictionaryKeyCallBacks,
216                                   &kCFTypeDictionaryValueCallBacks );
217
218        if ( prevDict )  CFRelease( prevDict );
219        if ( dict == 0 ) break;
220    }
221
222    return dict;
223}
224
225//---------------------------------------------------------------------------
226// IONetworkGetPacketFiltersMask
227
228IOReturn
229IONetworkGetPacketFiltersMask( io_connect_t    connect,
230                               const io_name_t filterGroup,
231                               UInt32 *        filtersMask,
232                               IOOptionBits    options )
233{
234	IOReturn               kr;
235    io_service_t           service   = 0;
236    CFMutableDictionaryRef dict      = 0;
237    CFArrayRef             keysArray = 0;
238    CFStringRef            group     = 0;
239    CFStringRef            keys[2];
240    CFTypeRef              value;
241
242    do {
243        *filtersMask = 0;
244
245        // Locate our service provider.
246
247        kr = IOConnectGetService( connect, &service );
248        if ( kr != kIOReturnSuccess ) break;
249
250        if ( kIONetworkSupportedPacketFilters & options )
251        {
252            io_service_t parentService;
253            kr = IORegistryEntryGetParentEntry( service, kIOServicePlane,
254                                                &parentService );
255            if ( kr != kIOReturnSuccess ) break;
256            IOObjectRelease( service );
257            service = parentService;
258        }
259
260        // Fetch properties from registry.
261
262        kr = IORegistryEntryCreateCFProperties( service,
263                                                &dict,
264                                                kCFAllocatorDefault,
265                                                kNilOptions );
266        if ( kr != kIOReturnSuccess ) break;
267
268        group = CFStringCreateWithCString( kCFAllocatorDefault, filterGroup,
269					                       CFStringGetSystemEncoding() );
270        if ( group == 0 )
271        {
272            kr = kIOReturnNoMemory;
273            break;
274        }
275
276        // Create an array of keys to the value.
277
278        keys[0] = (kIONetworkSupportedPacketFilters & options) ?
279                         CFSTR( kIOPacketFilters ) :
280                         CFSTR( kIORequiredPacketFilters );
281        keys[1] = group;
282
283        keysArray = CFArrayCreate( NULL, (void *)keys, 2, &kCFTypeArrayCallBacks );
284        if ( keysArray == 0 )
285        {
286            kr = kIOReturnNoMemory;
287            break;
288        }
289
290        value = GetDictionaryValueUsingKeys( dict, keysArray, CFNumberGetTypeID() );
291        if ( value == 0 )
292        {
293            kr = kIOReturnNotFound;
294            break;
295        }
296
297        CFNumberGetValue( (CFNumberRef)value, kCFNumberSInt32Type, filtersMask );
298    }
299    while ( 0 );
300
301    if ( dict )      CFRelease( dict );
302    if ( group )     CFRelease( group );
303	if ( keysArray ) CFRelease( keysArray );
304    if ( service )   IOObjectRelease( service );
305
306    return kr;
307}
308
309//---------------------------------------------------------------------------
310// IONetworkSetPacketFiltersMask
311
312IOReturn
313IONetworkSetPacketFiltersMask( io_connect_t    connect,
314                               const io_name_t filterGroup,
315                               UInt32          filtersMask,
316                               IOOptionBits options __unused )
317{
318	IOReturn        kr = kIOReturnNoMemory;
319    CFStringRef     keys[3];
320    CFArrayRef      keysArray = 0;
321    CFStringRef     group     = 0;
322    CFNumberRef     num       = 0;
323    CFDictionaryRef dict      = 0;
324
325    do {
326        num = CFNumberCreate( kCFAllocatorDefault,
327                              kCFNumberSInt32Type,
328                              &filtersMask );
329        if ( num == 0 ) break;
330
331        group = CFStringCreateWithCString( kCFAllocatorDefault, filterGroup,
332					                       CFStringGetSystemEncoding() );
333        if ( group == 0 ) break;
334
335        keys[0] = CFSTR( kIONetworkInterfaceProperties );
336        keys[1] = CFSTR( kIORequiredPacketFilters );
337        keys[2] = group;
338
339        keysArray = CFArrayCreate( NULL, (void *)keys, 3, &kCFTypeArrayCallBacks );
340        if ( keysArray == 0 ) break;
341
342        dict = CreateNestedDictionariesUsingKeys( keysArray, num );
343        if ( dict == 0 ) break;
344
345        kr = IOConnectSetCFProperties( connect, dict );
346    }
347    while ( 0 );
348
349	if ( num )       CFRelease( num );
350    if ( group )     CFRelease( group );
351    if ( keysArray ) CFRelease( keysArray );
352    if ( dict )      CFRelease( dict );
353
354    return kr;
355}
356