]> git.saurik.com Git - apple/xnu.git/blob - iokit/Families/IONetworking/IONetworkData.cpp
821f02b609bc25a7cbdcdcc570c7e54837efd979
[apple/xnu.git] / iokit / Families / IONetworking / IONetworkData.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, 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 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
24 *
25 * IONetworkData.cpp
26 */
27
28 #include <IOKit/assert.h>
29 #include <IOKit/IOLib.h>
30 #include <libkern/c++/OSDictionary.h>
31 #include <libkern/c++/OSNumber.h>
32 #include <libkern/c++/OSData.h>
33 #include <IOKit/network/IONetworkData.h>
34
35 #define super OSObject
36 OSDefineMetaClassAndStructors( IONetworkData, OSObject )
37 OSMetaClassDefineReservedUnused( IONetworkData, 0);
38 OSMetaClassDefineReservedUnused( IONetworkData, 1);
39 OSMetaClassDefineReservedUnused( IONetworkData, 2);
40 OSMetaClassDefineReservedUnused( IONetworkData, 3);
41
42 #define TAP_IS_VALID (_tapAction)
43
44 // All access method are serialized by a single global lock,
45 // shared among all IONetworkData instances.
46 //
47 static IOLock * gIONDLock = 0;
48 #define LOCK IOTakeLock(gIONDLock)
49 #define UNLOCK IOUnlock(gIONDLock)
50
51 static const OSSymbol * gIONDDataKey;
52 static const OSSymbol * gIONDAccessKey;
53 static const OSSymbol * gIONDSizeKey;
54
55 //---------------------------------------------------------------------------
56 // IONetworkData class initializer.
57
58 void IONetworkData::initialize()
59 {
60 // Allocates the global data lock.
61 //
62 gIONDLock = IOLockAlloc();
63 assert(gIONDLock);
64 IOLockInitWithState(gIONDLock, kIOLockStateUnlocked);
65
66 gIONDDataKey = OSSymbol::withCStringNoCopy( kIONetworkDataBytes );
67 gIONDAccessKey = OSSymbol::withCStringNoCopy( kIONetworkDataAccessTypes );
68 gIONDSizeKey = OSSymbol::withCStringNoCopy( kIONetworkDataSize );
69
70 assert(gIONDDataKey && gIONDAccessKey && gIONDSizeKey);
71 }
72
73 //---------------------------------------------------------------------------
74 // Initialize an IONetworkData instance.
75
76 bool
77 IONetworkData::init(const char * name,
78 UInt32 bufferType,
79 UInt32 bufferSize,
80 void * extBuffer = 0,
81 UInt32 accessTypes = kIONetworkDataBasicAccessTypes,
82 void * target = 0,
83 Action action = 0,
84 void * param = 0)
85 {
86 if ((bufferType == kIONetworkDataBufferTypeInternal) ||
87 (bufferType == kIONetworkDataBufferTypeExternal))
88 {
89 _buffer = (bufferType == kIONetworkDataBufferTypeInternal) ?
90 (void *) kalloc(bufferSize) : extBuffer;
91
92 if (_buffer == 0)
93 return false;
94
95 if (bufferType == kIONetworkDataBufferTypeInternal)
96 bzero(_buffer, bufferSize);
97 }
98
99 _bufType = bufferType;
100 _access = accessTypes;
101 _tapTarget = target;
102 _tapAction = action;
103 _tapParam = param;
104 _size = bufferSize;
105
106 // Generate a key for this object based on its assigned name.
107 //
108 if ((_key = OSSymbol::withCString(name)) == 0)
109 return false;
110
111 return true;
112 }
113
114 //---------------------------------------------------------------------------
115 // Factory method that will construct and initialize an IONetworkData
116 // instance with an internal buffer.
117
118 IONetworkData *
119 IONetworkData::withInternalBuffer(
120 const char * name,
121 UInt32 bufferSize,
122 UInt32 accessTypes = kIONetworkDataBasicAccessTypes,
123 void * target = 0,
124 Action action = 0,
125 void * param = 0)
126 {
127 IONetworkData * aData = new IONetworkData;
128
129 if (aData && !aData->init(name,
130 kIONetworkDataBufferTypeInternal,
131 bufferSize,
132 0,
133 accessTypes,
134 target,
135 action,
136 param))
137 {
138 aData->release();
139 aData = 0;
140 }
141 return aData;
142 }
143
144 //---------------------------------------------------------------------------
145 // Factory method that will construct and initialize an IONetworkData
146 // instance with an external buffer.
147
148 IONetworkData *
149 IONetworkData::withExternalBuffer(
150 const char * name,
151 UInt32 bufferSize,
152 void * buffer,
153 UInt32 accessTypes = kIONetworkDataBasicAccessTypes,
154 void * target = 0,
155 Action action = 0,
156 void * param = 0)
157 {
158 IONetworkData * aData = new IONetworkData;
159
160 if (aData && !aData->init(name,
161 kIONetworkDataBufferTypeExternal,
162 bufferSize,
163 buffer,
164 accessTypes,
165 target,
166 action,
167 param))
168 {
169 aData->release();
170 aData = 0;
171 }
172 return aData;
173 }
174
175 //---------------------------------------------------------------------------
176 // Factory method that will construct and initialize an IONetworkData
177 // instance with no data buffer. The notification handler must intervene
178 // when the IONetworkData is accessed.
179
180 IONetworkData *
181 IONetworkData::withNoBuffer(const char * name,
182 UInt32 bufferSize,
183 UInt32 accessTypes,
184 void * target,
185 Action action,
186 void * param = 0)
187 {
188 IONetworkData * aData = new IONetworkData;
189
190 if (aData && !aData->init(name,
191 kIONetworkDataBufferTypeNone,
192 bufferSize,
193 0,
194 accessTypes,
195 target,
196 action,
197 param))
198 {
199 aData->release();
200 aData = 0;
201 }
202 return aData;
203 }
204
205 //---------------------------------------------------------------------------
206 // Free the IONetworkData instance.
207
208 void IONetworkData::free()
209 {
210 if (_key)
211 _key->release();
212
213 if (_buffer && (_bufType == kIONetworkDataBufferTypeInternal))
214 kfree((vm_offset_t) _buffer, _size);
215
216 super::free();
217 }
218
219 //---------------------------------------------------------------------------
220 // Return the type of buffer managed by this instance.
221 // See IONetworkDataBufferType enum definition
222
223 UInt32 IONetworkData::getBufferType() const
224 {
225 return _bufType;
226 }
227
228 //---------------------------------------------------------------------------
229 // Change the supported access types.
230
231 #define kIONetworkDataImmutableAccessTypes 0
232
233 void IONetworkData::setAccessTypes(UInt32 types)
234 {
235 LOCK;
236 _access = (_access & kIONetworkDataImmutableAccessTypes) |
237 (types & ~kIONetworkDataImmutableAccessTypes);
238 UNLOCK;
239 }
240
241 //---------------------------------------------------------------------------
242 // Register a target/action to handle access notification.
243
244 void IONetworkData::setNotificationTarget(void * target,
245 Action action,
246 void * param)
247 {
248 LOCK;
249 _tapTarget = target;
250 _tapAction = action;
251 _tapParam = param;
252 UNLOCK;
253 }
254
255 //---------------------------------------------------------------------------
256 // Return the supported access types.
257
258 UInt32 IONetworkData::getAccessTypes() const
259 {
260 return _access;
261 }
262
263 //---------------------------------------------------------------------------
264 // Return the notification target.
265
266 void * IONetworkData::getNotificationTarget() const
267 {
268 return _tapTarget;
269 }
270
271 //---------------------------------------------------------------------------
272 // Return the notification action.
273
274 IONetworkData::Action IONetworkData::getNotificationAction() const
275 {
276 return _tapAction;
277 }
278
279 //---------------------------------------------------------------------------
280 // Return the notification parameter.
281
282 void * IONetworkData::getNotificationParameter() const
283 {
284 return _tapParam;
285 }
286
287 //---------------------------------------------------------------------------
288 // Get an OSSymbol key associated with this instance.
289 // During initialization, IONetworkData will create an OSSymbol
290 // key based on its assigned name.
291 //
292 // Return an OSSymbol key generated from the assigned name.
293
294 const OSSymbol * IONetworkData::getKey() const
295 {
296 return _key;
297 }
298
299 //---------------------------------------------------------------------------
300 // Return the size of the data managed by this instance in bytes.
301
302 UInt32 IONetworkData::getSize() const
303 {
304 return _size;
305 }
306
307 //---------------------------------------------------------------------------
308 // Write to the data buffer with data from a source buffer provided
309 // by the caller.
310
311 bool IONetworkData::writeBytes(const void * srcBuffer,
312 UInt32 srcBufferSize,
313 UInt32 writeOffset)
314 {
315 if ( _buffer == 0 ) return false;
316
317 if ( srcBufferSize &&
318 (writeOffset < _size) &&
319 ((writeOffset + srcBufferSize) <= _size) )
320 {
321 bcopy(srcBuffer, (char *) _buffer + writeOffset, srcBufferSize);
322 return true;
323 }
324
325 return false;
326 }
327
328 //---------------------------------------------------------------------------
329 // Return a pointer to the data buffer.
330
331 const void * IONetworkData::getBuffer() const
332 {
333 return (_buffer) ? _buffer : 0;
334 }
335
336 //---------------------------------------------------------------------------
337 // Copy the data buffer to a destination buffer provided by the caller.
338
339 bool IONetworkData::readBytes(void * dstBuffer,
340 UInt32 * dstBufferSize,
341 UInt32 readOffset) const
342 {
343 if ( _buffer == 0 ) return false;
344
345 if ( *dstBufferSize && (readOffset < _size) )
346 {
347 UInt32 bytesCopied = min((_size - readOffset), *dstBufferSize);
348
349 bcopy((char *) _buffer + readOffset, dstBuffer, bytesCopied);
350
351 *dstBufferSize = bytesCopied;
352
353 return true;
354 }
355
356 return false;
357 }
358
359 //---------------------------------------------------------------------------
360 // Clear the entire data buffer by filling it with zeroes.
361
362 bool IONetworkData::clearBuffer()
363 {
364 if ( _buffer )
365 {
366 bzero((void *) _buffer, _size);
367 return true;
368 }
369 return false;
370 }
371
372 //---------------------------------------------------------------------------
373 // Handle a user space request to reset the data buffer.
374
375 IOReturn IONetworkData::reset()
376 {
377 IOReturn ret = kIOReturnUnsupported;
378
379 LOCK;
380
381 do {
382 // Check access.
383
384 if ( (_access & kIONetworkDataAccessTypeReset) == 0 )
385 {
386 ret = kIOReturnNotWritable;
387 break;
388 }
389
390 // Default action is to bzero the entire buffer.
391
392 if ( clearBuffer() )
393 {
394 ret = kIOReturnSuccess;
395 }
396
397 // Notify our target.
398
399 if ( TAP_IS_VALID )
400 {
401 ret = (*_tapAction)(_tapTarget, _tapParam,
402 this,
403 (UInt32) kIONetworkDataAccessTypeReset,
404 0, 0, 0);
405 }
406 }
407 while (0);
408
409 UNLOCK;
410
411 return ret;
412 }
413
414 //---------------------------------------------------------------------------
415 // Handle an external request to read from the data buffer
416 // and copy it to the destination buffer provided by the accessor.
417
418 IOReturn IONetworkData::read(void * dstBuffer,
419 UInt32 * dstBufferSize,
420 UInt32 readOffset)
421 {
422 IOReturn ret = kIOReturnUnsupported;
423
424 LOCK;
425
426 do {
427 // Check the arguments.
428
429 if ( !dstBuffer || !dstBufferSize )
430 {
431 ret = kIOReturnBadArgument;
432 break;
433 }
434
435 // Check access.
436
437 if ( (_access & kIONetworkDataAccessTypeRead) == 0 )
438 {
439 ret = kIOReturnNotReadable;
440 break;
441 }
442
443 // Notify the target before the read operation.
444 // The target can take this opportunity to update the
445 // data buffer. If the target returns an error,
446 // abort and return the error.
447
448 if ( TAP_IS_VALID )
449 {
450 ret = (*_tapAction)(_tapTarget, _tapParam,
451 this,
452 (UInt32) kIONetworkDataAccessTypeRead,
453 dstBuffer,
454 dstBufferSize,
455 readOffset);
456 if (ret != kIOReturnSuccess)
457 break;
458 }
459
460 if ( _buffer )
461 {
462 ret = readBytes(dstBuffer, dstBufferSize, readOffset) ?
463 kIOReturnSuccess : kIOReturnBadArgument;
464 }
465 }
466 while (0);
467
468 UNLOCK;
469
470 return ret;
471 }
472
473 //---------------------------------------------------------------------------
474 // Handle an external request to write to the data buffer
475 // from a source buffer provided by the accessor.
476
477 IOReturn IONetworkData::write(void * srcBuffer,
478 UInt32 srcBufferSize,
479 UInt32 writeOffset)
480 {
481 IOReturn ret = kIOReturnUnsupported;
482
483 LOCK;
484
485 do {
486 // Check the arguments.
487
488 if ( srcBuffer == 0 )
489 {
490 ret = kIOReturnBadArgument;
491 break;
492 }
493
494 // Check access.
495
496 if ( (_access & kIONetworkDataAccessTypeWrite) == 0 )
497 {
498 ret = kIOReturnNotWritable;
499 break;
500 }
501
502 // Update the data buffer.
503
504 if ( _buffer &&
505 (writeBytes(srcBuffer, srcBufferSize, writeOffset) == false) )
506 {
507 ret = kIOReturnBadArgument;
508 break;
509 }
510
511 // Notify the target after a successful write operation.
512
513 if ( TAP_IS_VALID )
514 {
515 ret = (*_tapAction)(_tapTarget, _tapParam,
516 this,
517 (UInt32) kIONetworkDataAccessTypeWrite,
518 srcBuffer,
519 &srcBufferSize,
520 writeOffset);
521 }
522 }
523 while (0);
524
525 UNLOCK;
526
527 return ret;
528 }
529
530 //---------------------------------------------------------------------------
531 // Serialize the IONetworkData object. If notification is enabled,
532 // then the notification handler is called before the data buffer is
533 // serialized.
534
535 bool IONetworkData::serialize(OSSerialize * s) const
536 {
537 bool ok;
538 OSDictionary * dictToSerialize;
539 OSData * dataEntry;
540 OSNumber * numberEntry;
541
542 dictToSerialize = OSDictionary::withCapacity(3);
543 if (!dictToSerialize)
544 return false;
545
546 numberEntry = OSNumber::withNumber(_access, sizeof(_access) * 8);
547 if (numberEntry) {
548 dictToSerialize->setObject(gIONDAccessKey, numberEntry);
549 numberEntry->release();
550 }
551
552 numberEntry = OSNumber::withNumber(_size, sizeof(_size) * 8);
553 if (numberEntry) {
554 dictToSerialize->setObject(gIONDSizeKey, numberEntry);
555 numberEntry->release();
556 }
557
558 LOCK;
559
560 do {
561 // Check access.
562
563 if ((_access & kIONetworkDataAccessTypeSerialize) == 0)
564 break;
565
566 if (_buffer == 0)
567 break;
568
569 // Notify the target before the read operation.
570 // The target can take this opportunity to update the
571 // data buffer. If the target returns an error,
572 // then the data buffer is not serialized.
573
574 if (TAP_IS_VALID &&
575 ((*_tapAction)(_tapTarget, _tapParam,
576 (IONetworkData *) this,
577 kIONetworkDataAccessTypeSerialize,
578 0, 0, 0) != kIOReturnSuccess))
579 {
580 break;
581 }
582
583 dataEntry = OSData::withBytesNoCopy(_buffer, _size);
584 if (dataEntry) {
585 dictToSerialize->setObject(gIONDDataKey, dataEntry);
586 dataEntry->release();
587 }
588 }
589 while (0);
590
591 ok = dictToSerialize->serialize(s);
592 dictToSerialize->release();
593
594 UNLOCK;
595
596 return ok;
597 }