1/* 2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23#include <IOKit/assert.h> 24#include <IOKit/network/IONetworkInterface.h> 25#include <IOKit/network/IONetworkData.h> 26#include "IONetworkUserClient.h" 27#include "IONetworkDebug.h" 28 29//------------------------------------------------------------------------ 30 31#define super IOUserClient 32OSDefineMetaClassAndStructors( IONetworkUserClient, IOUserClient ) 33 34//--------------------------------------------------------------------------- 35// Factory method that performs allocation and initialization 36// of an IONetworkUserClient instance. 37 38IONetworkUserClient * IONetworkUserClient::withTask(task_t owningTask) 39{ 40 IONetworkUserClient * me; 41 42 me = new IONetworkUserClient; 43 if (me) 44 { 45 if (!me->init()) 46 { 47 me->release(); 48 return 0; 49 } 50 me->_task = owningTask; 51 } 52 return me; 53} 54 55//--------------------------------------------------------------------------- 56// Start the IONetworkUserClient. 57 58bool IONetworkUserClient::start(IOService * provider) 59{ 60 _owner = OSDynamicCast(IONetworkInterface, provider); 61 assert(_owner); 62 63 _handleArray = OSArray::withCapacity(4); 64 if (!_handleArray) 65 return false; 66 67 _handleLock = IOLockAlloc(); 68 if (!_handleLock) 69 return false; 70 71 if (!super::start(_owner)) 72 return false; 73 74 if (!_owner->open(this)) 75 return false; 76 77 return true; 78} 79 80//--------------------------------------------------------------------------- 81// Free the IONetworkUserClient instance. 82 83void IONetworkUserClient::free(void) 84{ 85 if (_handleArray) 86 { 87 _handleArray->release(); 88 _handleArray = 0; 89 } 90 if (_handleLock) 91 { 92 IOLockFree(_handleLock); 93 _handleLock = 0; 94 } 95 super::free(); 96} 97 98//--------------------------------------------------------------------------- 99// Handle a client close. Close and detach from our owner (provider). 100 101IOReturn IONetworkUserClient::clientClose(void) 102{ 103 if (_owner) { 104 _owner->close(this); 105 detach(_owner); 106 } 107 108 return kIOReturnSuccess; 109} 110 111//--------------------------------------------------------------------------- 112// Handle client death. Close and detach from our owner (provider). 113 114IOReturn IONetworkUserClient::clientDied(void) 115{ 116 return clientClose(); 117} 118 119//--------------------------------------------------------------------------- 120 121IOReturn IONetworkUserClient::externalMethod( 122 uint32_t selector, IOExternalMethodArguments * arguments, 123 IOExternalMethodDispatch * dispatch, OSObject * target, 124 void * reference ) 125{ 126 IOReturn ret = kIOReturnBadArgument; 127 128 if (!arguments) 129 return kIOReturnBadArgument; 130 131 switch (selector) 132 { 133 case kIONUCResetNetworkDataIndex: 134 if (arguments->scalarInputCount == 1) 135 ret = resetNetworkData( 136 (uint32_t) arguments->scalarInput[0]); 137 break; 138 139 case kIONUCWriteNetworkDataIndex: 140 if ((arguments->scalarInputCount == 1) && 141 (arguments->structureInputSize > 0)) 142 ret = writeNetworkData( 143 (uint32_t) arguments->scalarInput[0], 144 (void *) arguments->structureInput, 145 arguments->structureInputSize); 146 break; 147 148 case kIONUCReadNetworkDataIndex: 149 if ((arguments->scalarInputCount == 1) && 150 (arguments->structureOutputSize > 0)) 151 ret = readNetworkData( 152 (uint32_t) arguments->scalarInput[0], 153 arguments->structureOutput, 154 &arguments->structureOutputSize); 155 break; 156 157 case kIONUCGetNetworkDataCapacityIndex: 158 if ((arguments->scalarInputCount == 1) && 159 (arguments->scalarOutputCount == 1)) 160 ret = getNetworkDataCapacity( 161 (uint32_t) arguments->scalarInput[0], 162 &arguments->scalarOutput[0]); 163 break; 164 165 case kIONUCGetNetworkDataHandleIndex: 166 ret = getNetworkDataHandle( 167 (const char *) arguments->structureInput, 168 (uint32_t *) arguments->structureOutput, 169 arguments->structureInputSize, 170 &arguments->structureOutputSize); 171 break; 172 173 } 174 175 return ret; 176} 177 178//--------------------------------------------------------------------------- 179// Fill the data buffer in an IONetworkData object with zeroes. 180 181IOReturn IONetworkUserClient::resetNetworkData(uint32_t dataHandle) 182{ 183 IONetworkData * data; 184 const OSSymbol * key; 185 IOReturn ret; 186 187 IOLockLock(_handleLock); 188 key = (const OSSymbol *) _handleArray->getObject(dataHandle); 189 IOLockUnlock(_handleLock); 190 191 if (!key) 192 return kIOReturnBadArgument; 193 194 data = _owner->getNetworkData(key); 195 ret = data ? data->reset() : kIOReturnBadArgument; 196 197 return ret; 198} 199 200//--------------------------------------------------------------------------- 201// Write to the data buffer in an IONetworkData object with data from a 202// source buffer provided by the caller. 203 204IOReturn 205IONetworkUserClient::writeNetworkData(uint32_t dataHandle, 206 void * srcBuffer, 207 uint32_t srcBufferSize) 208{ 209 IONetworkData * data; 210 const OSSymbol * key; 211 IOReturn ret; 212 213 IOLockLock(_handleLock); 214 key = (const OSSymbol *) _handleArray->getObject(dataHandle); 215 IOLockUnlock(_handleLock); 216 217 if (!key || !srcBuffer || !srcBufferSize) 218 return kIOReturnBadArgument; 219 220 data = _owner->getNetworkData(key); 221 ret = data ? data->write(srcBuffer, srcBufferSize) : kIOReturnBadArgument; 222 223 return ret; 224} 225 226//--------------------------------------------------------------------------- 227// Read the data buffer in an IONetworkData object and copy 228// this data to a destination buffer provided by the caller. 229 230IOReturn 231IONetworkUserClient::readNetworkData(uint32_t dataHandle, 232 void * dstBuffer, 233 uint32_t * dstBufferSize) 234{ 235 IONetworkData * data; 236 const OSSymbol * key; 237 IOReturn ret; 238 239 IOLockLock(_handleLock); 240 key = (const OSSymbol *) _handleArray->getObject(dataHandle); 241 IOLockUnlock(_handleLock); 242 243 if (!key || !dstBuffer || !dstBufferSize) 244 return kIOReturnBadArgument; 245 246 data = _owner->getNetworkData(key); 247 ret = data ? data->read(dstBuffer, (UInt32 *) dstBufferSize) : 248 kIOReturnBadArgument; 249 250 return ret; 251} 252 253//--------------------------------------------------------------------------- 254// Get the capacity of an IONetworkData object. 255 256IOReturn 257IONetworkUserClient::getNetworkDataCapacity(uint32_t dataHandle, 258 uint64_t * capacity) 259{ 260 const OSSymbol * key; 261 IONetworkData * data; 262 IOReturn ret = kIOReturnBadArgument; 263 264 IOLockLock(_handleLock); 265 key = (const OSSymbol *) _handleArray->getObject(dataHandle); 266 IOLockUnlock(_handleLock); 267 268 if (key) 269 { 270 data = _owner->getNetworkData(key); 271 if (data) { 272 *capacity = (uint64_t) data->getSize(); 273 ret = kIOReturnSuccess; 274 } 275 } 276 277 return ret; 278} 279 280//--------------------------------------------------------------------------- 281// Called to obtain a handle that maps to an IONetworkData object. 282// This handle can be later passed to other methods in this class 283// to refer to the same object. 284 285IOReturn 286IONetworkUserClient::getNetworkDataHandle(const char * name, 287 uint32_t * handle, 288 uint32_t nameSize, 289 uint32_t * handleSizeP) 290{ 291 IOReturn ret = kIOReturnBadArgument; 292 const OSSymbol * key; 293 int index; 294 295 if (!name || !nameSize || (name[nameSize - 1] != '\0') || 296 (*handleSizeP != sizeof(*handle))) 297 return kIOReturnBadArgument; 298 299 key = OSSymbol::withCStringNoCopy(name); 300 if (!key) 301 return kIOReturnNoMemory; 302 303 if (_owner->getNetworkData(key)) 304 { 305 IOLockLock(_handleLock); 306 index = _handleArray->getNextIndexOfObject(key, 0); 307 if (index < 0) 308 { 309 _handleArray->setObject(key); 310 index = _handleArray->getNextIndexOfObject(key, 0); 311 } 312 IOLockUnlock(_handleLock); 313 314 if (index >= 0) 315 { 316 *handle = index; 317 ret = kIOReturnSuccess; 318 } 319 } 320 321 if (key) 322 key->release(); 323 324 return ret; 325} 326 327//--------------------------------------------------------------------------- 328// Route setProperties() to our provider. 329 330IOReturn 331IONetworkUserClient::setProperties(OSObject * properties) 332{ 333 return _owner->setProperties(properties); 334} 335 336//--------------------------------------------------------------------------- 337// Return our provider. This is called by IOConnectGetService(). 338 339IOService * IONetworkUserClient::getService() 340{ 341 return _owner; 342} 343