virtual void copyRawContent(uint8_t buffer[]) const { // Use ARM instructions that can jump to thumb. if (_s_log) fprintf(stderr, "3 ARM instruction shim to jump to %s\n", _target->name()); OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, pc + 4 OSWriteLittleInt32(&buffer[ 4], 0, 0xe12fff1c); // bx ip OSWriteLittleInt32(&buffer[ 8], 0, 0); // .long target }
virtual void copyRawContent(uint8_t buffer[]) const { // Use ARM instructions that can jump to thumb. assert( _target->isThumb() ); if (_s_log) fprintf(stderr, "4 ARM instruction shim to jump to %s\n", _target->name()); OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 4 OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip OSWriteLittleInt32(&buffer[ 8], 0, 0xe12fff1c); // bx ip OSWriteLittleInt32(&buffer[12], 0, 0); // .long target-this }
virtual void copyRawContent(uint8_t buffer[]) const { // Use ARM instructions that can jump to thumb. assert( ! _target->isThumb() ); if (_s_log) fprintf(stderr, "3 Thumb2 instruction shim to jump to %s\n", _target->name()); OSWriteLittleInt32(&buffer[0], 0, 0xc004f8df); // ldr ip, pc + 4 OSWriteLittleInt16(&buffer[4], 0, 0x44fc); // add ip, pc, ip OSWriteLittleInt16(&buffer[6], 0, 0x4760); // bx ip OSWriteLittleInt32(&buffer[8], 0, 0x00000000); // .long target-this }
// ---------------------------------------------------------------------------------------------------- IOReturn PlatformInterfaceI2S_Mapped::setPeakLevel ( UInt32 channelTarget, UInt32 levelMeterValue ) { IOReturn result = kIOReturnSuccess; switch ( channelTarget ) { case kStreamFrontLeft: OSWriteLittleInt32 ( mI2SBaseAddress, kI2SPeakLevelIn0Offset, levelMeterValue ); break; case kStreamFrontRight: OSWriteLittleInt32 ( mI2SBaseAddress, kI2SPeakLevelIn1Offset, levelMeterValue ); break; default: result = kIOReturnBadArgument; break; } return result; }
IOReturn AppleI386AGP::commitAGPMemory( IOAGPDevice * master, IOMemoryDescriptor * memory, IOByteCount agpOffset, IOOptionBits options ) { IOPCIAddressSpace target = getBridgeSpace(); IOReturn err = kIOReturnSuccess; UInt32 offset = 0, tmp, agpCtrl; IOPhysicalAddress physAddr; IOByteCount len; // ok = agpRange->allocate( memory->getLength(), &agpOffset ); agpCtrl = configRead32(target, kiAGPCTRL); agpCtrl &= ~(1 << 7); configWrite32( target, kiAGPCTRL, agpCtrl ); // b7 gtlb ena if(memory) { assert( agpOffset < systemLength ); agpOffset /= (page_size / 4); while( (physAddr = memory->getPhysicalSegment( offset, &len ))) { offset += len; len = (len + 0xfff) & ~0xfff; while( len > 0) { OSWriteLittleInt32( gartArray, agpOffset, ((physAddr & ~0xfff) | 1)); agpOffset += 4; physAddr += page_size; len -= page_size; } } // Read back from last entry written to flush entry to main memory. tmp = OSReadLittleInt32(gartArray, agpOffset-4); #if 1 // Deal with stupid Pentium 4 8-deeps store queue crap. for(offset = 0; offset < 64*16; offset += 64) { tmp = OSReadLittleInt32(gartArray, offset); OSWriteLittleInt32(gartArray, offset, tmp); } #endif } agpCtrl = configRead32(target, kiAGPCTRL); agpCtrl |= (1 << 7); configWrite32( target, kiAGPCTRL, agpCtrl ); // b7 gtlb ena return( err ); }
virtual void copyRawContent(uint8_t buffer[]) const { OSWriteLittleInt32(&buffer[ 0], 0, 0xe92d400f); // push {r0, r1, r2, r3, lr} OSWriteLittleInt32(&buffer[ 4], 0, 0xebfffffd); // bl _foo OSWriteLittleInt32(&buffer[ 8], 0, 0xe59fc010); // ldr ip, [pc, #16] OSWriteLittleInt32(&buffer[12], 0, 0xe08fc00c); // add ip, pc, ip OSWriteLittleInt32(&buffer[16], 0, 0xe58c0000); // str r0, [ip] OSWriteLittleInt32(&buffer[20], 0, 0xe1a0c000); // mov ip, r0 OSWriteLittleInt32(&buffer[24], 0, 0xe8bd400f); // pop {r0, r1, r2, r3, lr} OSWriteLittleInt32(&buffer[28], 0, 0xe12fff1c); // bx ip OSWriteLittleInt32(&buffer[32], 0, 0x00000000); // .long foo$lazyptr - helper + 20 }
/* write a 32-bit word, little endian */ void appendUint32( CFMutableDataRef buf, uint32_t word) { #if 1 unsigned char cb[4]; OSWriteLittleInt32(cb, 0, word); CFDataAppendBytes(buf, cb, 4); #else /* This is an alternate implementation which may or may not be faster than the above. */ CFIndex offset = CFDataGetLength(buf); UInt8 *bytes = CFDataGetMutableBytePtr(buf); CFDataIncreaseLength(buf, 4); OSWriteLittleInt32(bytes, offset, word); #endif }
virtual void copyRawContent(uint8_t buffer[]) const { // push lazy-info-offset OSWriteLittleInt32(&buffer[ 0], 0, 0xe52dc004); // str ip, [sp, #-4]! // push address of dyld_mageLoaderCache OSWriteLittleInt32(&buffer[ 4], 0, 0xe59fc010); // ldr ip, L1 OSWriteLittleInt32(&buffer[ 8], 0, 0xe08fc00c); // add ip, pc, ip OSWriteLittleInt32(&buffer[12], 0, 0xe52dc004); // str ip, [sp, #-4]! // jump through _fast_lazy_bind OSWriteLittleInt32(&buffer[16], 0, 0xe59fc008); // ldr ip, L2 OSWriteLittleInt32(&buffer[20], 0, 0xe08fc00c); // add ip, pc, ip OSWriteLittleInt32(&buffer[24], 0, 0xe59cf000); // ldr pc, [ip] OSWriteLittleInt32(&buffer[28], 0, 0x00000000); // L1: .long fFastStubGOTAtom - (helperhelper+16) OSWriteLittleInt32(&buffer[32], 0, 0x00000000); // L2: .long _fast_lazy_bind - (helperhelper+28) }
/* * Update a security buffer's offset to be the current end of data in a CFData. */ void secBufOffset( CFMutableDataRef buf, CFIndex offsetIndex) /* obtained from appendSecBuf() */ { CFIndex currPos = CFDataGetLength(buf); unsigned char cb[4]; OSWriteLittleInt32(cb, 0, (uint32_t)currPos); CFRange range = {offsetIndex, 4}; CFDataReplaceBytes(buf, range, cb, 4); }
virtual void copyRawContent(uint8_t buffer[]) const { // Use ARM instructions that can jump to thumb. assert( ! _target->isThumb() ); if (_s_log) fprintf(stderr, "6 Thumb1 instruction shim to jump to %s\n", _target->name()); OSWriteLittleInt16(&buffer[ 0], 0, 0xb402); // push {r1} OSWriteLittleInt16(&buffer[ 2], 0, 0x4902); // ldr r1, [pc, #8] OSWriteLittleInt16(&buffer[ 4], 0, 0x4479); // add r1, pc OSWriteLittleInt16(&buffer[ 6], 0, 0x468c); // mov ip, r1 OSWriteLittleInt16(&buffer[ 8], 0, 0xbc02); // pop {r1} OSWriteLittleInt16(&buffer[10], 0, 0x4760); // bx ip OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long target-this }
bool CLASS::initRxRing( void ) { IOPhysicalSegment vector; UInt segCount; IOPhysicalAddress physAddr; RxDesc * descPtr; UInt32 cmdStatus; // Link the descriptors into a ring. for (int i = kRxDescCount - 1 ;i > 0; i--) { physAddr = fRxDescMemory->getPhysicalSegment(sizeof(RxDesc) * i, 0); if (physAddr == 0) return false; fRxDescBase[i-1].link = physAddr; } // Wrap the ring - last descriptor points to the first fRxDescBase[kRxDescCount - 1].link = fRxDescPhysAddr; // Attach cluster mbufs to each receive descriptor. for (UInt32 i = 0 ;i < kRxDescCount; i++) { descPtr = &fRxDescBase[i]; if (descPtr->packet == 0) descPtr->packet = allocatePacket( kRxMaxBufferSize ); if (descPtr->packet == 0) return false; segCount = fRxMbufCursor->getPhysicalSegments( descPtr->packet, &vector, 1); if (segCount != 1) return false; cmdStatus = kDescInterrupt | kDescIncludeCRC | (kRxMaxBufferSize & kDescBufferSizeMask); descPtr->bufferPtr = vector.location; OSWriteLittleInt32(&descPtr->cmdStatus, 0, cmdStatus); } fRxHeadIndex = 0; return true; }
/* * Write a security buffer, providing the index into the CFData at which * this security buffer's offset is located. Just before the actual data is written, * go back and update the offset with the start of that data using secBufOffset(). */ void appendSecBuf( CFMutableDataRef buf, uint16_t len, CFIndex *offsetIndex) { #if 1 unsigned char cb[8]; OSWriteLittleInt16(cb, 0, len); /* buffer length */ OSWriteLittleInt16(cb, 2, len); /* buffer allocated size */ OSWriteLittleInt32(cb, 4, 0); /* offset is empty for now */ CFDataAppendBytes(buf, cb, 8); *offsetIndex = CFDataGetLength(buf) - 4; /* offset will go here */ #else appendUint16(buf, len); /* buffer length */ appendUint16(buf, len); /* buffer allocated size */ *offsetIndex = CFDataGetLength(buf); /* offset will go here */ appendUint32(buf, 0); /* but it's empty for now */ #endif }
static uint64_t WriteMMIO(uint64_t phys, uint8_t length, uint64_t value){ IOMemoryDescriptor* io_desc; IOMemoryMap* io_map; uint64_t page_offset = phys & PAGE_MASK; log_addr((uint64_t) page_offset, 64, "page_offset"); xlate_pa_va(phys, &io_desc, &io_map); if(io_map) { log_addr(io_map->getVirtualAddress(), 64, "io_map->getVirtualAddress"); switch (length) { case 1: *(volatile uint8_t *)((uintptr_t)io_map->getVirtualAddress() + page_offset) = value; break; case 2: OSWriteLittleInt16((void *)io_map->getVirtualAddress(), page_offset, (uint16_t) value); break; case 4: OSWriteLittleInt32((void *)io_map->getVirtualAddress(), page_offset, (uint32_t) value); break; case 8: OSWriteLittleInt64((void *)io_map->getVirtualAddress(), page_offset, value); default: pmem_error("WriteMMIO Incorrect write length"); break; } } unxlate_pa_va(&io_desc, &io_map); return value; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void AudioI2SControl::WriteWordLittleEndian(void *address, UInt32 offset, UInt32 value) { OSWriteLittleInt32(address, offset, value); }
void CLASS::serviceRxInterrupt(void) { mbuf_t pkt; UInt32 rxStatus; UInt32 rxLength; UInt32 rxIndex = fRxHeadIndex; RxDesc * descPtr = &fRxDescBase[ rxIndex ]; bool pktReplaced; rxStatus = OSReadLittleInt32(&descPtr->cmdStatus, 0); while (rxStatus & kDescOwn) { DEBUG_LOG("RX Status = %lx @ index %lu\n", rxStatus, rxIndex); // Total packet length, including the 4-byte FCS? rxLength = (rxStatus & kDescBufferSizeMask); // Packet must be contained within a single descriptor, // and must be a good packet. if (((rxStatus & (kDescMore | kDescPacketOK)) == kDescPacketOK) && (rxLength <= kIOEthernetMaxPacketSize + 4)) { pkt = replaceOrCopyPacket( &descPtr->packet, rxLength, &pktReplaced); if (pkt) { if (pktReplaced) { // New packet added to ring, update descriptor // with new physical address. OSWriteLittleInt32(&descPtr->bufferPtr, 0, MBUF_PADDR(descPtr->packet)); assert(descPtr->bufferPtr != 0); } fNetif->inputPacket( pkt, rxLength, IONetworkInterface::kInputOptionQueuePacket ); NET_STAT(inputPackets, 1); } else /* !pkt (mbuf shortage) */ { NET_STAT(inputErrors, 1); ETH_STAT(dot3RxExtraEntry.resourceErrors, 1); DEBUG_LOG("RX RESOURCE ERROR\n"); } } else { recordRxDescriptorErrors(rxStatus); } // Update the current descriptor and make it owned by NIC. rxStatus = kDescInterrupt | kDescIncludeCRC | (kRxMaxBufferSize & kDescBufferSizeMask); OSWriteLittleInt32(&descPtr->cmdStatus, 0, rxStatus); // Advance to next descriptor. rxIndex = (rxIndex + 1) & (kRxDescCount - 1); descPtr = &fRxDescBase[rxIndex]; rxStatus = OSReadLittleInt32(&descPtr->cmdStatus, 0); } fRxHeadIndex = rxIndex; // Push up all packets received in the loop above in one shot. fNetif->flushInputQueue(); }
UInt32 CLASS::outputPacket( mbuf_t packet, void * param ) { TxDesc * descNext; TxDesc * descHead; TxDesc * descLast; UInt segCount; UInt32 cmdStatus; UInt32 tailIndex; IOPhysicalSegment vectors[ kTxMaxSegmentCount ]; IODebuggerLockState state; state = IOKernelDebugger::lock(this); tailIndex = fTxTailIndex; // Check if there are enough descriptors to describe the packet // buffers. kTxMaxSegmentCount should be large enough to reduce // the need to coalesce mbufs. if (TX_RING_FREE(fTxHeadIndex, tailIndex) < kTxMaxSegmentCount) { IOKernelDebugger::unlock(state); return kIOReturnOutputStall; } // Get the next transmit descriptor owned by the driver. descHead = &fTxDescBase[tailIndex]; descNext = descHead; // Use the mbuf cursor to generate a list of physical address and // length vectors for the network buffers. segCount = fTxMbufCursor->getPhysicalSegmentsWithCoalesce( packet, vectors, kTxMaxSegmentCount); if (segCount == 0) { DEBUG_LOG("TX Cursor returned 0 segments\n"); goto drop_packet; } assert(segCount <= kTxMaxSegmentCount); // Update the first (head) descriptor. // Do not set the OWN bit until the rest of the descriptors are done. OSWriteLittleInt32(&descHead->bufferPtr, 0, vectors[0].location); cmdStatus = (vectors[0].length & kDescBufferSizeMask); tailIndex = (tailIndex + 1) & (kTxDescCount - 1); descLast = descHead; descNext = &fTxDescBase[tailIndex]; for (UInt seg = 1; seg < segCount; seg++) { // Write cmdStatus for previous descriptor with MORE bit set. OSWriteLittleInt32(&descLast->cmdStatus, 0, cmdStatus | kDescMore); // Update current descriptor. OSWriteLittleInt32(&descNext->bufferPtr, 0, vectors[seg].location); cmdStatus = (vectors[seg].length & kDescBufferSizeMask) | kDescOwn; tailIndex = (tailIndex + 1) & (kTxDescCount - 1); descLast = descNext; descNext = &fTxDescBase[tailIndex]; } // Last descriptor must have MORE bit cleared. if (++fTxInterruptInterval >= (kTxDescCount/kTxMaxSegmentCount/4)) { cmdStatus |= kDescInterrupt; fTxInterruptInterval = 0; } OSWriteLittleInt32(&descLast->cmdStatus, 0, cmdStatus); // Set OWN bit on head descriptor after all descriptors following it // have been prepared. descHead->cmdStatus |= OSSwapHostToLittleConstInt32(kDescOwn); // Update Head Descriptor. descHead->packet = packet; descHead->descLast = descLast; descHead->descCount = segCount; descHead->nextIndex = tailIndex; // Update free descriptor count after completing the descriptor chain. // The order is important otherwise we may race with interrupt handler. fTxTailIndex = tailIndex; DEBUG_LOG("TX DESC:%d-%ld (size %d)\n", descHead-fTxDescBase, fTxTailIndex, mbuf_pkthdr_len(packet)); // Enable transmitter in case its in txIdle state. WriteReg(CR, CR_TXE); IOKernelDebugger::unlock(state); NET_STAT(outputPackets, 1); return kIOReturnOutputSuccess; drop_packet: IOKernelDebugger::unlock(state); freePacket(packet); ETH_STAT(dot3TxExtraEntry.resourceErrors, 1); return kIOReturnOutputDropped; }
// ---------------------------------------------------------------------------------------------------- IOReturn PlatformInterfaceI2S_Mapped::setI2SIOM_PeakLevelIn1 ( UInt32 value ) { OSWriteLittleInt32(mI2SBaseAddress, kI2SPeakLevelIn1Offset, value); return kIOReturnSuccess; }
virtual void copyRawContent(uint8_t buffer[]) const { OSWriteLittleInt32(&buffer[0], 0, 0xe59fc000); // ldr ip, [pc, #0] OSWriteLittleInt32(&buffer[4], 0, 0xea000000); // b _helperhelper OSWriteLittleInt32(&buffer[8], 0, 0); // .long lazy-info-offset }
// ---------------------------------------------------------------------------------------------------- IOReturn PlatformInterfaceI2S_Mapped::setI2SIOM_CodecMsgIn ( UInt32 value ) { OSWriteLittleInt32(mI2SBaseAddress, kI2SCodecMsgInOffset, value); return kIOReturnSuccess; }
virtual void copyRawContent(uint8_t buffer[]) const { OSWriteLittleInt32(&buffer[ 0], 0, 0xE59FF000); // ldr pc, [pc, #foo$lazy_ptr] }
// ---------------------------------------------------------------------------------------------------- IOReturn PlatformInterfaceI2S_Mapped::setI2SIOMIntControl ( UInt32 intCntrl ) { OSWriteLittleInt32(mI2SBaseAddress, kI2SIntCtlOffset, intCntrl); return kIOReturnSuccess; }
virtual void copyRawContent(uint8_t buffer[]) const { OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 12 OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); // ldr pc, [ip] OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long L_foo$lazy_ptr - (L1$scv + 8) }
// ---------------------------------------------------------------------------------------------------- IOReturn PlatformInterfaceI2S_Mapped::setFrameCount ( UInt32 value ) { OSWriteLittleInt32 ( mI2SBaseAddress, kI2SFrameCountOffset, value ); return kIOReturnSuccess; }
// ---------------------------------------------------------------------------------------------------- IOReturn PlatformInterfaceI2S_Mapped::setDataWordSizes ( UInt32 dataWordSizes ) { debugIOLog ( 3, "± PlatformInterfaceI2S_Mapped::setDataWordSizes ( 0x%0.8X )", dataWordSizes ); OSWriteLittleInt32(mI2SBaseAddress, kI2SDataWordSizesOffset, dataWordSizes); return kIOReturnSuccess; }
virtual void copyRawContent(uint8_t buffer[]) const { OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, [pc, #0] OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); // ldr pc, [ip] OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); // .long L_foo$lazy_ptr }
void writel(unsigned int value, void *addr) { OSWriteLittleInt32((volatile void*)addr, 0, value); }
// ---------------------------------------------------------------------------------------------------- IOReturn PlatformInterfaceI2S_Mapped::setI2SIOM_FrameMatch ( UInt32 value ) { OSWriteLittleInt32(mI2SBaseAddress, kI2SFrameMatchOffset, value); return kIOReturnSuccess; }
// ---------------------------------------------------------------------------------------------------- IOReturn PlatformInterfaceI2S_Mapped::setSerialFormatRegister ( UInt32 serialFormat ) { debugIOLog ( 3, "± PlatformInterfaceI2S_Mapped::setSerialFormatRegister ( 0x%0.8X )", serialFormat ); OSWriteLittleInt32 ( mI2SBaseAddress, kI2SSerialFormatOffset, serialFormat ); return kIOReturnSuccess; }
NTSTATUS SMBRawTransaction( SMBHANDLE inConnection, const void *lpInBuffer, size_t nInBufferSize, void *lpOutBuffer, size_t nOutBufferSize, size_t *lpBytesRead) { NTSTATUS status; int err; void * hContext; struct smb_header header; mbuf_t words = NULL; mbuf_t bytes = NULL; mbuf_t response = NULL; size_t len; const void * ptr; bzero(&header, sizeof(header)); status = SMBServerContext(inConnection, &hContext); if (!NT_SUCCESS(status)) { return status; } if ((size_t)nInBufferSize < sizeof(struct smb_header) || (size_t)nOutBufferSize < sizeof(struct smb_header)) { err = STATUS_BUFFER_TOO_SMALL; goto errout; } /* Split the request buffer into the header, the parameter words and the * data bytes. */ ptr = lpInBuffer; ADVANCE(ptr, sizeof(uint32_t)); header.command = *(uint8_t *)ptr; if ((size_t)nInBufferSize < (sizeof(struct smb_header) + sizeof(uint8_t))) { err = STATUS_BUFFER_TOO_SMALL; goto errout; } ptr = lpInBuffer; ADVANCE(ptr, sizeof(struct smb_header)); len = (*(uint8_t *)ptr) * sizeof(uint16_t); ADVANCE(ptr, sizeof(uint8_t)); /* skip word_count field */ if (mbuf_attachcluster(MBUF_WAITOK, MBUF_TYPE_DATA, &words, (void *)ptr, NULL, len, NULL)) { err = STATUS_NO_MEMORY; goto errout; } mbuf_setlen(words, len); ADVANCE(ptr, len); /* skip parameter words */ if ((uintptr_t)ptr > ((uintptr_t)lpInBuffer + nInBufferSize) || (uintptr_t)ptr < (uintptr_t)mbuf_data(words)) { err = STATUS_MARSHALL_OVERFLOW; goto errout; } len = OSReadLittleInt16(ptr, 0); ADVANCE(ptr, sizeof(uint16_t)); /* skip byte_count field */ if (mbuf_attachcluster(MBUF_WAITOK, MBUF_TYPE_DATA, &bytes, (void *)ptr, NULL, len, NULL)) { err = STATUS_NO_MEMORY; goto errout; } mbuf_setlen(bytes, len); ADVANCE(ptr, len); if ((uintptr_t)ptr > ((uintptr_t)lpInBuffer + nInBufferSize) || (uintptr_t)ptr < (uintptr_t)mbuf_data(bytes)) { err = STATUS_MARSHALL_OVERFLOW; goto errout; } /* Set up the response buffer so that we leave room to place the * SMB header at the front. */ len = (size_t)(nOutBufferSize - sizeof(struct smb_header)); if (mbuf_attachcluster(MBUF_WAITOK, MBUF_TYPE_DATA, &response, ((uint8_t *)lpOutBuffer + sizeof(struct smb_header)), NULL, len, NULL)) { err = STATUS_NO_MEMORY; goto errout; } err = smb_ioc_request(hContext, &header, words, bytes, response); if (err) { err = STATUS_IO_DEVICE_ERROR; goto errout; } /* Stash the new SMB header at the front of the output buffer so the * caller gets the server status code, etc. */ memcpy(lpOutBuffer, lpInBuffer, sizeof(header)); OSWriteLittleInt32(lpOutBuffer, 0, *(const uint32_t *)(void *)SMB_SIGNATURE); OSWriteLittleInt32(lpOutBuffer, offsetof(struct smb_header, status), header.status); OSWriteLittleInt16(lpOutBuffer, offsetof(struct smb_header, flags), header.flags); OSWriteLittleInt32(lpOutBuffer, offsetof(struct smb_header, flags2), header.flags2); *lpBytesRead = mbuf_len(response) + sizeof(struct smb_header); /* We return success, even though the server may have failed the call. The * caller is responsible for parsing the reply packet and looking at the * status field in the header. */ err = STATUS_SUCCESS; errout: if (words) mbuf_freem(words); if (bytes) mbuf_freem(bytes); if (response) mbuf_freem(response); return err; }