// Read the next packet from the driver bool SuGetNextPacket(SU_ADAPTER *a, void **buf, UINT *size) { // Validate arguments if (a == NULL || buf == NULL || size == NULL) { return false; } if (a->Halt) { return false; } while (true) { if (a->CurrentPacketCount < SL_NUM_PACKET(a->GetBuffer)) { // There are still packets that have been already read *size = SL_SIZE_OF_PACKET(a->GetBuffer, a->CurrentPacketCount); *buf = Malloc(*size); Copy(*buf, SL_ADDR_OF_PACKET(a->GetBuffer, a->CurrentPacketCount), *size); // Increment the packet number a->CurrentPacketCount++; return true; } else { // Read the next packet from the driver if (SuGetPacketsFromDriver(a) == false) { return false; } if (SL_NUM_PACKET(a->GetBuffer) == 0) { // Packet is not received yet *buf = NULL; *size = 0; return true; } a->CurrentPacketCount = 0; } } }
// Write the next packet to the driver bool SuPutPacket(SU_ADAPTER *a, void *buf, UINT size) { // Validate arguments if (a == NULL) { return false; } if (a->Halt) { return false; } if (size > MAX_PACKET_SIZE) { return false; } // First, examine whether the current buffer is full if ((SL_NUM_PACKET(a->PutBuffer) >= SL_MAX_PACKET_EXCHANGE) || (buf == NULL && SL_NUM_PACKET(a->PutBuffer) != 0)) { // Write all current packets to the driver if (SuPutPacketsToDriver(a) == false) { return false; } SL_NUM_PACKET(a->PutBuffer) = 0; } // Add the next packet to the buffer if (buf != NULL) { UINT i = SL_NUM_PACKET(a->PutBuffer); SL_NUM_PACKET(a->PutBuffer)++; SL_SIZE_OF_PACKET(a->PutBuffer, i) = size; Copy(SL_ADDR_OF_PACKET(a->PutBuffer, i), buf, size); Free(buf); } return true; }
// Write procedure of the device NTSTATUS SlDeviceWriteProc(DEVICE_OBJECT *device_object, IRP *irp) { SL_DEVICE *dev = *((SL_DEVICE **)device_object->DeviceExtension); NTSTATUS ret = STATUS_UNSUCCESSFUL; IO_STACK_LOCATION *irp_stack = IoGetCurrentIrpStackLocation(irp); UINT ret_size = 0; if (dev->IsBasicDevice == false) { // Adapter device SL_FILE *f = irp_stack->FileObject->FsContext; if (irp_stack->Parameters.Write.Length == SL_EXCHANGE_BUFFER_SIZE) { UCHAR *buf = irp->UserBuffer; if (dev->Halting || dev->Adapter->Halt || buf == NULL) { // Halting } else { // Write the packet MDL *mdl; UINT num = SL_NUM_PACKET(buf); mdl = IoAllocateMdl(buf, SL_EXCHANGE_BUFFER_SIZE, false, false, NULL); if (mdl != NULL) { MmProbeAndLockPages(mdl, KernelMode, IoReadAccess); } ret = true; ret_size = SL_EXCHANGE_BUFFER_SIZE; if (num >= 1 && num <= SL_MAX_PACKET_EXCHANGE) { UINT i, j; NET_BUFFER_LIST *nbl_head = NULL; NET_BUFFER_LIST *nbl_tail = NULL; UINT num_packets = 0; NDIS_HANDLE adapter_handle = NULL; SlLock(f->Adapter->Lock); if (f->Adapter->NumPendingSendPackets <= SL_MAX_PACKET_QUEUED) { // Admit to send only if the number of packets being transmitted does not exceed the specified limit adapter_handle = f->Adapter->AdapterHandle; } if (adapter_handle != NULL) { // Lock the file list which opens the same adapter SlLockList(dev->FileList); for (j = 0;j < SL_LIST_NUM(dev->FileList);j++) { SL_FILE *other = SL_LIST_DATA(dev->FileList, j); if (other != f) { // Lock the receive queue of other file lists SlLock(other->RecvLock); other->SetEventFlag = false; } } for (i = 0;i < num;i++) { UINT packet_size = SL_SIZE_OF_PACKET(buf, i); UCHAR *packet_buf; NET_BUFFER_LIST *nbl = NULL; bool ok = false; if (packet_size > SL_MAX_PACKET_SIZE) { packet_size = SL_MAX_PACKET_SIZE; } else if (packet_size < SL_PACKET_HEADER_SIZE) { packet_size = SL_PACKET_HEADER_SIZE; } packet_buf = (UCHAR *)SL_ADDR_OF_PACKET(buf, i); for (j = 0;j < SL_LIST_NUM(dev->FileList);j++) { SL_FILE *other = SL_LIST_DATA(dev->FileList, j); if (other != f) { // Insert into the receive queue of the other file lists if (other->NumRecvPackets < SL_MAX_PACKET_QUEUED) { SL_PACKET *q = SlMalloc(sizeof(SL_PACKET)); SlCopy(q->Data, packet_buf, packet_size); q->Size = packet_size; q->Next = NULL; if (other->RecvPacketHead == NULL) { other->RecvPacketHead = q; } else { other->RecvPacketTail->Next = q; } other->RecvPacketTail = q; other->NumRecvPackets++; other->SetEventFlag = true; } } } // Allocate a new NET_BUFFER_LIST if (f->NetBufferListPool != NULL) { nbl = NdisAllocateNetBufferList(f->NetBufferListPool, 16, 0); if (nbl != NULL) { nbl->SourceHandle = adapter_handle; } } if (nbl != NULL) { // Get the NET_BUFFER from the NET_BUFFER_LIST NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl); NET_BUFFER_LIST_NEXT_NBL(nbl) = NULL; if (nb != NULL && OK(NdisRetreatNetBufferDataStart(nb, packet_size, 0, NULL))) { // Buffer copy UCHAR *dst = NdisGetDataBuffer(nb, packet_size, NULL, 1, 0); if (dst != NULL) { SlCopy(dst, packet_buf, packet_size); ok = true; } else { NdisAdvanceNetBufferDataStart(nb, packet_size, false, NULL); } } } if (ok == false) { if (nbl != NULL) { NdisFreeNetBufferList(nbl); } } else { if (nbl_head == NULL) { nbl_head = nbl; } if (nbl_tail != NULL) { NET_BUFFER_LIST_NEXT_NBL(nbl_tail) = nbl; } nbl_tail = nbl; *((void **)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl)) = f; num_packets++; } } for (j = 0;j < SL_LIST_NUM(dev->FileList);j++) { SL_FILE *other = SL_LIST_DATA(dev->FileList, j); if (other != f) { // Release the receive queue of other file lists SlUnlock(other->RecvLock); // Set an event if (other->SetEventFlag) { SlSet(other->Event); } } } SlUnlockList(dev->FileList); if (nbl_head != NULL) { InterlockedExchangeAdd(&f->NumSendingPacketets, num_packets); InterlockedExchangeAdd(&f->Adapter->NumPendingSendPackets, num_packets); SlUnlock(f->Adapter->Lock); NdisSendNetBufferLists(adapter_handle, nbl_head, 0, 0); } else { SlUnlock(f->Adapter->Lock); } } else { SlUnlock(f->Adapter->Lock); } } if (mdl != NULL) { MmUnlockPages(mdl); IoFreeMdl(mdl); } } } } irp->IoStatus.Information = ret_size; irp->IoStatus.Status = ret; IoCompleteRequest(irp, IO_NO_INCREMENT); return ret; }
// Read procedure of the device NTSTATUS SlDeviceReadProc(DEVICE_OBJECT *device_object, IRP *irp) { SL_DEVICE *dev = *((SL_DEVICE **)device_object->DeviceExtension); NTSTATUS ret = STATUS_UNSUCCESSFUL; UINT ret_size = 0; IO_STACK_LOCATION *irp_stack = IoGetCurrentIrpStackLocation(irp); if (dev->IsBasicDevice) { // Return the adapter list in the case of basic device if (irp_stack->Parameters.Read.Length >= sizeof(SL_ADAPTER_INFO_LIST)) { SL_ADAPTER_INFO_LIST *dst = irp->UserBuffer; if (dst != NULL) { MDL *mdl; mdl = IoAllocateMdl(dst, irp_stack->Parameters.Read.Length, false, false, NULL); if (mdl != NULL) { MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess); } SlZero(dst, sizeof(SL_ADAPTER_INFO_LIST)); dst->Signature = SL_SIGNATURE; dst->SeLowVersion = SL_VER; dst->EnumCompleted = sl->IsEnumCompleted ? 8 : 1; SlLockList(sl->AdapterList); { UINT i; dst->NumAdapters = MIN(SL_LIST_NUM(sl->AdapterList), SL_MAX_ADAPTER_INFO_LIST_ENTRY); for (i = 0;i < dst->NumAdapters;i++) { SL_ADAPTER *a = SL_LIST_DATA(sl->AdapterList, i); SL_ADAPTER_INFO *d = &dst->Adapters[i]; d->MtuSize = a->MtuSize; SlCopy(d->MacAddress, a->MacAddress, 6); SlCopy(d->AdapterId, a->AdapterId, sizeof(a->AdapterId)); strcpy(d->FriendlyName, a->FriendlyName); } } SlUnlockList(sl->AdapterList); ret_size = sizeof(SL_ADAPTER_INFO); ret = STATUS_SUCCESS; if (mdl != NULL) { MmUnlockPages(mdl); IoFreeMdl(mdl); } } } } else { // Adapter device SL_FILE *f = irp_stack->FileObject->FsContext; if (irp_stack->Parameters.Read.Length == SL_EXCHANGE_BUFFER_SIZE) { UCHAR *buf = irp->UserBuffer; if (dev->Halting || f->Adapter->Halt || buf == NULL) { // Halting } else { UINT num = 0; bool left = true; MDL *mdl; mdl = IoAllocateMdl(buf, SL_EXCHANGE_BUFFER_SIZE, false, false, NULL); if (mdl != NULL) { MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess); } // Lock the receive queue SlLock(f->RecvLock); { while (true) { SL_PACKET *q; if (num >= SL_MAX_PACKET_EXCHANGE) { if (f->RecvPacketHead == NULL) { left = false; } break; } q = f->RecvPacketHead; if (q != NULL) { f->RecvPacketHead = f->RecvPacketHead->Next; q->Next = NULL; f->NumRecvPackets--; if (f->RecvPacketHead == NULL) { f->RecvPacketTail = NULL; } } else { left = false; break; } SL_SIZE_OF_PACKET(buf, num) = q->Size; SlCopy(SL_ADDR_OF_PACKET(buf, num), q->Data, q->Size); num++; SlFree(q); } } SlUnlock(f->RecvLock); if (mdl != NULL) { MmUnlockPages(mdl); IoFreeMdl(mdl); } SL_NUM_PACKET(buf) = num; SL_LEFT_FLAG(buf) = left; if (left == false) { SlReset(f->Event); } else { SlSet(f->Event); } ret = STATUS_SUCCESS; ret_size = SL_EXCHANGE_BUFFER_SIZE; } } } irp->IoStatus.Status = ret; irp->IoStatus.Information = ret_size; IoCompleteRequest(irp, IO_NO_INCREMENT); return ret; }