// Crash void NeoNdisCrash() { NEO_QUEUE *q; q = (NEO_QUEUE *)0xACACACAC; q->Size = 128; NeoCopy(q->Buf, "ABCDEFG", 8); }
// Read the packet data from the transmit packet queue void NeoRead(void *buf) { NEO_QUEUE *q; UINT num; BOOL left; // Validate arguments if (buf == NULL) { return; } // Copy the packets one by one from the queue num = 0; left = TRUE; NeoLockPacketQueue(); { while (TRUE) { if (num >= NEO_MAX_PACKET_EXCHANGE) { if (ctx->PacketQueue == NULL) { left = FALSE; } break; } q = NeoGetNextQueue(); if (q == NULL) { left = FALSE; break; } NEO_SIZE_OF_PACKET(buf, num) = q->Size; NeoCopy(NEO_ADDR_OF_PACKET(buf, num), q->Buf, q->Size); num++; NeoFreeQueue(q); } } NeoUnlockPacketQueue(); NEO_NUM_PACKET(buf) = num; NEO_LEFT_FLAG(buf) = left; if (left == FALSE) { NeoReset(ctx->Event); } else { NeoSet(ctx->Event); } return; }
// Process the received packet void NeoWrite(void *buf) { UINT num, i, size; UCHAR *packet_buf; NET_BUFFER_LIST *nbl_chain = NULL; NET_BUFFER_LIST *nbl_tail = NULL; UINT num_nbl_chain = 0; // Validate arguments if (buf == NULL) { return; } // Number of packets num = NEO_NUM_PACKET(buf); if (num > NEO_MAX_PACKET_EXCHANGE) { // Number of packets is too many return; } if (num == 0) { // No packet return; } if (ctx->Halting != FALSE) { // Stopping return; } if (ctx->Paused) { // Paused return; } if (ctx->Opened == FALSE) { // Not connected return; } for (i = 0;i < num;i++) { PACKET_BUFFER *p = ctx->PacketBuffer[i]; void *dst; NET_BUFFER_LIST *nbl = ctx->PacketBuffer[i]->NetBufferList; NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl); nbl->SourceHandle = ctx->NdisMiniport; NET_BUFFER_LIST_NEXT_NBL(nbl) = NULL; size = NEO_SIZE_OF_PACKET(buf, i); if (size > NEO_MAX_PACKET_SIZE) { size = NEO_MAX_PACKET_SIZE; } if (size < NEO_PACKET_HEADER_SIZE) { size = NEO_PACKET_HEADER_SIZE; } packet_buf = (UCHAR *)(NEO_ADDR_OF_PACKET(buf, i)); if (OK(NdisRetreatNetBufferDataStart(nb, size, 0, NULL))) { // Buffer copy dst = NdisGetDataBuffer(nb, size, NULL, 1, 0); if (dst != NULL) { NeoCopy(dst, packet_buf, size); if (nbl_chain == NULL) { nbl_chain = nbl; } if (nbl_tail != NULL) { NET_BUFFER_LIST_NEXT_NBL(nbl_tail) = nbl; } nbl_tail = nbl; num_nbl_chain++; } } nbl->Status = NDIS_STATUS_RESOURCES; ctx->Status.Int64BytesRecvTotal += (UINT64)size; if (packet_buf[0] & 0x40) { ctx->Status.Int64NumRecvBroadcast++; ctx->Status.Int64BytesRecvBroadcast += (UINT64)size; } else { ctx->Status.Int64NumRecvUnicast++; ctx->Status.Int64BytesRecvUnicast += (UINT64)size; } } if (nbl_chain == NULL) { return; } // Notify that it has received ctx->Status.NumPacketRecv += num_nbl_chain; NdisMIndicateReceiveNetBufferLists(ctx->NdisMiniport, nbl_chain, 0, num_nbl_chain, NDIS_RECEIVE_FLAGS_RESOURCES); if (true) { // Restore the packet buffer NET_BUFFER_LIST *nbl = nbl_chain; while (nbl != NULL) { NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl); if (nb != NULL) { UINT size = NET_BUFFER_DATA_LENGTH(nb); NdisAdvanceNetBufferDataStart(nb, size, false, NULL); } nbl = NET_BUFFER_LIST_NEXT_NBL(nbl); } } }
// Process the received packet void NeoWrite(void *buf) { UINT num, i, size; void *packet_buf; // Validate arguments if (buf == NULL) { return; } // Number of packets num = NEO_NUM_PACKET(buf); if (num > NEO_MAX_PACKET_EXCHANGE) { // Number of packets is too many return; } if (num == 0) { // No packet return; } if (ctx->Halting != FALSE) { // Halting return; } if (ctx->Opened == FALSE) { // Not connected return; } for (i = 0;i < num;i++) { PACKET_BUFFER *p = ctx->PacketBuffer[i]; size = NEO_SIZE_OF_PACKET(buf, i); if (size > NEO_MAX_PACKET_SIZE) { size = NEO_MAX_PACKET_SIZE; } if (size < NEO_PACKET_HEADER_SIZE) { size = NEO_PACKET_HEADER_SIZE; } packet_buf = NEO_ADDR_OF_PACKET(buf, i); // Buffer copy NeoCopy(p->Buf, packet_buf, size); if (g_is_win8 == false) { // Adjust the buffer size NdisAdjustBufferLength(p->NdisBuffer, size); // Set the packet information NDIS_SET_PACKET_STATUS(p->NdisPacket, NDIS_STATUS_RESOURCES); NDIS_SET_PACKET_HEADER_SIZE(p->NdisPacket, NEO_PACKET_HEADER_SIZE); } else { NdisMEthIndicateReceive(ctx->NdisMiniport, ctx, p->Buf, NEO_PACKET_HEADER_SIZE, ((UCHAR *)p->Buf) + NEO_PACKET_HEADER_SIZE, size - NEO_PACKET_HEADER_SIZE, size - NEO_PACKET_HEADER_SIZE); NdisMEthIndicateReceiveComplete(ctx->NdisMiniport); } } // Notify that packets have received ctx->Status.NumPacketRecv += num; if (g_is_win8 == false) { NdisMIndicateReceivePacket(ctx->NdisMiniport, ctx->PacketBufferArray, num); } }
// Initialization handler of adapter NDIS_STATUS NeoNdisInitEx(NDIS_HANDLE MiniportAdapterHandle, NDIS_HANDLE MiniportDriverContext, PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters) { NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES attr; NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES gen; NDIS_PM_CAPABILITIES pnpcap; if (ctx == NULL) { return NDIS_STATUS_FAILURE; } if (ctx->NdisMiniportDriverHandle == NULL) { ctx->NdisMiniportDriverHandle = ndis_miniport_driver_handle; } // Prevention of multiple start if (ctx->Initing != FALSE) { // Multiple started return NDIS_STATUS_FAILURE; } ctx->Initing = TRUE; // Examine whether it has already been initialized if (ctx->Inited != FALSE) { // Driver is started on another instance already. // VPN driver can start only one instance per one service. // User can start multiple drivers with different instance ID return NDIS_STATUS_FAILURE; } // Current value of the packet filter ctx->CurrentPacketFilter = NDIS_PACKET_TYPE_ALL_LOCAL | NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_ALL_FUNCTIONAL; // Initialize the adapter information ctx->NdisMiniport = MiniportAdapterHandle; ctx->NdisContext = ctx; ctx->HardwareStatus = NdisHardwareStatusReady; ctx->Halting = FALSE; ctx->Connected = ctx->ConnectedOld = FALSE; //if (keep_link == false) { ctx->ConnectedForce = TRUE; } // Read the information from the registry if (NeoLoadRegistory() == FALSE) { // Failure ctx->Initing = FALSE; return NDIS_STATUS_FAILURE; } // Register the device attributes NeoZero(&attr, sizeof(attr)); attr.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES; attr.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; attr.Header.Size = sizeof(NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES); attr.AttributeFlags = NDIS_MINIPORT_ATTRIBUTES_NO_HALT_ON_SUSPEND; attr.InterfaceType = NdisInterfaceInternal; attr.MiniportAdapterContext = ctx->NdisContext; NdisMSetMiniportAttributes(ctx->NdisMiniport, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&attr); NeoZero(&pnpcap, sizeof(pnpcap)); NeoZero(&gen, sizeof(gen)); gen.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES; gen.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_2; gen.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_2; gen.MediaType = NdisMedium802_3; gen.PhysicalMediumType = NdisPhysicalMedium802_3; gen.MtuSize = NEO_MAX_PACKET_SIZE_ANNOUNCE - NEO_MIN_PACKET_SIZE; gen.MaxXmitLinkSpeed = gen.MaxRcvLinkSpeed = max_speed; gen.RcvLinkSpeed = gen.XmitLinkSpeed = max_speed; gen.MediaConnectState = MediaConnectStateDisconnected; gen.LookaheadSize = NEO_MAX_PACKET_SIZE_ANNOUNCE - NEO_MIN_PACKET_SIZE; gen.MacOptions = NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | NDIS_MAC_OPTION_NO_LOOPBACK; gen.SupportedPacketFilters = NDIS_PACKET_TYPE_ALL_LOCAL | NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_ALL_FUNCTIONAL; gen.MaxMulticastListSize = NEO_MAX_MULTICASE; gen.MacAddressLength = NEO_MAC_ADDRESS_SIZE; NeoCopy(gen.PermanentMacAddress, ctx->MacAddress, NEO_MAC_ADDRESS_SIZE); NeoCopy(gen.CurrentMacAddress, ctx->MacAddress, NEO_MAC_ADDRESS_SIZE); gen.AccessType = NET_IF_ACCESS_BROADCAST; gen.DirectionType = NET_IF_DIRECTION_SENDRECEIVE; gen.ConnectionType = NET_IF_CONNECTION_DEDICATED; gen.IfType = IF_TYPE_ETHERNET_CSMACD; gen.IfConnectorPresent = TRUE; gen.SupportedStatistics = NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV | NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV | NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS | NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT | NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT | NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR | NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT; gen.SupportedPauseFunctions = NdisPauseFunctionsUnsupported; gen.AutoNegotiationFlags = NDIS_LINK_STATE_XMIT_LINK_SPEED_AUTO_NEGOTIATED | NDIS_LINK_STATE_RCV_LINK_SPEED_AUTO_NEGOTIATED | NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED | NDIS_LINK_STATE_PAUSE_FUNCTIONS_AUTO_NEGOTIATED; gen.SupportedOidList = SupportedOids; gen.SupportedOidListLength = sizeof(SupportedOids); NeoZero(&pnpcap, sizeof(pnpcap)); pnpcap.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; pnpcap.Header.Revision = NDIS_PM_CAPABILITIES_REVISION_1; pnpcap.Header.Size = NDIS_SIZEOF_NDIS_PM_CAPABILITIES_REVISION_1; pnpcap.MinMagicPacketWakeUp = NdisDeviceStateUnspecified; pnpcap.MinPatternWakeUp = NdisDeviceStateUnspecified; pnpcap.MinLinkChangeWakeUp = NdisDeviceStateUnspecified; gen.PowerManagementCapabilitiesEx = &pnpcap; NdisMSetMiniportAttributes(ctx->NdisMiniport, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&gen); // Initialize the received packet array NeoInitPacketArray(); // Initialize the control device NeoInitControlDevice(); // Start the adapter NeoStartAdapter(); // Flag setting ctx->Initing = FALSE; ctx->Inited = TRUE; // Notify the connection state NeoSetConnectState(FALSE); return NDIS_STATUS_SUCCESS; }
// Information acquisition handler of adapter NDIS_STATUS NeoNdisQuery(NDIS_HANDLE MiniportAdapterContext, NDIS_OID Oid, void *InformationBuffer, ULONG InformationBufferLength, ULONG *BytesWritten, ULONG *BytesNeeded) { NDIS_MEDIUM media; void *buf; UINT value32; USHORT value16; UINT size; if (ctx == NULL) { return NDIS_STATUS_FAILURE; } // Initialization size = sizeof(UINT); value32 = value16 = 0; buf = &value32; // Branch processing switch (Oid) { case OID_GEN_SUPPORTED_LIST: // Return a list of supported OID buf = SupportedOids; size = sizeof(SupportedOids); break; case OID_GEN_MAC_OPTIONS: // Ethernet option value32 = NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | NDIS_MAC_OPTION_RECEIVE_SERIALIZED | NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | NDIS_MAC_OPTION_NO_LOOPBACK; break; case OID_GEN_HARDWARE_STATUS: // Hardware state buf = &ctx->HardwareStatus; size = sizeof(NDIS_HARDWARE_STATUS); break; case OID_GEN_MEDIA_SUPPORTED: case OID_GEN_MEDIA_IN_USE: // Type of media media = NdisMedium802_3; buf = &media; size = sizeof(NDIS_MEDIUM); break; case OID_GEN_CURRENT_LOOKAHEAD: case OID_GEN_MAXIMUM_LOOKAHEAD: // Available look-ahead size value32 = NEO_MAX_PACKET_SIZE_ANNOUNCE - NEO_MIN_PACKET_SIZE; break; case OID_GEN_MAXIMUM_FRAME_SIZE: // Maximum frame size value32 = NEO_MAX_PACKET_SIZE_ANNOUNCE - NEO_MIN_PACKET_SIZE; break; case OID_GEN_MAXIMUM_TOTAL_SIZE: case OID_GEN_TRANSMIT_BLOCK_SIZE: case OID_GEN_RECEIVE_BLOCK_SIZE: // Maximum packet size value32 = NEO_MAX_PACKET_SIZE_ANNOUNCE; break; case OID_GEN_TRANSMIT_BUFFER_SPACE: case OID_GEN_RECEIVE_BUFFER_SPACE: // Buffer size value32 = NEO_MAX_PACKET_SIZE_ANNOUNCE * NEO_MAX_PACKET_EXCHANGE; break; case OID_GEN_LINK_SPEED: // Communication speed value32 = max_speed; break; case OID_GEN_VENDOR_ID: // Vendor ID NeoCopy(&value32, ctx->MacAddress, 3); value32 &= 0xFFFFFF00; value32 |= 0x01; break; case OID_GEN_VENDOR_DESCRIPTION: // Hardware ID buf = ctx->HardwarePrintableID; size = (UINT)strlen(ctx->HardwarePrintableID) + 1; break; case OID_GEN_DRIVER_VERSION: // Driver version value16 = ((USHORT)NEO_NDIS_MAJOR_VERSION << 8) | NEO_NDIS_MINOR_VERSION; buf = &value16; size = sizeof(USHORT); break; case OID_GEN_VENDOR_DRIVER_VERSION: // Vendor driver version value16 = ((USHORT)NEO_NDIS_MAJOR_VERSION << 8) | NEO_NDIS_MINOR_VERSION; buf = &value16; size = sizeof(USHORT); break; case OID_802_3_PERMANENT_ADDRESS: case OID_802_3_CURRENT_ADDRESS: // MAC address buf = ctx->MacAddress; size = NEO_MAC_ADDRESS_SIZE; break; case OID_802_3_MAXIMUM_LIST_SIZE: // Number of multicast value32 = NEO_MAX_MULTICASE; break; case OID_GEN_MAXIMUM_SEND_PACKETS: // Number of packets that can be sent at a time value32 = NEO_MAX_PACKET_EXCHANGE; break; case OID_GEN_XMIT_OK: // Number of packets sent value32 = ctx->Status.NumPacketSend; break; case OID_GEN_RCV_OK: // Number of received packets value32 = ctx->Status.NumPacketRecv; break; case OID_GEN_XMIT_ERROR: // Number of transmission error packets value32 = ctx->Status.NumPacketSendError; break; case OID_GEN_RCV_ERROR: // Number of error packets received value32 = ctx->Status.NumPacketRecvError; break; case OID_GEN_RCV_NO_BUFFER: // Number of reception buffer shortage occurrences value32 = ctx->Status.NumPacketRecvNoBuffer; break; case OID_802_3_RCV_ERROR_ALIGNMENT: // Number of errors value32 = 0; break; case OID_GEN_MEDIA_CONNECT_STATUS: // Cable connection state NeoCheckConnectState(); if (keep_link == false) { value32 = ctx->Connected ? NdisMediaStateConnected : NdisMediaStateDisconnected; } else { value32 = NdisMediaStateConnected; } break; case OID_802_3_XMIT_ONE_COLLISION: case OID_802_3_XMIT_MORE_COLLISIONS: // Number of collisions value32 = 0; break; case OID_GEN_CURRENT_PACKET_FILTER: // Current settings of the packet filter value32 = ctx->CurrentPacketFilter; break; /* case OID_GEN_PROTOCOL_OPTIONS: // Current value of the protocol option value32 = ctx->CurrentProtocolOptions; break;*/ default: // Unknown OID *BytesWritten = 0; return NDIS_STATUS_INVALID_OID; } if (size > InformationBufferLength) { // Undersize *BytesNeeded = size; *BytesWritten = 0; return NDIS_STATUS_INVALID_LENGTH; } // Data copy NeoCopy(InformationBuffer, buf, size); *BytesWritten = size; return NDIS_STATUS_SUCCESS; }
// Read the information from the registry BOOL NeoLoadRegistory() { void *buf; NDIS_STATUS ret; UINT size; NDIS_HANDLE config; NDIS_CONFIGURATION_PARAMETER *param; UNICODE *name; ANSI_STRING ansi; UNICODE_STRING *unicode; UINT speed; BOOL keep; // Get the config handle NdisOpenConfiguration(&ret, &config, ctx->NdisConfig); if (NG(ret)) { // Failure return FALSE; } // Read the MAC address NdisReadNetworkAddress(&ret, &buf, &size, config); if (NG(ret)) { // Failure NdisCloseConfiguration(config); return FALSE; } // Copy the MAC address if (size != NEO_MAC_ADDRESS_SIZE) { // Invalid size NdisCloseConfiguration(config); return FALSE; } NeoCopy(ctx->MacAddress, buf, NEO_MAC_ADDRESS_SIZE); if (ctx->MacAddress[0] == 0x00 && ctx->MacAddress[1] == 0x00 && ctx->MacAddress[2] == 0x01 && ctx->MacAddress[3] == 0x00 && ctx->MacAddress[4] == 0x00 && ctx->MacAddress[5] == 0x01) { // Special MAC address UINT ptr32 = (UINT)((UINT64)ctx); ctx->MacAddress[0] = 0x00; ctx->MacAddress[1] = 0xAD; ctx->MacAddress[2] = ((UCHAR *)(&ptr32))[0]; ctx->MacAddress[3] = ((UCHAR *)(&ptr32))[1]; ctx->MacAddress[4] = ((UCHAR *)(&ptr32))[2]; ctx->MacAddress[5] = ((UCHAR *)(&ptr32))[3]; } // Initialize the key name of the device name name = NewUnicode("MatchingDeviceId"); // Read the hardware ID NdisReadConfiguration(&ret, ¶m, config, GetUnicode(name), NdisParameterString); FreeUnicode(name); if (NG(ret)) { // Failure NdisCloseConfiguration(config); return FALSE; } // Type checking if (param->ParameterType != NdisParameterString) { // Failure NdisCloseConfiguration(config); return FALSE; } unicode = ¶m->ParameterData.StringData; // Prepare a buffer for ANSI string NeoZero(&ansi, sizeof(ANSI_STRING)); ansi.MaximumLength = MAX_SIZE - 1; ansi.Buffer = NeoZeroMalloc(MAX_SIZE); // Convert to ANSI string NdisUnicodeStringToAnsiString(&ansi, unicode); // Copy strcpy(ctx->HardwareID, ansi.Buffer); strcpy(ctx->HardwareID_Raw, ctx->HardwareID); // Convert to upper case _strupr(ctx->HardwareID); // Release the memory NeoFree(ansi.Buffer); // Read the bit rate name = NewUnicode("MaxSpeed"); NdisReadConfiguration(&ret, ¶m, config, GetUnicode(name), NdisParameterInteger); FreeUnicode(name); if (NG(ret) || param->ParameterType != NdisParameterInteger) { speed = NEO_MAX_SPEED_DEFAULT; } else { speed = param->ParameterData.IntegerData * 10000; } max_speed = speed; // Read the link keeping flag name = NewUnicode("KeepLink"); NdisReadConfiguration(&ret, ¶m, config, GetUnicode(name), NdisParameterInteger); FreeUnicode(name); if (NG(ret) || param->ParameterType != NdisParameterInteger) { keep = false; } else { keep = (param->ParameterData.IntegerData == 0 ? false : true); } keep_link = keep; // Close the Config handle NdisCloseConfiguration(config); return TRUE; }
// Packet send handler void NeoNdisSendPackets(NDIS_HANDLE MiniportAdapterContext, NDIS_PACKET **PacketArray, UINT NumberOfPackets) { UCHAR *Buf,*BufCopy; PNDIS_BUFFER Buffer; UCHAR *Tmp; UINT PacketLength; UINT CurrentLength; UINT i; if (ctx == NULL) { return; } // Update the connection state NeoCheckConnectState(); if (NumberOfPackets == 0) { // The number of packets is 0 return; } if (NeoNdisSendPacketsHaltCheck(PacketArray, NumberOfPackets) == FALSE) { // Device is stopped return; } // Operation of the packet queue NeoLockPacketQueue(); { if (NeoNdisSendPacketsHaltCheck(PacketArray, NumberOfPackets) == FALSE) { // Device is stopped NeoUnlockPacketQueue(); return; } // Place the packet in the queue in order for (i = 0;i < NumberOfPackets;i++) { // Get a packet NdisQueryPacket(PacketArray[i], NULL, NULL, &Buffer, &PacketLength); // Extract the packet. // Memory allocated here is used for the queue and is released at the time of releasing the queue. Buf = NeoMalloc(PacketLength); BufCopy = Buf; while (Buffer) { NdisQueryBuffer(Buffer, &Tmp, &CurrentLength); if (CurrentLength == 0) { // Complete break; } NeoCopy(BufCopy, Tmp, CurrentLength); BufCopy += CurrentLength; NdisGetNextBuffer(Buffer, &Buffer); } // Process this packet if (PacketLength > NEO_MIN_PACKET_SIZE) { if (PacketLength > NEO_MAX_PACKET_SIZE) { // Packet is too large NDIS_SET_PACKET_STATUS(PacketArray[i], NDIS_STATUS_FAILURE); if (g_is_win8) { NdisMSendComplete(ctx->NdisMiniport, PacketArray[i], NDIS_STATUS_FAILURE); } ctx->Status.NumPacketSendError++; NeoFree(Buf); } else { // Insert the packet into the queue NeoInsertQueue(Buf, PacketLength); NDIS_SET_PACKET_STATUS(PacketArray[i], NDIS_STATUS_SUCCESS); if (g_is_win8) { NdisMSendComplete(ctx->NdisMiniport, PacketArray[i], NDIS_STATUS_SUCCESS); } ctx->Status.NumPacketSend++; } } else { // Release if the packet doesn't contain data NDIS_SET_PACKET_STATUS(PacketArray[i], NDIS_STATUS_SUCCESS); if (g_is_win8) { NdisMSendComplete(ctx->NdisMiniport, PacketArray[i], NDIS_STATUS_SUCCESS); } NeoFree(Buf); } } } NeoUnlockPacketQueue(); // Reception event NeoSet(ctx->Event); }
// Information acquisition handler of adapter NDIS_STATUS NeoNdisQuery(NDIS_HANDLE MiniportAdapterContext, NDIS_OID Oid, void *InformationBuffer, ULONG InformationBufferLength, ULONG *BytesWritten, ULONG *BytesNeeded) { NDIS_MEDIUM media; void *buf; UINT value32; USHORT value16; UINT size; NDIS_STATISTICS_INFO stat; NDIS_INTERRUPT_MODERATION_PARAMETERS intp; if (ctx == NULL) { return NDIS_STATUS_FAILURE; } // Initialization size = sizeof(UINT); value32 = value16 = 0; buf = &value32; // Branch processing switch (Oid) { case OID_GEN_SUPPORTED_LIST: // Return a list of supported OID buf = SupportedOids; size = sizeof(SupportedOids); break; case OID_GEN_MAC_OPTIONS: // Ethernet option value32 = NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | NDIS_MAC_OPTION_RECEIVE_SERIALIZED | NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | NDIS_MAC_OPTION_NO_LOOPBACK; break; case OID_GEN_HARDWARE_STATUS: // Hardware state buf = &ctx->HardwareStatus; size = sizeof(NDIS_HARDWARE_STATUS); break; case OID_GEN_MEDIA_SUPPORTED: case OID_GEN_MEDIA_IN_USE: // Type of media media = NdisMedium802_3; buf = &media; size = sizeof(NDIS_MEDIUM); break; case OID_GEN_CURRENT_LOOKAHEAD: case OID_GEN_MAXIMUM_LOOKAHEAD: // Read-ahead available size value32 = NEO_MAX_PACKET_SIZE_ANNOUNCE - NEO_MIN_PACKET_SIZE; break; case OID_GEN_MAXIMUM_FRAME_SIZE: // Maximum frame size value32 = NEO_MAX_PACKET_SIZE_ANNOUNCE - NEO_MIN_PACKET_SIZE; break; case OID_GEN_MAXIMUM_TOTAL_SIZE: case OID_GEN_TRANSMIT_BLOCK_SIZE: case OID_GEN_RECEIVE_BLOCK_SIZE: // Maximum packet size value32 = NEO_MAX_PACKET_SIZE_ANNOUNCE; break; case OID_GEN_TRANSMIT_BUFFER_SPACE: case OID_GEN_RECEIVE_BUFFER_SPACE: // Buffer size value32 = NEO_MAX_PACKET_SIZE_ANNOUNCE * NEO_MAX_PACKET_EXCHANGE; break; case OID_GEN_LINK_SPEED: // Communication speed value32 = (UINT)(max_speed / 100); break; case OID_GEN_VENDOR_ID: // Vendor ID NeoCopy(&value32, ctx->MacAddress, 3); value32 &= 0xFFFFFF00; value32 |= 0x01; break; case OID_GEN_VENDOR_DESCRIPTION: // Hardware ID buf = ctx->HardwarePrintableID; size = (UINT)strlen(ctx->HardwarePrintableID) + 1; break; case OID_GEN_DRIVER_VERSION: // Driver version value16 = ((USHORT)NEO_NDIS_MAJOR_VERSION << 8) | NEO_NDIS_MINOR_VERSION; buf = &value16; size = sizeof(USHORT); break; case OID_GEN_VENDOR_DRIVER_VERSION: // Vendor driver version value16 = ((USHORT)NEO_NDIS_MAJOR_VERSION << 8) | NEO_NDIS_MINOR_VERSION; buf = &value16; size = sizeof(USHORT); break; case OID_802_3_PERMANENT_ADDRESS: case OID_802_3_CURRENT_ADDRESS: // MAC address buf = ctx->MacAddress; size = NEO_MAC_ADDRESS_SIZE; break; case OID_802_3_MAXIMUM_LIST_SIZE: // Number of multicast value32 = NEO_MAX_MULTICASE; break; case OID_GEN_MAXIMUM_SEND_PACKETS: // Number of packets that can be sent at a time value32 = NEO_MAX_PACKET_EXCHANGE; break; case OID_GEN_XMIT_OK: // Number of packets sent value32 = ctx->Status.NumPacketSend; break; case OID_GEN_RCV_OK: // Number of received packets value32 = ctx->Status.NumPacketRecv; break; case OID_GEN_XMIT_ERROR: // Number of transmission error packets value32 = ctx->Status.NumPacketSendError; break; case OID_GEN_RCV_ERROR: // Number of error packets received value32 = ctx->Status.NumPacketRecvError; break; case OID_GEN_RCV_NO_BUFFER: // Number of reception buffer shortage occurrences value32 = ctx->Status.NumPacketRecvNoBuffer; break; case OID_802_3_RCV_ERROR_ALIGNMENT: // Number of errors value32 = 0; break; case OID_GEN_MEDIA_CONNECT_STATUS: // Cable connection state NeoCheckConnectState(); if (keep_link == false) { value32 = ctx->Connected ? NdisMediaStateConnected : NdisMediaStateDisconnected; } else { value32 = NdisMediaStateConnected; } break; case OID_802_3_XMIT_ONE_COLLISION: case OID_802_3_XMIT_MORE_COLLISIONS: // Number of collisions value32 = 0; break; case OID_GEN_CURRENT_PACKET_FILTER: // Current settings of the packet filter value32 = ctx->CurrentPacketFilter; break; /* case OID_GEN_PROTOCOL_OPTIONS: // Current value of the protocol option value32 = ctx->CurrentProtocolOptions; break;*/ case OID_GEN_STATISTICS: // Statistics (NDIS 6.0) NeoZero(&stat, sizeof(stat)); buf = &stat; size = sizeof(stat); stat.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; stat.Header.Revision = NDIS_STATISTICS_INFO_REVISION_1; stat.Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1; stat.SupportedStatistics = NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV | NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV | NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS | NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT | NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT | NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR | NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT; stat.ifInErrors = ctx->Status.Int64NumRecvError; stat.ifHCInOctets = ctx->Status.Int64BytesRecvTotal; stat.ifHCInUcastPkts = ctx->Status.Int64NumRecvUnicast; stat.ifHCInBroadcastPkts = ctx->Status.Int64NumRecvBroadcast; stat.ifHCOutOctets = ctx->Status.Int64BytesSendTotal; stat.ifHCOutUcastPkts = ctx->Status.Int64NumSendUnicast; stat.ifHCOutBroadcastPkts = ctx->Status.Int64NumSendBroadcast; stat.ifOutErrors = ctx->Status.Int64NumSendError; stat.ifHCInUcastOctets = ctx->Status.Int64BytesRecvUnicast; stat.ifHCInBroadcastOctets = ctx->Status.Int64BytesRecvBroadcast; stat.ifHCOutUcastOctets = ctx->Status.Int64BytesSendUnicast; stat.ifHCOutBroadcastOctets = ctx->Status.Int64BytesSendBroadcast; break; case OID_GEN_INTERRUPT_MODERATION: // Interrupt Moderation (NDIS 6.0) NeoZero(&intp, sizeof(intp)); buf = &intp; size = sizeof(intp); intp.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; intp.Header.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1; intp.Header.Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1; intp.InterruptModeration = NdisInterruptModerationNotSupported; break; default: // Unknown OID *BytesWritten = 0; return NDIS_STATUS_INVALID_OID; } if (size > InformationBufferLength) { // Undersize *BytesNeeded = size; *BytesWritten = 0; return NDIS_STATUS_INVALID_LENGTH; } // Data copy NeoCopy(InformationBuffer, buf, size); *BytesWritten = size; return NDIS_STATUS_SUCCESS; }
// Packet send handler void NeoNdisSendNetBufferLists(NDIS_HANDLE MiniportAdapterContext, NET_BUFFER_LIST *NetBufferLists, NDIS_PORT_NUMBER PortNumber, ULONG SendFlags) { if (ctx == NULL) { return; } // Update the connection state NeoCheckConnectState(); if (NeoNdisSendPacketsHaltCheck(NetBufferLists) == FALSE) { // Device is stopped return; } // Operation of the packet queue NeoLockPacketQueue(); { NET_BUFFER_LIST *nbl; if (NeoNdisSendPacketsHaltCheck(NetBufferLists) == FALSE) { // Device is stopped NeoUnlockPacketQueue(); return; } nbl = NetBufferLists; while (nbl != NULL) { NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl); while (nb != NULL) { UINT size = NET_BUFFER_DATA_LENGTH(nb); if (size >= NEO_MIN_PACKET_SIZE && size <= NEO_MAX_PACKET_SIZE) { UCHAR *buf = NeoMalloc(size); void *ptr; ptr = NdisGetDataBuffer(nb, size, buf, 1, 0); if (ptr == NULL) { ctx->Status.NumPacketSendError++; ctx->Status.Int64NumSendError++; NeoFree(buf); } else { if (ptr != buf) { NeoCopy(buf, ptr, size); } NeoInsertQueue(buf, size); ctx->Status.NumPacketSend++; if (buf[0] & 0x40) { ctx->Status.Int64NumSendBroadcast++; ctx->Status.Int64BytesSendBroadcast += (UINT64)size; } else { ctx->Status.Int64NumSendUnicast++; ctx->Status.Int64BytesSendUnicast += (UINT64)size; } ctx->Status.Int64BytesSendTotal += (UINT64)size; } } else { ctx->Status.NumPacketSendError++; ctx->Status.Int64NumSendError++; } nb = NET_BUFFER_NEXT_NB(nb); } nbl = NET_BUFFER_LIST_NEXT_NBL(nbl); } } NeoUnlockPacketQueue(); // Notify the transmission completion NdisMSendNetBufferListsComplete(ctx->NdisMiniport, NetBufferLists, NDIS_STATUS_SUCCESS); // Reception event NeoSet(ctx->Event); }