diff --git a/reactos/base/applications/network/CMakeLists.txt b/reactos/base/applications/network/CMakeLists.txt
index 02eb61db45a..b7f2d0ea652 100644
--- a/reactos/base/applications/network/CMakeLists.txt
+++ b/reactos/base/applications/network/CMakeLists.txt
@@ -14,3 +14,5 @@ if(NOT MSVC)
endif()
add_subdirectory(tracert)
add_subdirectory(whois)
+add_subdirectory(wlanconf)
+
diff --git a/reactos/base/applications/network/network.rbuild b/reactos/base/applications/network/network.rbuild
index 61109ec8bd7..13b9a537328 100644
--- a/reactos/base/applications/network/network.rbuild
+++ b/reactos/base/applications/network/network.rbuild
@@ -40,4 +40,7 @@
+
+
+
diff --git a/reactos/base/applications/network/wlanconf/CMakeLists.txt b/reactos/base/applications/network/wlanconf/CMakeLists.txt
new file mode 100644
index 00000000000..35938d4bcd4
--- /dev/null
+++ b/reactos/base/applications/network/wlanconf/CMakeLists.txt
@@ -0,0 +1,8 @@
+
+include_directories(
+ BEFORE include
+ ${REACTOS_SOURCE_DIR}/include/reactos/drivers/ndisuio)
+add_executable(wlanconf wlanconf.c wlanconf.rc)
+set_module_type(wlanconf win32cui)
+add_importlibs(wlanconf msvcrt iphlpapi kernel32)
+add_cd_file(TARGET wlanconf DESTINATION reactos/system32 FOR all)
diff --git a/reactos/base/applications/network/wlanconf/wlanconf.c b/reactos/base/applications/network/wlanconf/wlanconf.c
new file mode 100644
index 00000000000..15e351de6cd
--- /dev/null
+++ b/reactos/base/applications/network/wlanconf/wlanconf.c
@@ -0,0 +1,969 @@
+/*
+ * PROJECT: ReactOS WLAN command-line configuration utility
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: base/applications/network/wlanconf/wlanconf.c
+ * PURPOSE: Allows WLAN configuration via the command prompt
+ * COPYRIGHT: Copyright 2012 Cameron Gutman (cameron.gutman@reactos.org)
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+BOOL bScan = FALSE;
+
+BOOL bConnect = FALSE;
+char* sSsid = NULL;
+char* sWepKey = NULL;
+BOOL bAdhoc = FALSE;
+
+BOOL bDisconnect = FALSE;
+
+DWORD DoFormatMessage(DWORD ErrorCode)
+{
+ LPVOID lpMsgBuf;
+ DWORD RetVal;
+
+ if ((RetVal = FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ ErrorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL )))
+ {
+ _tprintf(_T("%s"), (LPTSTR)lpMsgBuf);
+
+ LocalFree(lpMsgBuf);
+
+ /* return number of TCHAR's stored in output buffer
+ * excluding '\0' - as FormatMessage does*/
+ return RetVal;
+ }
+ else
+ return 0;
+}
+
+HANDLE
+OpenDriverHandle(VOID)
+{
+ HANDLE hDriver;
+ DWORD dwBytesReturned;
+ BOOL bSuccess;
+
+ /* Open a handle to the NDISUIO driver */
+ hDriver = CreateFileW(NDISUIO_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hDriver == INVALID_HANDLE_VALUE)
+ return INVALID_HANDLE_VALUE;
+
+ /* Wait for binds */
+ bSuccess = DeviceIoControl(hDriver,
+ IOCTL_NDISUIO_BIND_WAIT,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &dwBytesReturned,
+ NULL);
+ if (!bSuccess)
+ {
+ CloseHandle(hDriver);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ return hDriver;
+}
+
+BOOL
+IsWlanAdapter(HANDLE hAdapter)
+{
+ BOOL bSuccess;
+ DWORD dwBytesReturned;
+ NDISUIO_QUERY_OID QueryOid;
+
+ /* WLAN drivers must support this OID */
+ QueryOid.Oid = OID_GEN_PHYSICAL_MEDIUM;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_QUERY_OID_VALUE,
+ &QueryOid,
+ sizeof(QueryOid),
+ &QueryOid,
+ sizeof(QueryOid),
+ &dwBytesReturned,
+ NULL);
+ if (!bSuccess || *(PULONG)QueryOid.Data != NdisPhysicalMediumWirelessLan)
+ return FALSE;
+
+ return TRUE;
+}
+
+BOOL
+OpenAdapterHandle(DWORD Index, HANDLE *hAdapter, IP_ADAPTER_INDEX_MAP *IpInfo)
+{
+ HANDLE hDriver;
+ BOOL bSuccess;
+ DWORD dwBytesReturned;
+ DWORD QueryBindingSize = sizeof(NDISUIO_QUERY_BINDING) + (1024 * sizeof(WCHAR));
+ PNDISUIO_QUERY_BINDING QueryBinding;
+ DWORD dwStatus, dwSize, i;
+ PIP_INTERFACE_INFO InterfaceInfo = NULL;
+
+ /* Open the driver handle */
+ hDriver = OpenDriverHandle();
+ if (hDriver == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ /* Allocate the binding struct */
+ QueryBinding = HeapAlloc(GetProcessHeap(), 0, QueryBindingSize);
+ if (!QueryBinding)
+ {
+ CloseHandle(hDriver);
+ return FALSE;
+ }
+
+ /* Query the adapter binding information */
+ QueryBinding->BindingIndex = Index;
+ bSuccess = DeviceIoControl(hDriver,
+ IOCTL_NDISUIO_QUERY_BINDING,
+ QueryBinding,
+ QueryBindingSize,
+ QueryBinding,
+ QueryBindingSize,
+ &dwBytesReturned,
+ NULL);
+
+ if (!bSuccess)
+ {
+ HeapFree(GetProcessHeap(), 0, QueryBinding);
+ CloseHandle(hDriver);
+ return FALSE;
+ }
+
+ /* Bind to the adapter */
+ bSuccess = DeviceIoControl(hDriver,
+ IOCTL_NDISUIO_OPEN_DEVICE,
+ (PUCHAR)QueryBinding + QueryBinding->DeviceNameOffset,
+ QueryBinding->DeviceNameLength,
+ NULL,
+ 0,
+ &dwBytesReturned,
+ NULL);
+
+ if (!bSuccess)
+ {
+ HeapFree(GetProcessHeap(), 0, QueryBinding);
+ CloseHandle(hDriver);
+ return FALSE;
+ }
+
+ /* Get interface info from the IP helper */
+ dwSize = sizeof(IP_INTERFACE_INFO);
+ do {
+ if (InterfaceInfo) HeapFree(GetProcessHeap(), 0, InterfaceInfo);
+ InterfaceInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(IP_INTERFACE_INFO));
+ if (!InterfaceInfo)
+ {
+ HeapFree(GetProcessHeap(), 0, QueryBinding);
+ CloseHandle(hDriver);
+ return FALSE;
+ }
+ dwStatus = GetInterfaceInfo(InterfaceInfo, &dwSize);
+ } while (dwStatus == ERROR_INSUFFICIENT_BUFFER);
+
+ if (dwStatus != NO_ERROR)
+ {
+ HeapFree(GetProcessHeap(), 0, QueryBinding);
+ HeapFree(GetProcessHeap(), 0, InterfaceInfo);
+ return FALSE;
+ }
+
+ for (i = 0; i < InterfaceInfo->NumAdapters; i++)
+ {
+ if (wcsstr((PWCHAR)((PUCHAR)QueryBinding + QueryBinding->DeviceNameOffset),
+ InterfaceInfo->Adapter[i].Name))
+ {
+ *IpInfo = InterfaceInfo->Adapter[i];
+ *hAdapter = hDriver;
+
+ HeapFree(GetProcessHeap(), 0, QueryBinding);
+ HeapFree(GetProcessHeap(), 0, InterfaceInfo);
+
+ return TRUE;
+ }
+ }
+
+ HeapFree(GetProcessHeap(), 0, QueryBinding);
+ HeapFree(GetProcessHeap(), 0, InterfaceInfo);
+ CloseHandle(hDriver);
+
+ return FALSE;
+}
+
+/* Only works with the first adapter for now */
+BOOL
+OpenWlanAdapter(HANDLE *hAdapter, IP_ADAPTER_INDEX_MAP *IpInfo)
+{
+ DWORD dwCurrentIndex;
+
+ for (dwCurrentIndex = 0; ; dwCurrentIndex++)
+ {
+ if (!OpenAdapterHandle(dwCurrentIndex, hAdapter, IpInfo))
+ break;
+
+ if (IsWlanAdapter(*hAdapter))
+ return TRUE;
+ else
+ CloseHandle(*hAdapter);
+ }
+
+ return FALSE;
+}
+
+BOOL
+WlanDisconnect(HANDLE hAdapter, PIP_ADAPTER_INDEX_MAP IpInfo)
+{
+ BOOL bSuccess;
+ DWORD dwBytesReturned;
+ NDISUIO_SET_OID SetOid;
+
+ /* Release this IP address */
+ IpReleaseAddress(IpInfo);
+
+ /* Disassociate from the AP */
+ SetOid.Oid = OID_802_11_DISASSOCIATE;
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_SET_OID_VALUE,
+ &SetOid,
+ sizeof(SetOid),
+ NULL,
+ 0,
+ &dwBytesReturned,
+ NULL);
+ if (!bSuccess)
+ return FALSE;
+
+ _tprintf(_T("The operation completed successfully.\n"));
+ return TRUE;
+}
+
+static
+UCHAR
+CharToHex(CHAR Char)
+{
+ Char = toupper(Char);
+
+ switch (Char)
+ {
+ case '0':
+ return 0x0;
+ case '1':
+ return 0x1;
+ case '2':
+ return 0x2;
+ case '3':
+ return 0x3;
+ case '4':
+ return 0x4;
+ case '5':
+ return 0x5;
+ case '6':
+ return 0x6;
+ case '7':
+ return 0x7;
+ case '8':
+ return 0x8;
+ case '9':
+ return 0x9;
+ case 'A':
+ return 0xA;
+ case 'B':
+ return 0xB;
+ case 'C':
+ return 0xC;
+ case 'D':
+ return 0xD;
+ case 'E':
+ return 0xE;
+ case 'F':
+ return 0xF;
+ default:
+ return 0;
+ }
+}
+
+BOOL
+WlanPrintCurrentStatus(HANDLE hAdapter)
+{
+ PNDISUIO_QUERY_OID QueryOid;
+ DWORD QueryOidSize;
+ BOOL bSuccess;
+ DWORD dwBytesReturned;
+ PNDIS_802_11_SSID SsidInfo;
+ CHAR SsidBuffer[NDIS_802_11_LENGTH_SSID + 1];
+ DWORD i;
+
+ QueryOidSize = FIELD_OFFSET(NDISUIO_QUERY_OID, Data) + sizeof(NDIS_802_11_SSID);
+ QueryOid = HeapAlloc(GetProcessHeap(), 0, QueryOidSize);
+ if (!QueryOid)
+ return FALSE;
+
+ QueryOid->Oid = OID_802_11_SSID;
+ SsidInfo = (PNDIS_802_11_SSID)QueryOid->Data;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_QUERY_OID_VALUE,
+ QueryOid,
+ QueryOidSize,
+ QueryOid,
+ QueryOidSize,
+ &dwBytesReturned,
+ NULL);
+ if (!bSuccess)
+ {
+ HeapFree(GetProcessHeap(), 0, QueryOid);
+ return FALSE;
+ }
+
+ /* Copy the SSID to our internal buffer and terminate it */
+ RtlCopyMemory(SsidBuffer, SsidInfo->Ssid, SsidInfo->SsidLength);
+ SsidBuffer[SsidInfo->SsidLength] = 0;
+
+ HeapFree(GetProcessHeap(), 0, QueryOid);
+ QueryOidSize = FIELD_OFFSET(NDISUIO_QUERY_OID, Data) + sizeof(NDIS_802_11_MAC_ADDRESS);
+ QueryOid = HeapAlloc(GetProcessHeap(), 0, QueryOidSize);
+ if (!QueryOid)
+ return FALSE;
+
+ QueryOid->Oid = OID_802_11_BSSID;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_QUERY_OID_VALUE,
+ QueryOid,
+ QueryOidSize,
+ QueryOid,
+ QueryOidSize,
+ &dwBytesReturned,
+ NULL);
+ if (SsidInfo->SsidLength == 0 || !bSuccess)
+ {
+ _tprintf(_T("\nWLAN disconnected\n"));
+ HeapFree(GetProcessHeap(), 0, QueryOid);
+ return TRUE;
+ }
+ else
+ {
+ _tprintf(_T("\nCurrent wireless configuration information:\n\n"));
+ }
+
+ _tprintf(_T("SSID: %s\n"), SsidBuffer);
+
+ _tprintf(_T("BSSID: "));
+ for (i = 0; i < sizeof(NDIS_802_11_MAC_ADDRESS); i++)
+ {
+ UINT BssidData = QueryOid->Data[i];
+
+ _tprintf(_T("%.2x"), BssidData);
+
+ if (i != sizeof(NDIS_802_11_MAC_ADDRESS) - 1)
+ _tprintf(_T(":"));
+ }
+ _tprintf(_T("\n"));
+
+ HeapFree(GetProcessHeap(), 0, QueryOid);
+ QueryOidSize = sizeof(NDISUIO_QUERY_OID);
+ QueryOid = HeapAlloc(GetProcessHeap(), 0, QueryOidSize);
+ if (!QueryOid)
+ return FALSE;
+
+ QueryOid->Oid = OID_802_11_INFRASTRUCTURE_MODE;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_QUERY_OID_VALUE,
+ QueryOid,
+ QueryOidSize,
+ QueryOid,
+ QueryOidSize,
+ &dwBytesReturned,
+ NULL);
+ if (!bSuccess)
+ {
+ HeapFree(GetProcessHeap(), 0, QueryOid);
+ return FALSE;
+ }
+
+ _tprintf(_T("Network mode: %s\n"), (*(PUINT)QueryOid->Data == Ndis802_11IBSS) ? "Adhoc" : "Infrastructure");
+
+ QueryOid->Oid = OID_802_11_WEP_STATUS;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_QUERY_OID_VALUE,
+ QueryOid,
+ QueryOidSize,
+ QueryOid,
+ QueryOidSize,
+ &dwBytesReturned,
+ NULL);
+ if (!bSuccess)
+ {
+ HeapFree(GetProcessHeap(), 0, QueryOid);
+ return FALSE;
+ }
+
+ _tprintf(_T("WEP enabled: %s\n"), (*(PUINT)QueryOid->Data == Ndis802_11WEPEnabled) ? "Yes" : "No");
+
+ _tprintf("\n");
+ QueryOid->Oid = OID_802_11_RSSI;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_QUERY_OID_VALUE,
+ QueryOid,
+ QueryOidSize,
+ QueryOid,
+ QueryOidSize,
+ &dwBytesReturned,
+ NULL);
+ if (bSuccess)
+ {
+ /* This OID is optional */
+ _tprintf(_T("RSSI: %i dBm\n"), *(PINT)QueryOid->Data);
+ }
+
+ QueryOid->Oid = OID_802_11_TX_POWER_LEVEL;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_QUERY_OID_VALUE,
+ QueryOid,
+ QueryOidSize,
+ QueryOid,
+ QueryOidSize,
+ &dwBytesReturned,
+ NULL);
+ if (bSuccess)
+ {
+ /* This OID is optional */
+ _tprintf(_T("Transmission power: %d mW\n"), *(PUINT)QueryOid->Data);
+ }
+
+ _tprintf(_T("\n"));
+
+ QueryOid->Oid = OID_802_11_NUMBER_OF_ANTENNAS;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_QUERY_OID_VALUE,
+ QueryOid,
+ QueryOidSize,
+ QueryOid,
+ QueryOidSize,
+ &dwBytesReturned,
+ NULL);
+ if (bSuccess)
+ {
+ /* This OID is optional */
+ _tprintf(_T("Antenna count: %d\n"), *(PUINT)QueryOid->Data);
+ }
+
+ QueryOid->Oid = OID_802_11_TX_ANTENNA_SELECTED;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_QUERY_OID_VALUE,
+ QueryOid,
+ QueryOidSize,
+ QueryOid,
+ QueryOidSize,
+ &dwBytesReturned,
+ NULL);
+ if (bSuccess)
+ {
+ UINT TransmitAntenna = *(PUINT)QueryOid->Data;
+
+ if (TransmitAntenna != 0xFFFFFFFF)
+ _tprintf(_T("Transmit antenna: %d\n"), TransmitAntenna);
+ else
+ _tprintf(_T("Transmit antenna: Any\n"));
+ }
+
+ QueryOid->Oid = OID_802_11_RX_ANTENNA_SELECTED;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_QUERY_OID_VALUE,
+ QueryOid,
+ QueryOidSize,
+ QueryOid,
+ QueryOidSize,
+ &dwBytesReturned,
+ NULL);
+ if (bSuccess)
+ {
+ UINT ReceiveAntenna = *(PUINT)QueryOid->Data;
+
+ if (ReceiveAntenna != 0xFFFFFFFF)
+ _tprintf(_T("Receive antenna: %d\n"), ReceiveAntenna);
+ else
+ _tprintf(_T("Receive antenna: Any\n"));
+ }
+
+ _tprintf(_T("\n"));
+
+ QueryOid->Oid = OID_802_11_FRAGMENTATION_THRESHOLD;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_QUERY_OID_VALUE,
+ QueryOid,
+ QueryOidSize,
+ QueryOid,
+ QueryOidSize,
+ &dwBytesReturned,
+ NULL);
+ if (bSuccess)
+ {
+ /* This OID is optional */
+ _tprintf(_T("Fragmentation threshold: %d bytes\n"), *(PUINT)QueryOid->Data);
+ }
+
+ QueryOid->Oid = OID_802_11_RTS_THRESHOLD;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_QUERY_OID_VALUE,
+ QueryOid,
+ QueryOidSize,
+ QueryOid,
+ QueryOidSize,
+ &dwBytesReturned,
+ NULL);
+ if (bSuccess)
+ {
+ /* This OID is optional */
+ _tprintf(_T("RTS threshold: %d bytes\n"), *(PUINT)QueryOid->Data);
+ }
+
+ HeapFree(GetProcessHeap(), 0, QueryOid);
+
+ _tprintf(_T("\n"));
+ return TRUE;
+}
+
+BOOL
+WlanConnect(HANDLE hAdapter)
+{
+ BOOL bSuccess;
+ DWORD dwBytesReturned, SetOidSize;
+ PNDISUIO_SET_OID SetOid;
+ PNDIS_802_11_SSID Ssid;
+ DWORD i;
+
+ SetOidSize = sizeof(NDISUIO_SET_OID);
+ SetOid = HeapAlloc(GetProcessHeap(), 0, SetOidSize);
+ if (!SetOid)
+ return FALSE;
+
+ /* Set the network mode */
+ SetOid->Oid = OID_802_11_INFRASTRUCTURE_MODE;
+ *(PULONG)SetOid->Data = bAdhoc ? Ndis802_11IBSS : Ndis802_11Infrastructure;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_SET_OID_VALUE,
+ SetOid,
+ SetOidSize,
+ NULL,
+ 0,
+ &dwBytesReturned,
+ NULL);
+ if (!bSuccess)
+ {
+ HeapFree(GetProcessHeap(), 0, SetOid);
+ return FALSE;
+ }
+
+ /* Set the authentication mode */
+ SetOid->Oid = OID_802_11_AUTHENTICATION_MODE;
+ *(PULONG)SetOid->Data = sWepKey ? Ndis802_11AuthModeShared : Ndis802_11AuthModeOpen;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_SET_OID_VALUE,
+ SetOid,
+ SetOidSize,
+ NULL,
+ 0,
+ &dwBytesReturned,
+ NULL);
+ if (!bSuccess)
+ {
+ HeapFree(GetProcessHeap(), 0, SetOid);
+ return FALSE;
+ }
+
+ if (sWepKey)
+ {
+ PNDIS_802_11_WEP WepData;
+
+ HeapFree(GetProcessHeap(), 0, SetOid);
+
+ SetOidSize = FIELD_OFFSET(NDISUIO_SET_OID, Data) +
+ FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial) +
+ (strlen(sWepKey) >> 1);
+ SetOid = HeapAlloc(GetProcessHeap(), 0, SetOidSize);
+ if (!SetOid)
+ return FALSE;
+
+ /* Add the WEP key */
+ SetOid->Oid = OID_802_11_ADD_WEP;
+ WepData = (PNDIS_802_11_WEP)SetOid->Data;
+
+ WepData->KeyIndex = 0x80000000;
+ WepData->KeyLength = strlen(sWepKey) >> 1;
+ WepData->Length = FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial) + WepData->KeyLength;
+
+ /* Assemble the hex key */
+ i = 0;
+ while (sWepKey[i << 1] != '\0')
+ {
+ WepData->KeyMaterial[i] = CharToHex(sWepKey[i << 1]) << 4;
+ WepData->KeyMaterial[i] |= CharToHex(sWepKey[(i << 1) + 1]);
+ i++;
+ }
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_SET_OID_VALUE,
+ SetOid,
+ SetOidSize,
+ NULL,
+ 0,
+ &dwBytesReturned,
+ NULL);
+ if (!bSuccess)
+ {
+ HeapFree(GetProcessHeap(), 0, SetOid);
+ return FALSE;
+ }
+ }
+
+ /* Set the encryption status */
+ SetOid->Oid = OID_802_11_WEP_STATUS;
+ *(PULONG)SetOid->Data = sWepKey ? Ndis802_11WEPEnabled : Ndis802_11WEPDisabled;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_SET_OID_VALUE,
+ SetOid,
+ SetOidSize,
+ NULL,
+ 0,
+ &dwBytesReturned,
+ NULL);
+ if (!bSuccess)
+ {
+ HeapFree(GetProcessHeap(), 0, SetOid);
+ return FALSE;
+ }
+
+ HeapFree(GetProcessHeap(), 0, SetOid);
+ SetOidSize = FIELD_OFFSET(NDISUIO_SET_OID, Data) + sizeof(NDIS_802_11_MAC_ADDRESS);
+ SetOid = HeapAlloc(GetProcessHeap(), 0, SetOidSize);
+ if (!SetOid)
+ return FALSE;
+
+ /* Set the BSSID */
+ SetOid->Oid = OID_802_11_BSSID;
+ RtlFillMemory(SetOid->Data, sizeof(NDIS_802_11_MAC_ADDRESS), 0xFF);
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_SET_OID_VALUE,
+ SetOid,
+ SetOidSize,
+ NULL,
+ 0,
+ &dwBytesReturned,
+ NULL);
+ if (!bSuccess)
+ {
+ HeapFree(GetProcessHeap(), 0, SetOid);
+ return FALSE;
+ }
+
+ HeapFree(GetProcessHeap(), 0, SetOid);
+ SetOidSize = FIELD_OFFSET(NDISUIO_SET_OID, Data) + sizeof(NDIS_802_11_SSID);
+ SetOid = HeapAlloc(GetProcessHeap(), 0, SetOidSize);
+ if (!SetOid)
+ return FALSE;
+
+ /* Finally, set the SSID */
+ SetOid->Oid = OID_802_11_SSID;
+ Ssid = (PNDIS_802_11_SSID)SetOid->Data;
+
+ RtlCopyMemory(Ssid->Ssid, sSsid, strlen(sSsid));
+ Ssid->SsidLength = strlen(sSsid);
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_SET_OID_VALUE,
+ SetOid,
+ SetOidSize,
+ NULL,
+ 0,
+ &dwBytesReturned,
+ NULL);
+
+ HeapFree(GetProcessHeap(), 0, SetOid);
+
+ if (!bSuccess)
+ return FALSE;
+
+ _tprintf(_T("The operation completed successfully.\n"));
+ return TRUE;
+}
+
+BOOL
+WlanScan(HANDLE hAdapter)
+{
+ BOOL bSuccess;
+ DWORD dwBytesReturned;
+ NDISUIO_SET_OID SetOid;
+ PNDISUIO_QUERY_OID QueryOid;
+ DWORD QueryOidSize;
+ PNDIS_802_11_BSSID_LIST BssidList;
+ DWORD i, j;
+
+ SetOid.Oid = OID_802_11_BSSID_LIST_SCAN;
+
+ /* Send the scan OID */
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_SET_OID_VALUE,
+ &SetOid,
+ sizeof(SetOid),
+ NULL,
+ 0,
+ &dwBytesReturned,
+ NULL);
+ if (!bSuccess)
+ return FALSE;
+
+ /* Allocate space for 15 networks to be returned */
+ QueryOidSize = sizeof(NDISUIO_QUERY_OID) + (sizeof(NDIS_WLAN_BSSID) * 15);
+ QueryOid = HeapAlloc(GetProcessHeap(), 0, QueryOidSize);
+ if (!QueryOid)
+ return FALSE;
+
+ QueryOid->Oid = OID_802_11_BSSID_LIST;
+ BssidList = (PNDIS_802_11_BSSID_LIST)QueryOid->Data;
+
+ bSuccess = DeviceIoControl(hAdapter,
+ IOCTL_NDISUIO_QUERY_OID_VALUE,
+ QueryOid,
+ QueryOidSize,
+ QueryOid,
+ QueryOidSize,
+ &dwBytesReturned,
+ NULL);
+ if (!bSuccess)
+ {
+ HeapFree(GetProcessHeap(), 0, QueryOid);
+ return FALSE;
+ }
+
+ if (BssidList->NumberOfItems == 0)
+ {
+ _tprintf(_T("No networks found in range\n"));
+ }
+ else
+ {
+ PNDIS_WLAN_BSSID BssidInfo = BssidList->Bssid;
+ for (i = 0; i < BssidList->NumberOfItems; i++)
+ {
+ PNDIS_802_11_SSID Ssid = &BssidInfo->Ssid;
+ NDIS_802_11_RSSI Rssi = BssidInfo->Rssi;
+ NDIS_802_11_NETWORK_INFRASTRUCTURE NetworkType = BssidInfo->InfrastructureMode;
+ CHAR SsidBuffer[NDIS_802_11_LENGTH_SSID + 1];
+ UINT Rate;
+
+ /* SSID member is a non-null terminated ASCII string */
+ RtlCopyMemory(SsidBuffer, Ssid->Ssid, Ssid->SsidLength);
+ SsidBuffer[Ssid->SsidLength] = 0;
+
+ _tprintf(_T("\n"));
+
+ _tprintf(_T("SSID: %s\n"), SsidBuffer);
+
+ _tprintf(_T("BSSID: "));
+ for (j = 0; j < sizeof(NDIS_802_11_MAC_ADDRESS); j++)
+ {
+ UINT BssidData = BssidInfo->MacAddress[j];
+
+ _tprintf(_T("%.2x"), BssidData);
+
+ if (j != sizeof(NDIS_802_11_MAC_ADDRESS) - 1)
+ _tprintf(_T(":"));
+ }
+ _tprintf(_T("\n"));
+
+ _tprintf(_T("Encrypted: %s\n"
+ "Network Type: %s\n"
+ "RSSI: %i dBm\n"
+ "Supported Rates (Mbps): "),
+ BssidInfo->Privacy == 0 ? "No" : "Yes",
+ NetworkType == Ndis802_11IBSS ? "Adhoc" : "Infrastructure",
+ (int)Rssi);
+
+ for (j = 0; j < NDIS_802_11_LENGTH_RATES; j++)
+ {
+ Rate = BssidInfo->SupportedRates[j];
+ if (Rate != 0)
+ {
+ /* Bit 7 is the basic rates bit */
+ Rate = Rate & 0x7F;
+
+ /* SupportedRates are in units of .5 */
+ if (Rate & 0x01)
+ {
+ /* Bit 0 is set so we need to add 0.5 */
+ _tprintf(_T("%u.5 "), (Rate >> 1));
+ }
+ else
+ {
+ /* Bit 0 is clear so just print the conversion */
+ _tprintf(_T("%u "), (Rate >> 1));
+ }
+ }
+ }
+ _tprintf(_T("\n"));
+
+ /* Move to the next entry */
+ BssidInfo = (PNDIS_WLAN_BSSID)((PUCHAR)BssidInfo + BssidInfo->Length);
+ }
+ }
+
+ HeapFree(GetProcessHeap(), 0, QueryOid);
+
+ return bSuccess;
+}
+
+VOID Usage()
+{
+ _tprintf(_T("\nConfigures a WLAN adapter.\n\n"
+ "WLANCONF [-c SSID [-w WEP] [-a]] [-d] [-s]\n\n"
+ " -c SSID Connects to a supplied SSID.\n"
+ " -w WEP Specifies a WEP key to use.\n"
+ " -a Specifies the target network is ad-hoc\n"
+ " -d Disconnects from the current AP.\n"
+ " -s Scans and displays a list of access points in range.\n\n"
+ " Passing no parameters will print information about the current WLAN connection\n"));
+}
+
+
+BOOL ParseCmdline(int argc, char* argv[])
+{
+ INT i;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 's':
+ bScan = TRUE;
+ break;
+ case 'd':
+ bDisconnect = TRUE;
+ break;
+ case 'c':
+ if (i == argc - 1)
+ {
+ Usage();
+ return FALSE;
+ }
+ bConnect = TRUE;
+ sSsid = argv[++i];
+ break;
+ case 'w':
+ if (i == argc - 1)
+ {
+ Usage();
+ return FALSE;
+ }
+ sWepKey = argv[++i];
+ break;
+ case 'a':
+ bAdhoc = TRUE;
+ break;
+ default :
+ Usage();
+ return FALSE;
+ }
+
+ }
+ else
+ {
+ Usage();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+int main(int argc, char* argv[])
+{
+ HANDLE hAdapter;
+ IP_ADAPTER_INDEX_MAP IpInfo;
+
+ if (!ParseCmdline(argc, argv))
+ return -1;
+
+ if (!OpenWlanAdapter(&hAdapter, &IpInfo))
+ {
+ _tprintf(_T("Unable to find a WLAN adapter on the system\n"));
+ return -1;
+ }
+
+ if (bScan)
+ {
+ if (!WlanScan(hAdapter))
+ {
+ DoFormatMessage(GetLastError());
+ CloseHandle(hAdapter);
+ return -1;
+ }
+ }
+ else if (bDisconnect)
+ {
+ if (!WlanDisconnect(hAdapter, &IpInfo))
+ {
+ DoFormatMessage(GetLastError());
+ CloseHandle(hAdapter);
+ return -1;
+ }
+ }
+ else if (bConnect)
+ {
+ if (!WlanConnect(hAdapter))
+ {
+ DoFormatMessage(GetLastError());
+ CloseHandle(hAdapter);
+ return -1;
+ }
+ }
+ else
+ {
+ if (!WlanPrintCurrentStatus(hAdapter))
+ {
+ DoFormatMessage(GetLastError());
+ CloseHandle(hAdapter);
+ return -1;
+ }
+ }
+
+ CloseHandle(hAdapter);
+ return 0;
+}
diff --git a/reactos/base/applications/network/wlanconf/wlanconf.rbuild b/reactos/base/applications/network/wlanconf/wlanconf.rbuild
new file mode 100644
index 00000000000..9658c2826eb
--- /dev/null
+++ b/reactos/base/applications/network/wlanconf/wlanconf.rbuild
@@ -0,0 +1,9 @@
+
+
+
+ .
+ include/reactos/drivers/ndisuio
+ iphlpapi
+ wlanconf.c
+ wlanconf.rc
+
diff --git a/reactos/base/applications/network/wlanconf/wlanconf.rc b/reactos/base/applications/network/wlanconf/wlanconf.rc
new file mode 100644
index 00000000000..78b2584976d
--- /dev/null
+++ b/reactos/base/applications/network/wlanconf/wlanconf.rc
@@ -0,0 +1,7 @@
+#define REACTOS_STR_FILE_DESCRIPTION "ReactOS WLAN Configuration Tool\0"
+#define REACTOS_STR_INTERNAL_NAME "wlanconf\0"
+#define REACTOS_STR_ORIGINAL_FILENAME "wlanconf.exe\0"
+#define REACTOS_STR_ORIGINAL_COPYRIGHT "Cameron Gutman (cameron.gutman@reactos.org)\0"
+#include
+
+
diff --git a/reactos/boot/bootdata/hivesys_i386.inf b/reactos/boot/bootdata/hivesys_i386.inf
index 368733acfd9..97d40aeb7a1 100644
--- a/reactos/boot/bootdata/hivesys_i386.inf
+++ b/reactos/boot/bootdata/hivesys_i386.inf
@@ -1399,6 +1399,13 @@ HKLM,"SYSTEM\CurrentControlSet\Services\NMIDebug","ImagePath",0x00020000,"system
HKLM,"SYSTEM\CurrentControlSet\Services\NMIDebug","Start",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\NMIDebug","Type",0x00010001,0x00000001
+; NDIS User I/O driver (FIXME: Should be installed via INF and started on demand)
+HKLM,"SYSTEM\CurrentControlSet\Services\Ndisuio","ErrorControl",0x00010001,0x00000001
+HKLM,"SYSTEM\CurrentControlSet\Services\Ndisuio","Group",0x00000000,"NDIS"
+HKLM,"SYSTEM\CurrentControlSet\Services\Ndisuio","ImagePath",0x00020000,"system32\drivers\ndisuio.sys"
+HKLM,"SYSTEM\CurrentControlSet\Services\Ndisuio","Start",0x00010001,0x00000001
+HKLM,"SYSTEM\CurrentControlSet\Services\Ndisuio","Type",0x00010001,0x00000001
+
; Packet driver
HKLM,"SYSTEM\CurrentControlSet\Services\Packet","ErrorControl",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\Packet","Group",0x00000000,"PNP_TDI"
@@ -1629,7 +1636,7 @@ HKLM,"SYSTEM\CurrentControlSet\Services\WlanSvc","ErrorControl",0x00010001,0x000
HKLM,"SYSTEM\CurrentControlSet\Services\WlanSvc","Group",0x00000000,"TDI"
HKLM,"SYSTEM\CurrentControlSet\Services\WlanSvc","ImagePath",0x00020000,"%SystemRoot%\system32\wlansvc.exe"
HKLM,"SYSTEM\CurrentControlSet\Services\WlanSvc","ObjectName",0x00000000,"LocalSystem"
-HKLM,"SYSTEM\CurrentControlSet\Services\WlanSvc","Start",0x00010001,0x00000003
+HKLM,"SYSTEM\CurrentControlSet\Services\WlanSvc","Start",0x00010001,0x00000002
HKLM,"SYSTEM\CurrentControlSet\Services\WlanSvc","Type",0x00010001,0x00000110
; Simple TCP services
diff --git a/reactos/boot/bootdata/packages/reactos.dff b/reactos/boot/bootdata/packages/reactos.dff
index c68046d8e59..22127862008 100644
--- a/reactos/boot/bootdata/packages/reactos.dff
+++ b/reactos/boot/bootdata/packages/reactos.dff
@@ -76,6 +76,7 @@ base\applications\network\route\route.exe 1
base\applications\network\telnet\telnet.exe 1
base\applications\network\tracert\tracert.exe 1
base\applications\network\whois\whois.exe 1
+base\applications\network\wlanconf\wlanconf.exe 1
base\applications\notepad\notepad.exe 1
base\applications\rapps\rapps.exe 1
base\applications\regedit\regedit.exe 4
@@ -532,6 +533,7 @@ drivers\network\tcpip\tcpip.sys 2
drivers\network\tdi\tdi.sys 2
drivers\network\dd\ne2000\ne2000.sys 2
drivers\network\dd\pcnet\pcnet.sys 2
+drivers\network\ndisuio\ndisuio.sys 2
drivers\serial\serenum\serenum.sys 2
drivers\serial\serial\serial.sys 2
diff --git a/reactos/drivers/network/CMakeLists.txt b/reactos/drivers/network/CMakeLists.txt
index 88521cab276..abffd627bb7 100644
--- a/reactos/drivers/network/CMakeLists.txt
+++ b/reactos/drivers/network/CMakeLists.txt
@@ -2,5 +2,6 @@
add_subdirectory(afd)
add_subdirectory(dd)
add_subdirectory(ndis)
+add_subdirectory(ndisuio)
add_subdirectory(tcpip)
add_subdirectory(tdi)
diff --git a/reactos/drivers/network/directory.rbuild b/reactos/drivers/network/directory.rbuild
index 2a62dbd7fbf..76df85538ab 100644
--- a/reactos/drivers/network/directory.rbuild
+++ b/reactos/drivers/network/directory.rbuild
@@ -10,6 +10,9 @@
+
+
+
diff --git a/reactos/drivers/network/ndisuio/CMakeLists.txt b/reactos/drivers/network/ndisuio/CMakeLists.txt
new file mode 100644
index 00000000000..3ab2f938f5e
--- /dev/null
+++ b/reactos/drivers/network/ndisuio/CMakeLists.txt
@@ -0,0 +1,25 @@
+add_definitions(
+ -DNDIS50
+ -D_NTDRIVER_)
+
+include_directories(
+ BEFORE include
+ ${REACTOS_SOURCE_DIR}/include/reactos/drivers/ndisuio)
+
+list(APPEND SOURCE
+ createclose.c
+ ioctl.c
+ main.c
+ misc.c
+ protocol.c
+ readwrite.c
+ ndisuio.rc)
+
+add_library(ndisuio SHARED ${SOURCE})
+
+set_module_type(ndisuio kernelmodedriver)
+add_importlibs(ndisuio ndis ntoskrnl hal)
+
+add_pch(ndisuio ndisuio.h)
+
+add_cd_file(TARGET ndisuio DESTINATION reactos/system32/drivers FOR all)
diff --git a/reactos/drivers/network/ndisuio/createclose.c b/reactos/drivers/network/ndisuio/createclose.c
new file mode 100644
index 00000000000..d0fe7af9fb6
--- /dev/null
+++ b/reactos/drivers/network/ndisuio/createclose.c
@@ -0,0 +1,69 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS NDIS User I/O driver
+ * FILE: createclose.c
+ * PURPOSE: IRP_MJ_CREATE and IRP_MJ_CLOSE handling
+ * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
+ */
+
+#include "ndisuio.h"
+
+//#define NDEBUG
+#include
+
+NTSTATUS
+NTAPI
+NduDispatchCreate(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ ASSERT(DeviceObject == GlobalDeviceObject);
+
+ DPRINT("Created file object 0x%x\n", IrpSp->FileObject);
+
+ /* This is associated with an adapter during IOCTL_NDISUIO_OPEN_(WRITE_)DEVICE */
+ IrpSp->FileObject->FsContext = NULL;
+ IrpSp->FileObject->FsContext2 = NULL;
+
+ /* Completed successfully */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = FILE_OPENED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ /* Return success */
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+NduDispatchClose(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
+ PNDISUIO_OPEN_ENTRY OpenEntry = IrpSp->FileObject->FsContext2;
+
+ ASSERT(DeviceObject == GlobalDeviceObject);
+
+ DPRINT("Closing file object 0x%x\n", IrpSp->FileObject);
+
+ /* Check if this handle was ever associated with an adapter */
+ if (AdapterContext != NULL)
+ {
+ ASSERT(OpenEntry != NULL);
+
+ DPRINT("Removing binding to adapter %wZ\n", &AdapterContext->DeviceName);
+
+ /* Call the our helper */
+ DereferenceAdapterContextWithOpenEntry(AdapterContext, OpenEntry);
+ }
+
+ /* Completed */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ /* Return success */
+ return STATUS_SUCCESS;
+}
\ No newline at end of file
diff --git a/reactos/drivers/network/ndisuio/ioctl.c b/reactos/drivers/network/ndisuio/ioctl.c
new file mode 100644
index 00000000000..74070d60e70
--- /dev/null
+++ b/reactos/drivers/network/ndisuio/ioctl.c
@@ -0,0 +1,525 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS NDIS User I/O driver
+ * FILE: ioctl.c
+ * PURPOSE: IOCTL handling
+ * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
+ */
+
+#include "ndisuio.h"
+
+//#define NDEBUG
+#include
+
+static
+NTSTATUS
+WaitForBind(PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ /* I've seen several code samples that use this IOCTL but there's
+ * no official documentation on it. I'm just implementing it as a no-op
+ * right now because I don't see any reason we need it. We handle an open
+ * and bind just fine with IRP_MJ_CREATE and IOCTL_NDISUIO_OPEN_DEVICE */
+ DPRINT("Wait for bind complete\n");
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return STATUS_SUCCESS;
+}
+
+static
+NTSTATUS
+QueryBinding(PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = NULL;
+ PNDISUIO_QUERY_BINDING QueryBinding = Irp->AssociatedIrp.SystemBuffer;
+ ULONG BindingLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ NTSTATUS Status;
+ PLIST_ENTRY CurrentEntry;
+ KIRQL OldIrql;
+ ULONG i;
+ ULONG BytesCopied = 0;
+
+ if (QueryBinding && BindingLength >= sizeof(NDISUIO_QUERY_BINDING))
+ {
+ KeAcquireSpinLock(&GlobalAdapterListLock, &OldIrql);
+ i = 0;
+ CurrentEntry = GlobalAdapterList.Flink;
+ while (CurrentEntry != &GlobalAdapterList)
+ {
+ if (i == QueryBinding->BindingIndex)
+ {
+ AdapterContext = CONTAINING_RECORD(CurrentEntry, NDISUIO_ADAPTER_CONTEXT, ListEntry);
+ break;
+ }
+ i++;
+ CurrentEntry = CurrentEntry->Flink;
+ }
+ KeReleaseSpinLock(&GlobalAdapterListLock, OldIrql);
+ if (AdapterContext)
+ {
+ DPRINT("Query binding for index %d is adapter %wZ\n", i, &AdapterContext->DeviceName);
+ BytesCopied = sizeof(NDISUIO_QUERY_BINDING);
+ if (AdapterContext->DeviceName.Length <= BindingLength - BytesCopied)
+ {
+ QueryBinding->DeviceNameOffset = BytesCopied;
+ QueryBinding->DeviceNameLength = AdapterContext->DeviceName.Length;
+ RtlCopyMemory((PUCHAR)QueryBinding + QueryBinding->DeviceNameOffset,
+ AdapterContext->DeviceName.Buffer,
+ QueryBinding->DeviceNameLength);
+ BytesCopied += AdapterContext->DeviceName.Length;
+
+ /* FIXME: Copy description too */
+ QueryBinding->DeviceDescrOffset = BytesCopied;
+ QueryBinding->DeviceDescrLength = 0;
+
+ /* Successful */
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ /* Not enough buffer space */
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+ else
+ {
+ /* Invalid index */
+ Status = STATUS_NO_MORE_ENTRIES;
+ }
+ }
+ else
+ {
+ /* Invalid parameters */
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = BytesCopied;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
+
+#if 0
+static
+NTSTATUS
+CancelPacketRead(PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
+ PNDISUIO_PACKET_ENTRY PacketEntry;
+ NTSTATUS Status;
+
+ /* Indicate a 0-byte packet on the queue so one read returns 0 */
+ PacketEntry = ExAllocatePool(PagedPool, sizeof(NDISUIO_PACKET_ENTRY));
+ if (PacketEntry)
+ {
+ PacketEntry->PacketLength = 0;
+
+ ExInterlockedInsertHeadList(&AdapterContext->PacketList,
+ &PacketEntry->ListEntry,
+ &AdapterContext->Spinlock);
+
+ KeSetEvent(&AdapterContext->PacketReadEvent, IO_NO_INCREMENT, FALSE);
+
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ Status = STATUS_NO_MEMORY;
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
+#endif
+
+static
+NTSTATUS
+SetAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
+ PNDISUIO_SET_OID SetOidRequest;
+ NDIS_REQUEST Request;
+ ULONG RequestLength;
+ NDIS_STATUS Status;
+
+ Irp->IoStatus.Information = 0;
+
+ SetOidRequest = Irp->AssociatedIrp.SystemBuffer;
+ RequestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ if (SetOidRequest && RequestLength >= sizeof(NDIS_OID))
+ {
+ /* Setup the NDIS request */
+ Request.RequestType = NdisRequestSetInformation;
+ Request.DATA.SET_INFORMATION.Oid = SetOidRequest->Oid;
+ Request.DATA.SET_INFORMATION.InformationBufferLength = RequestLength - sizeof(NDIS_OID);
+ if (Request.DATA.SET_INFORMATION.InformationBufferLength != 0)
+ {
+ Request.DATA.SET_INFORMATION.InformationBuffer = SetOidRequest->Data;
+ }
+ else
+ {
+ Request.DATA.SET_INFORMATION.InformationBuffer = NULL;
+ }
+ Request.DATA.SET_INFORMATION.BytesRead = 0;
+
+ DPRINT("Setting OID 0x%x on adapter %wZ\n", SetOidRequest->Oid, &AdapterContext->DeviceName);
+
+ /* Dispatch the request */
+ NdisRequest(&Status,
+ AdapterContext->BindingHandle,
+ &Request);
+
+ /* Wait for the request */
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&AdapterContext->AsyncEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ Status = AdapterContext->AsyncStatus;
+ }
+
+ /* Return the bytes read */
+ if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(NDIS_OID) + Request.DATA.SET_INFORMATION.BytesRead;
+
+ DPRINT("Final request status: 0x%x (%d)\n", Status, Irp->IoStatus.Information);
+ }
+ else
+ {
+ /* Bad parameters */
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ Irp->IoStatus.Status = Status;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
+
+static
+NTSTATUS
+QueryAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
+ PNDISUIO_QUERY_OID QueryOidRequest;
+ NDIS_REQUEST Request;
+ ULONG RequestLength;
+ NDIS_STATUS Status;
+
+ Irp->IoStatus.Information = 0;
+
+ QueryOidRequest = Irp->AssociatedIrp.SystemBuffer;
+ RequestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ if (QueryOidRequest && RequestLength >= sizeof(NDIS_OID))
+ {
+ /* Setup the NDIS request */
+ Request.RequestType = NdisRequestQueryInformation;
+ Request.DATA.QUERY_INFORMATION.Oid = QueryOidRequest->Oid;
+ Request.DATA.QUERY_INFORMATION.InformationBufferLength = RequestLength - sizeof(NDIS_OID);
+ if (Request.DATA.QUERY_INFORMATION.InformationBufferLength != 0)
+ {
+ Request.DATA.QUERY_INFORMATION.InformationBuffer = QueryOidRequest->Data;
+ }
+ else
+ {
+ Request.DATA.QUERY_INFORMATION.InformationBuffer = NULL;
+ }
+ Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+
+ DPRINT("Querying OID 0x%x on adapter %wZ\n", QueryOidRequest->Oid, &AdapterContext->DeviceName);
+
+ /* Dispatch the request */
+ NdisRequest(&Status,
+ AdapterContext->BindingHandle,
+ &Request);
+
+ /* Wait for the request */
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&AdapterContext->AsyncEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ Status = AdapterContext->AsyncStatus;
+ }
+
+ /* Return the bytes written */
+ if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(NDIS_OID) + Request.DATA.QUERY_INFORMATION.BytesWritten;
+
+ DPRINT("Final request status: 0x%x (%d)\n", Status, Irp->IoStatus.Information);
+ }
+ else
+ {
+ /* Bad parameters */
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ Irp->IoStatus.Status = Status;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
+
+static
+NTSTATUS
+OpenDeviceReadWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ UNICODE_STRING DeviceName;
+ ULONG NameLength;
+ NTSTATUS Status;
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext;
+ PNDISUIO_OPEN_ENTRY OpenEntry;
+ KIRQL OldIrql;
+
+ NameLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ if (NameLength != 0)
+ {
+ DeviceName.MaximumLength = DeviceName.Length = NameLength;
+ DeviceName.Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+ /* Check if this already has a context */
+ AdapterContext = FindAdapterContextByName(&DeviceName);
+ if (AdapterContext != NULL)
+ {
+ DPRINT("Binding file object 0x%x to device %wZ\n", FileObject, &AdapterContext->DeviceName);
+
+ /* Reference the adapter context */
+ KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql);
+ if (AdapterContext->OpenCount != 0)
+ {
+ /* An open for read-write is exclusive,
+ * so we can't have any other open handles */
+ KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Add a reference */
+ ReferenceAdapterContext(AdapterContext);
+ Status = STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ /* Invalid device name */
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ /* Check that the bind succeeded */
+ if (NT_SUCCESS(Status))
+ {
+ OpenEntry = ExAllocatePool(NonPagedPool, sizeof(*OpenEntry));
+ if (OpenEntry)
+ {
+ /* Set the file object pointer */
+ OpenEntry->FileObject = FileObject;
+
+ /* Set the permissions */
+ OpenEntry->WriteOnly = FALSE;
+
+ /* Associate this FO with the adapter */
+ FileObject->FsContext = AdapterContext;
+ FileObject->FsContext2 = OpenEntry;
+
+ /* Add it to the adapter's list */
+ InsertTailList(&AdapterContext->OpenEntryList,
+ &OpenEntry->ListEntry);
+
+ /* Success */
+ KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ /* Remove the reference we added */
+ KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
+ DereferenceAdapterContextWithOpenEntry(AdapterContext, NULL);
+ Status = STATUS_NO_MEMORY;
+ }
+ }
+ }
+ else
+ {
+ /* Invalid device name */
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
+
+#if 0
+static
+NTSTATUS
+OpenDeviceWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ UNICODE_STRING DeviceName;
+ ULONG NameLength;
+ NTSTATUS Status;
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext;
+ PNDISUIO_OPEN_ENTRY OpenEntry;
+ KIRQL OldIrql;
+
+ NameLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ if (NameLength != 0)
+ {
+ DeviceName.MaximumLength = DeviceName.Length = NameLength;
+ DeviceName.Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+ /* Check if this already has a context */
+ AdapterContext = FindAdapterContextByName(&DeviceName);
+ if (AdapterContext != NULL)
+ {
+ /* Reference the adapter context */
+ KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql);
+ ReferenceAdapterContext(AdapterContext);
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ /* Invalid device name */
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ /* Check that the bind succeeded */
+ if (NT_SUCCESS(Status))
+ {
+ OpenEntry = ExAllocatePool(NonPagedPool, sizeof(*OpenEntry));
+ if (OpenEntry)
+ {
+ /* Set the file object pointer */
+ OpenEntry->FileObject = FileObject;
+
+ /* Associate this FO with the adapter */
+ FileObject->FsContext = AdapterContext;
+ FileObject->FsContext2 = OpenEntry;
+
+ /* Set permissions */
+ OpenEntry->WriteOnly = TRUE;
+
+ /* Add it to the adapter's list */
+ InsertTailList(&AdapterContext->OpenEntryList,
+ &OpenEntry->ListEntry);
+
+ /* Success */
+ KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ /* Remove the reference we added */
+ KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
+ DereferenceAdapterContext(AdapterContext, NULL);
+ Status = STATUS_NO_MEMORY;
+ }
+ }
+ }
+ else
+ {
+ /* Invalid device name */
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
+#endif
+
+NTSTATUS
+NTAPI
+NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PNDISUIO_OPEN_ENTRY OpenEntry;
+
+ ASSERT(DeviceObject == GlobalDeviceObject);
+
+ /* Handle open IOCTLs first */
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_NDISUIO_OPEN_DEVICE:
+ return OpenDeviceReadWrite(Irp, IrpSp);
+#if 0
+ case IOCTL_NDISUIO_OPEN_WRITE_DEVICE:
+ return OpenDeviceWrite(Irp, IrpSp);
+#endif
+ case IOCTL_NDISUIO_BIND_WAIT:
+ return WaitForBind(Irp, IrpSp);
+
+ case IOCTL_NDISUIO_QUERY_BINDING:
+ return QueryBinding(Irp, IrpSp);
+
+ default:
+ /* Fail if this file object has no adapter associated */
+ if (IrpSp->FileObject->FsContext == NULL)
+ {
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Now handle write IOCTLs */
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_NDISUIO_SET_OID_VALUE:
+ return SetAdapterOid(Irp, IrpSp);
+
+ default:
+ /* Check that we have read permissions */
+ OpenEntry = IrpSp->FileObject->FsContext2;
+ if (OpenEntry->WriteOnly)
+ {
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+#if 0
+ case IOCTL_CANCEL_READ:
+ return CancelPacketRead(Irp, IrpSp);
+#endif
+
+ case IOCTL_NDISUIO_QUERY_OID_VALUE:
+ return QueryAdapterOid(Irp, IrpSp);
+
+ default:
+ DPRINT1("Unimplemented\n");
+ Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+ }
+ break;
+ }
+}
diff --git a/reactos/drivers/network/ndisuio/main.c b/reactos/drivers/network/ndisuio/main.c
new file mode 100644
index 00000000000..07567770240
--- /dev/null
+++ b/reactos/drivers/network/ndisuio/main.c
@@ -0,0 +1,104 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS NDIS User I/O driver
+ * FILE: main.c
+ * PURPOSE: Driver entry point and protocol initialization
+ * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
+ */
+
+#include "ndisuio.h"
+
+//#define NDEBUG
+#include
+
+PDEVICE_OBJECT GlobalDeviceObject;
+NDIS_HANDLE GlobalProtocolHandle;
+KSPIN_LOCK GlobalAdapterListLock;
+LIST_ENTRY GlobalAdapterList;
+
+NDIS_STRING ProtocolName = RTL_CONSTANT_STRING(L"NDISUIO");
+
+VOID NTAPI NduUnload(PDRIVER_OBJECT DriverObject)
+{
+ DPRINT("NDISUIO: Unloaded\n");
+}
+
+NTSTATUS
+NTAPI
+DriverEntry(PDRIVER_OBJECT DriverObject,
+ PUNICODE_STRING RegistryPath)
+{
+ NDIS_STATUS Status;
+ NDIS_PROTOCOL_CHARACTERISTICS Chars;
+ UNICODE_STRING NtDeviceName = RTL_CONSTANT_STRING(NDISUIO_DEVICE_NAME_NT);
+ UNICODE_STRING DosDeviceName = RTL_CONSTANT_STRING(NDISUIO_DEVICE_NAME_DOS);
+
+ /* Setup dispatch functions */
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = NduDispatchCreate;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = NduDispatchClose;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NduDispatchDeviceControl;
+ DriverObject->MajorFunction[IRP_MJ_READ] = NduDispatchRead;
+ DriverObject->MajorFunction[IRP_MJ_WRITE] = NduDispatchWrite;
+ DriverObject->DriverUnload = NduUnload;
+
+ /* Setup global state */
+ InitializeListHead(&GlobalAdapterList);
+ KeInitializeSpinLock(&GlobalAdapterListLock);
+
+ /* Create the NDISUIO device object */
+ Status = IoCreateDevice(DriverObject,
+ 0,
+ &NtDeviceName,
+ FILE_DEVICE_SECURE_OPEN,
+ 0,
+ FALSE,
+ &GlobalDeviceObject);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to create device object with status 0x%x\n", Status);
+ return Status;
+ }
+
+ /* Create a symbolic link into the DOS devices namespace */
+ Status = IoCreateSymbolicLink(&DosDeviceName, &NtDeviceName);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to create symbolic link with status 0x%x\n", Status);
+ IoDeleteDevice(GlobalDeviceObject);
+ return Status;
+ }
+
+ /* Register the protocol with NDIS */
+ RtlZeroMemory(&Chars, sizeof(Chars));
+ Chars.MajorNdisVersion = NDIS_MAJOR_VERSION;
+ Chars.MinorNdisVersion = NDIS_MINOR_VERSION;
+ Chars.OpenAdapterCompleteHandler = NduOpenAdapterComplete;
+ Chars.CloseAdapterCompleteHandler = NduCloseAdapterComplete;
+ Chars.SendCompleteHandler = NduSendComplete;
+ Chars.TransferDataCompleteHandler = NduTransferDataComplete;
+ Chars.ResetCompleteHandler = NduResetComplete;
+ Chars.RequestCompleteHandler = NduRequestComplete;
+ Chars.ReceiveHandler = NduReceive;
+ Chars.ReceiveCompleteHandler = NduReceiveComplete;
+ Chars.StatusHandler = NduStatus;
+ Chars.StatusCompleteHandler = NduStatusComplete;
+ Chars.Name = ProtocolName;
+ Chars.BindAdapterHandler = NduBindAdapter;
+ Chars.UnbindAdapterHandler = NduUnbindAdapter;
+
+ NdisRegisterProtocol(&Status,
+ &GlobalProtocolHandle,
+ &Chars,
+ sizeof(Chars));
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DPRINT1("Failed to register protocol with status 0x%x\n", Status);
+ IoDeleteSymbolicLink(&DosDeviceName);
+ IoDeleteDevice(GlobalDeviceObject);
+ return Status;
+ }
+
+ DPRINT("NDISUIO: Loaded\n");
+
+ return STATUS_SUCCESS;
+}
diff --git a/reactos/drivers/network/ndisuio/misc.c b/reactos/drivers/network/ndisuio/misc.c
new file mode 100644
index 00000000000..43552cb9fa0
--- /dev/null
+++ b/reactos/drivers/network/ndisuio/misc.c
@@ -0,0 +1,176 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS NDIS User I/O driver
+ * FILE: misc.c
+ * PURPOSE: Helper functions
+ * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
+ */
+
+#include "ndisuio.h"
+
+#define NDEBUG
+#include
+
+NDIS_STATUS
+AllocateAndChainBuffer(PNDISUIO_ADAPTER_CONTEXT AdapterContext,
+ PNDIS_PACKET Packet,
+ PVOID Buffer,
+ ULONG BufferSize,
+ BOOLEAN Front)
+{
+ NDIS_STATUS Status;
+ PNDIS_BUFFER NdisBuffer;
+
+ /* Allocate the NDIS buffer mapping the pool */
+ NdisAllocateBuffer(&Status,
+ &NdisBuffer,
+ AdapterContext->BufferPoolHandle,
+ Buffer,
+ BufferSize);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DPRINT1("No free buffer descriptors\n");
+ return Status;
+ }
+
+ if (Front)
+ {
+ /* Chain the buffer to front */
+ NdisChainBufferAtFront(Packet, NdisBuffer);
+ }
+ else
+ {
+ /* Chain the buffer to back */
+ NdisChainBufferAtBack(Packet, NdisBuffer);
+ }
+
+ /* Return success */
+ return NDIS_STATUS_SUCCESS;
+}
+
+PNDIS_PACKET
+CreatePacketFromPoolBuffer(PNDISUIO_ADAPTER_CONTEXT AdapterContext,
+ PVOID Buffer,
+ ULONG BufferSize)
+{
+ PNDIS_PACKET Packet;
+ NDIS_STATUS Status;
+
+ /* Allocate a packet descriptor */
+ NdisAllocatePacket(&Status,
+ &Packet,
+ AdapterContext->PacketPoolHandle);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DPRINT1("No free packet descriptors\n");
+ return NULL;
+ }
+
+ /* Use the helper to chain the buffer */
+ Status = AllocateAndChainBuffer(AdapterContext, Packet,
+ Buffer, BufferSize, TRUE);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NdisFreePacket(Packet);
+ return NULL;
+ }
+
+ /* Return the packet */
+ return Packet;
+}
+
+VOID
+CleanupAndFreePacket(PNDIS_PACKET Packet, BOOLEAN FreePool)
+{
+ PNDIS_BUFFER Buffer;
+ PVOID Data;
+ ULONG Length;
+
+ /* Free each buffer and its backing pool memory */
+ while (TRUE)
+ {
+ /* Unchain each buffer */
+ NdisUnchainBufferAtFront(Packet, &Buffer);
+ if (!Buffer)
+ break;
+
+ /* Get the backing memory */
+ NdisQueryBuffer(Buffer, &Data, &Length);
+
+ /* Free the buffer */
+ NdisFreeBuffer(Buffer);
+
+ if (FreePool)
+ {
+ /* Free the backing memory */
+ ExFreePool(Data);
+ }
+ }
+
+ /* Free the packet descriptor */
+ NdisFreePacket(Packet);
+}
+
+PNDISUIO_ADAPTER_CONTEXT
+FindAdapterContextByName(PNDIS_STRING DeviceName)
+{
+ KIRQL OldIrql;
+ PLIST_ENTRY CurrentEntry;
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext;
+
+ KeAcquireSpinLock(&GlobalAdapterListLock, &OldIrql);
+ CurrentEntry = GlobalAdapterList.Flink;
+ while (CurrentEntry != &GlobalAdapterList)
+ {
+ AdapterContext = CONTAINING_RECORD(CurrentEntry, NDISUIO_ADAPTER_CONTEXT, ListEntry);
+
+ /* Check if the device name matches */
+ if (RtlEqualUnicodeString(&AdapterContext->DeviceName, DeviceName, TRUE))
+ {
+ KeReleaseSpinLock(&GlobalAdapterListLock, OldIrql);
+ return AdapterContext;
+ }
+
+ CurrentEntry = CurrentEntry->Flink;
+ }
+ KeReleaseSpinLock(&GlobalAdapterListLock, OldIrql);
+
+ return NULL;
+}
+
+VOID
+ReferenceAdapterContext(PNDISUIO_ADAPTER_CONTEXT AdapterContext)
+{
+ /* Increment the open count */
+ AdapterContext->OpenCount++;
+}
+
+VOID
+DereferenceAdapterContextWithOpenEntry(PNDISUIO_ADAPTER_CONTEXT AdapterContext,
+ PNDISUIO_OPEN_ENTRY OpenEntry)
+{
+ KIRQL OldIrql;
+
+ /* Lock the adapter context */
+ KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql);
+
+ /* Decrement the open count */
+ AdapterContext->OpenCount--;
+
+ /* Cleanup the open entry if we were given one */
+ if (OpenEntry != NULL)
+ {
+ /* Remove the open entry */
+ RemoveEntryList(&OpenEntry->ListEntry);
+
+ /* Invalidate the FO */
+ OpenEntry->FileObject->FsContext = NULL;
+ OpenEntry->FileObject->FsContext2 = NULL;
+
+ /* Free the open entry */
+ ExFreePool(OpenEntry);
+ }
+
+ /* Release the adapter context lock */
+ KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
+}
diff --git a/reactos/drivers/network/ndisuio/ndisuio.h b/reactos/drivers/network/ndisuio/ndisuio.h
new file mode 100644
index 00000000000..13f6d919239
--- /dev/null
+++ b/reactos/drivers/network/ndisuio/ndisuio.h
@@ -0,0 +1,210 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS NDIS User I/O driver
+ * FILE: ndisuio.h
+ * PURPOSE: NDISUIO definitions
+ */
+#ifndef __NDISUIO_H
+#define __NDISUIO_H
+
+#include
+#include
+#include
+
+extern PDEVICE_OBJECT GlobalDeviceObject;
+extern NDIS_HANDLE GlobalProtocolHandle;
+extern LIST_ENTRY GlobalAdapterList;
+extern KSPIN_LOCK GlobalAdapterListLock;
+
+typedef struct _NDISUIO_ADAPTER_CONTEXT
+{
+ /* Asynchronous completion */
+ NDIS_STATUS AsyncStatus;
+ KEVENT AsyncEvent;
+
+ /* NDIS binding information */
+ NDIS_HANDLE BindingHandle;
+
+ /* Reference count information */
+ ULONG OpenCount;
+ LIST_ENTRY OpenEntryList;
+
+ /* NDIS pools */
+ NDIS_HANDLE PacketPoolHandle;
+ NDIS_HANDLE BufferPoolHandle;
+
+ /* Receive packet list */
+ LIST_ENTRY PacketList;
+ KEVENT PacketReadEvent;
+
+ /* Mac options */
+ ULONG MacOptions;
+
+ /* Device name */
+ UNICODE_STRING DeviceName;
+
+ /* Global list entry */
+ LIST_ENTRY ListEntry;
+
+ /* Spin lock */
+ KSPIN_LOCK Spinlock;
+} NDISUIO_ADAPTER_CONTEXT, *PNDISUIO_ADAPTER_CONTEXT;
+
+typedef struct _NDISUIO_OPEN_ENTRY
+{
+ /* File object */
+ PFILE_OBJECT FileObject;
+
+ /* Tracks how this adapter was opened (write-only or read-write) */
+ BOOLEAN WriteOnly;
+
+ /* List entry */
+ LIST_ENTRY ListEntry;
+} NDISUIO_OPEN_ENTRY, *PNDISUIO_OPEN_ENTRY;
+
+typedef struct _NDISUIO_PACKET_ENTRY
+{
+ /* Length of data at the end of the struct */
+ ULONG PacketLength;
+
+ /* Entry on the packet list */
+ LIST_ENTRY ListEntry;
+
+ /* Packet data */
+ UCHAR PacketData[1];
+} NDISUIO_PACKET_ENTRY, *PNDISUIO_PACKET_ENTRY;
+
+/* NDIS version info */
+#define NDIS_MAJOR_VERSION 5
+#define NDIS_MINOR_VERSION 0
+
+/* createclose.c */
+NTSTATUS
+NTAPI
+NduDispatchCreate(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp);
+
+NTSTATUS
+NTAPI
+NduDispatchClose(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp);
+
+/* ioctl.c */
+NTSTATUS
+NTAPI
+NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp);
+
+/* misc.c */
+NDIS_STATUS
+AllocateAndChainBuffer(PNDISUIO_ADAPTER_CONTEXT AdapterContext,
+ PNDIS_PACKET Packet,
+ PVOID Buffer,
+ ULONG BufferSize,
+ BOOLEAN Front);
+
+PNDIS_PACKET
+CreatePacketFromPoolBuffer(PNDISUIO_ADAPTER_CONTEXT AdapterContext,
+ PVOID Buffer,
+ ULONG BufferSize);
+
+VOID
+CleanupAndFreePacket(PNDIS_PACKET Packet,
+ BOOLEAN FreePool);
+
+PNDISUIO_ADAPTER_CONTEXT
+FindAdapterContextByName(PNDIS_STRING DeviceName);
+
+VOID
+ReferenceAdapterContext(PNDISUIO_ADAPTER_CONTEXT AdapterContext);
+
+VOID
+DereferenceAdapterContextWithOpenEntry(PNDISUIO_ADAPTER_CONTEXT AdapterContext,
+ PNDISUIO_OPEN_ENTRY OpenEntry);
+
+/* protocol.c */
+VOID
+NTAPI
+NduOpenAdapterComplete(NDIS_HANDLE ProtocolBindingContext,
+ NDIS_STATUS Status,
+ NDIS_STATUS OpenStatus);
+
+VOID
+NTAPI
+NduCloseAdapterComplete(NDIS_HANDLE ProtocolBindingContext,
+ NDIS_STATUS Status);
+
+VOID
+NTAPI
+NduSendComplete(NDIS_HANDLE ProtocolBindingContext,
+ PNDIS_PACKET Packet,
+ NDIS_STATUS Status);
+
+VOID
+NTAPI
+NduTransferDataComplete(NDIS_HANDLE ProtocolBindingContext,
+ PNDIS_PACKET Packet,
+ NDIS_STATUS Status,
+ UINT BytesTransferred);
+
+VOID
+NTAPI
+NduResetComplete(NDIS_HANDLE ProtocolBindingContext,
+ NDIS_STATUS Status);
+
+VOID
+NTAPI
+NduRequestComplete(NDIS_HANDLE ProtocolBindingContext,
+ PNDIS_REQUEST NdisRequest,
+ NDIS_STATUS Status);
+
+NDIS_STATUS
+NTAPI
+NduReceive(NDIS_HANDLE ProtocolBindingContext,
+ NDIS_HANDLE MacReceiveContext,
+ PVOID HeaderBuffer,
+ UINT HeaderBufferSize,
+ PVOID LookAheadBuffer,
+ UINT LookaheadBufferSize,
+ UINT PacketSize);
+
+VOID
+NTAPI
+NduReceiveComplete(NDIS_HANDLE ProtocolBindingContext);
+
+VOID
+NTAPI
+NduStatus(NDIS_HANDLE ProtocolBindingContext,
+ NDIS_STATUS GeneralStatus,
+ PVOID StatusBuffer,
+ UINT StatusBufferSize);
+
+VOID
+NTAPI
+NduStatusComplete(NDIS_HANDLE ProtocolBindingContext);
+
+VOID
+NTAPI
+NduBindAdapter(PNDIS_STATUS Status,
+ NDIS_HANDLE BindContext,
+ PNDIS_STRING DeviceName,
+ PVOID SystemSpecific1,
+ PVOID SystemSpecific2);
+
+VOID
+NTAPI
+NduUnbindAdapter(PNDIS_STATUS Status,
+ NDIS_HANDLE ProtocolBindingContext,
+ NDIS_HANDLE UnbindContext);
+
+/* readwrite.c */
+NTSTATUS
+NTAPI
+NduDispatchRead(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp);
+
+NTSTATUS
+NTAPI
+NduDispatchWrite(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp);
+#endif /* __NDISUIO_H */
diff --git a/reactos/drivers/network/ndisuio/ndisuio.rbuild b/reactos/drivers/network/ndisuio/ndisuio.rbuild
new file mode 100644
index 00000000000..1ba528ec747
--- /dev/null
+++ b/reactos/drivers/network/ndisuio/ndisuio.rbuild
@@ -0,0 +1,19 @@
+
+
+
+ .
+ include/reactos/drivers/ndisuio
+
+
+ ndis
+ ntoskrnl
+ hal
+ ndisuio.h
+ createclose.c
+ ioctl.c
+ main.c
+ misc.c
+ protocol.c
+ readwrite.c
+ ndisuio.rc
+
diff --git a/reactos/drivers/network/ndisuio/ndisuio.rc b/reactos/drivers/network/ndisuio/ndisuio.rc
new file mode 100644
index 00000000000..bf0e8f4c7ae
--- /dev/null
+++ b/reactos/drivers/network/ndisuio/ndisuio.rc
@@ -0,0 +1,5 @@
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "NDIS User-Mode I/O Protocol Driver\0"
+#define REACTOS_STR_INTERNAL_NAME "ndisuio\0"
+#define REACTOS_STR_ORIGINAL_FILENAME "ndisuio.sys\0"
+#include
diff --git a/reactos/drivers/network/ndisuio/protocol.c b/reactos/drivers/network/ndisuio/protocol.c
new file mode 100644
index 00000000000..4b8fe31413c
--- /dev/null
+++ b/reactos/drivers/network/ndisuio/protocol.c
@@ -0,0 +1,496 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS NDIS User I/O driver
+ * FILE: protocol.c
+ * PURPOSE: Protocol stuff
+ * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
+ */
+
+#include "ndisuio.h"
+
+#define NDEBUG
+#include
+
+VOID
+NTAPI
+NduOpenAdapterComplete(NDIS_HANDLE ProtocolBindingContext,
+ NDIS_STATUS Status,
+ NDIS_STATUS OpenStatus)
+{
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext;
+
+ DPRINT("Asynchronous adapter open completed\n");
+
+ /* Store the final status and signal the event */
+ AdapterContext->AsyncStatus = Status;
+ KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE);
+}
+
+VOID
+NTAPI
+NduCloseAdapterComplete(NDIS_HANDLE ProtocolBindingContext,
+ NDIS_STATUS Status)
+{
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext;
+
+ DPRINT("Asynchronous adapter close completed\n");
+
+ /* Store the final status and signal the event */
+ AdapterContext->AsyncStatus = Status;
+ KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE);
+}
+
+VOID
+NTAPI
+NduSendComplete(NDIS_HANDLE ProtocolBindingContext,
+ PNDIS_PACKET Packet,
+ NDIS_STATUS Status)
+{
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext;
+
+ DPRINT("Asynchronous adapter send completed\n");
+
+ /* Store the final status and signal the event */
+ AdapterContext->AsyncStatus = Status;
+ KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE);
+}
+
+VOID
+NTAPI
+NduTransferDataComplete(NDIS_HANDLE ProtocolBindingContext,
+ PNDIS_PACKET Packet,
+ NDIS_STATUS Status,
+ UINT BytesTransferred)
+{
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext;
+
+ DPRINT("Asynchronous adapter transfer completed\n");
+
+ /* Store the final status and signal the event */
+ AdapterContext->AsyncStatus = Status;
+ KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE);
+}
+
+VOID
+NTAPI
+NduResetComplete(NDIS_HANDLE ProtocolBindingContext,
+ NDIS_STATUS Status)
+{
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext;
+
+ DPRINT("Asynchronous adapter reset completed\n");
+
+ /* Store the final status and signal the event */
+ AdapterContext->AsyncStatus = Status;
+ KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE);
+}
+
+VOID
+NTAPI
+NduRequestComplete(NDIS_HANDLE ProtocolBindingContext,
+ PNDIS_REQUEST NdisRequest,
+ NDIS_STATUS Status)
+{
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext;
+
+ DPRINT("Asynchronous adapter request completed\n");
+
+ /* Store the final status and signal the event */
+ AdapterContext->AsyncStatus = Status;
+ KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE);
+}
+
+NDIS_STATUS
+NTAPI
+NduReceive(NDIS_HANDLE ProtocolBindingContext,
+ NDIS_HANDLE MacReceiveContext,
+ PVOID HeaderBuffer,
+ UINT HeaderBufferSize,
+ PVOID LookAheadBuffer,
+ UINT LookaheadBufferSize,
+ UINT PacketSize)
+{
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext;
+ PNDISUIO_PACKET_ENTRY PacketEntry;
+ PVOID PacketBuffer;
+ PNDIS_PACKET Packet;
+ NDIS_STATUS Status;
+ UINT BytesTransferred;
+
+ DPRINT("Received a %d byte packet\n", PacketSize);
+
+ /* Discard if nobody is waiting for it */
+ if (AdapterContext->OpenCount == 0)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ /* Allocate a buffer to hold the packet data and header */
+ PacketBuffer = ExAllocatePool(NonPagedPool, PacketSize + HeaderBufferSize);
+ if (!PacketBuffer)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ /* Allocate the packet descriptor and buffer */
+ Packet = CreatePacketFromPoolBuffer(AdapterContext,
+ (PUCHAR)PacketBuffer + HeaderBufferSize,
+ PacketSize);
+ if (!Packet)
+ {
+ ExFreePool(PacketBuffer);
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
+
+ /* Transfer the packet data into our data buffer */
+ if (LookaheadBufferSize == PacketSize)
+ {
+ NdisCopyLookaheadData((PVOID)((PUCHAR)PacketBuffer + HeaderBufferSize),
+ LookAheadBuffer,
+ PacketSize,
+ AdapterContext->MacOptions);
+ BytesTransferred = PacketSize;
+ }
+ else
+ {
+ NdisTransferData(&Status,
+ AdapterContext->BindingHandle,
+ MacReceiveContext,
+ 0,
+ PacketSize,
+ Packet,
+ &BytesTransferred);
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&AdapterContext->AsyncEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ Status = AdapterContext->AsyncStatus;
+ }
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DPRINT1("Failed to transfer data with status 0x%x\n", Status);
+ CleanupAndFreePacket(Packet, TRUE);
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
+ }
+
+ /* Copy the header data */
+ RtlCopyMemory(PacketBuffer, HeaderBuffer, HeaderBufferSize);
+
+ /* Free the packet descriptor and buffers
+ but not the pool because we still need it */
+ CleanupAndFreePacket(Packet, FALSE);
+
+ /* Allocate a packet entry from pool */
+ PacketEntry = ExAllocatePool(NonPagedPool, sizeof(NDISUIO_PACKET_ENTRY) + BytesTransferred + HeaderBufferSize - 1);
+ if (!PacketEntry)
+ {
+ ExFreePool(PacketBuffer);
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ /* Initialize the packet entry and copy in packet data */
+ PacketEntry->PacketLength = BytesTransferred + HeaderBufferSize;
+ RtlCopyMemory(PacketEntry->PacketData, PacketBuffer, PacketEntry->PacketLength);
+
+ /* Free the old buffer */
+ ExFreePool(PacketBuffer);
+
+ /* Insert the packet on the adapter's packet list */
+ ExInterlockedInsertTailList(&AdapterContext->PacketList,
+ &PacketEntry->ListEntry,
+ &AdapterContext->Spinlock);
+
+ /* Signal the read event */
+ KeSetEvent(&AdapterContext->PacketReadEvent,
+ IO_NETWORK_INCREMENT,
+ FALSE);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+NduReceiveComplete(NDIS_HANDLE ProtocolBindingContext)
+{
+ /* No op */
+}
+
+VOID
+NTAPI
+NduStatus(NDIS_HANDLE ProtocolBindingContext,
+ NDIS_STATUS GeneralStatus,
+ PVOID StatusBuffer,
+ UINT StatusBufferSize)
+{
+ /* FIXME: Implement status tracking */
+}
+
+VOID
+NTAPI
+NduStatusComplete(NDIS_HANDLE ProtocolBindingContext)
+{
+ /* FIXME: Implement status tracking */
+}
+
+static
+NDIS_STATUS
+UnbindAdapterByContext(PNDISUIO_ADAPTER_CONTEXT AdapterContext)
+{
+ KIRQL OldIrql;
+ PLIST_ENTRY CurrentEntry;
+ PNDISUIO_OPEN_ENTRY OpenEntry;
+ PNDISUIO_PACKET_ENTRY PacketEntry;
+ NDIS_STATUS Status;
+
+ DPRINT("Unbinding adapter %wZ\n", &AdapterContext->DeviceName);
+
+ /* FIXME: We don't do anything with outstanding reads */
+
+ /* Remove the adapter context from the global list */
+ KeAcquireSpinLock(&GlobalAdapterListLock, &OldIrql);
+ RemoveEntryList(&AdapterContext->ListEntry);
+ KeReleaseSpinLock(&GlobalAdapterListLock, OldIrql);
+
+ /* Free the device name string */
+ RtlFreeUnicodeString(&AdapterContext->DeviceName);
+
+ /* Invalidate all handles to this adapter */
+ CurrentEntry = AdapterContext->OpenEntryList.Flink;
+ while (CurrentEntry != &AdapterContext->OpenEntryList)
+ {
+ OpenEntry = CONTAINING_RECORD(CurrentEntry, NDISUIO_OPEN_ENTRY, ListEntry);
+
+ /* Make sure the entry is sane */
+ ASSERT(OpenEntry->FileObject);
+
+ /* Remove the adapter context pointer */
+ ASSERT(AdapterContext == OpenEntry->FileObject->FsContext);
+ OpenEntry->FileObject->FsContext = NULL;
+ AdapterContext->OpenCount--;
+
+ /* Remove the open entry pointer */
+ ASSERT(OpenEntry == OpenEntry->FileObject->FsContext2);
+ OpenEntry->FileObject->FsContext2 = NULL;
+
+ /* Move to the next entry */
+ CurrentEntry = CurrentEntry->Flink;
+
+ /* Free the open entry */
+ ExFreePool(OpenEntry);
+ }
+
+ /* If this fails, we have a refcount mismatch somewhere */
+ ASSERT(AdapterContext->OpenCount == 0);
+
+ /* Free all pending packet entries */
+ CurrentEntry = AdapterContext->PacketList.Flink;
+ while (CurrentEntry != &AdapterContext->PacketList)
+ {
+ PacketEntry = CONTAINING_RECORD(CurrentEntry, NDISUIO_PACKET_ENTRY, ListEntry);
+
+ /* Move to the next entry */
+ CurrentEntry = CurrentEntry->Flink;
+
+ /* Free the packet entry */
+ ExFreePool(PacketEntry);
+ }
+
+ /* Send the close request */
+ NdisCloseAdapter(&Status,
+ AdapterContext->BindingHandle);
+
+ /* Wait for a pending close */
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&AdapterContext->AsyncEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ Status = AdapterContext->AsyncStatus;
+ }
+
+ /* Free the context */
+ ExFreePool(AdapterContext);
+
+ return Status;
+}
+
+static
+NDIS_STATUS
+BindAdapterByName(PNDIS_STRING DeviceName)
+{
+ NDIS_STATUS OpenErrorStatus;
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext;
+ NDIS_MEDIUM SupportedMedia[1] = {NdisMedium802_3};
+ UINT SelectedMedium;
+ NDIS_STATUS Status;
+ NDIS_REQUEST Request;
+
+ /* Allocate the adapter context */
+ AdapterContext = ExAllocatePool(NonPagedPool, sizeof(*AdapterContext));
+ if (!AdapterContext)
+ {
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ /* Set up the adapter context */
+ RtlZeroMemory(AdapterContext, sizeof(*AdapterContext));
+ KeInitializeEvent(&AdapterContext->AsyncEvent, SynchronizationEvent, FALSE);
+ KeInitializeEvent(&AdapterContext->PacketReadEvent, SynchronizationEvent, FALSE);
+ KeInitializeSpinLock(&AdapterContext->Spinlock);
+ InitializeListHead(&AdapterContext->PacketList);
+ InitializeListHead(&AdapterContext->OpenEntryList);
+ AdapterContext->OpenCount = 0;
+
+ AdapterContext->DeviceName.Length =
+ AdapterContext->DeviceName.MaximumLength = DeviceName->Length;
+ AdapterContext->DeviceName.Buffer = ExAllocatePool(NonPagedPool, DeviceName->Length);
+ if (!AdapterContext->DeviceName.Buffer)
+ {
+ ExFreePool(AdapterContext);
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ /* Copy the device name into the adapter context */
+ RtlCopyMemory(AdapterContext->DeviceName.Buffer, DeviceName->Buffer, DeviceName->Length);
+
+ DPRINT("Binding adapter %wZ\n", &AdapterContext->DeviceName);
+
+ /* Create the buffer pool */
+ NdisAllocateBufferPool(&Status,
+ &AdapterContext->BufferPoolHandle,
+ 50);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DPRINT1("Failed to allocate buffer pool with status 0x%x\n", Status);
+ RtlFreeUnicodeString(&AdapterContext->DeviceName);
+ ExFreePool(AdapterContext);
+ return Status;
+ }
+
+ /* Create the packet pool */
+ NdisAllocatePacketPool(&Status,
+ &AdapterContext->PacketPoolHandle,
+ 25,
+ PROTOCOL_RESERVED_SIZE_IN_PACKET);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DPRINT1("Failed to allocate packet pool with status 0x%x\n", Status);
+ NdisFreeBufferPool(AdapterContext->BufferPoolHandle);
+ RtlFreeUnicodeString(&AdapterContext->DeviceName);
+ ExFreePool(AdapterContext);
+ return Status;
+ }
+
+ /* Send the open request */
+ NdisOpenAdapter(&Status,
+ &OpenErrorStatus,
+ &AdapterContext->BindingHandle,
+ &SelectedMedium,
+ SupportedMedia,
+ 1,
+ GlobalProtocolHandle,
+ AdapterContext,
+ DeviceName,
+ 0,
+ NULL);
+
+ /* Wait for a pending open */
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&AdapterContext->AsyncEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ Status = AdapterContext->AsyncStatus;
+ }
+
+ /* Check the final status */
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DPRINT1("Failed to open adapter for bind with status 0x%x\n", Status);
+ NdisFreePacketPool(AdapterContext->PacketPoolHandle);
+ NdisFreeBufferPool(AdapterContext->BufferPoolHandle);
+ RtlFreeUnicodeString(&AdapterContext->DeviceName);
+ ExFreePool(AdapterContext);
+ return Status;
+ }
+
+ /* Get the MAC options */
+ Request.RequestType = NdisRequestQueryInformation;
+ Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS;
+ Request.DATA.QUERY_INFORMATION.InformationBuffer = &AdapterContext->MacOptions;
+ Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(ULONG);
+ NdisRequest(&Status,
+ AdapterContext->BindingHandle,
+ &Request);
+
+ /* Wait for a pending request */
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&AdapterContext->AsyncEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ Status = AdapterContext->AsyncStatus;
+ }
+
+ /* Check the final status */
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDIS_STATUS CloseStatus;
+
+ DPRINT1("Failed to get MAC options with status 0x%x\n", Status);
+
+ NdisCloseAdapter(&CloseStatus,
+ AdapterContext->BindingHandle);
+ if (CloseStatus == NDIS_STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&AdapterContext->AsyncEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+
+ NdisFreePacketPool(AdapterContext->PacketPoolHandle);
+ NdisFreeBufferPool(AdapterContext->BufferPoolHandle);
+ RtlFreeUnicodeString(&AdapterContext->DeviceName);
+ ExFreePool(AdapterContext);
+ return Status;
+ }
+
+ /* Add the adapter context to the global list */
+ ExInterlockedInsertTailList(&GlobalAdapterList,
+ &AdapterContext->ListEntry,
+ &GlobalAdapterListLock);
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+NduBindAdapter(PNDIS_STATUS Status,
+ NDIS_HANDLE BindContext,
+ PNDIS_STRING DeviceName,
+ PVOID SystemSpecific1,
+ PVOID SystemSpecific2)
+{
+ /* Use our helper function to create a context for this adapter */
+ *Status = BindAdapterByName(DeviceName);
+}
+
+VOID
+NTAPI
+NduUnbindAdapter(PNDIS_STATUS Status,
+ NDIS_HANDLE ProtocolBindingContext,
+ NDIS_HANDLE UnbindContext)
+{
+ /* This is forced unbind. UnbindAdapterByContext() will take care of
+ * invalidating file handles pointer to this adapter for us */
+ *Status = UnbindAdapterByContext(ProtocolBindingContext);
+}
+
diff --git a/reactos/drivers/network/ndisuio/readwrite.c b/reactos/drivers/network/ndisuio/readwrite.c
new file mode 100644
index 00000000000..ceae632c156
--- /dev/null
+++ b/reactos/drivers/network/ndisuio/readwrite.c
@@ -0,0 +1,209 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS NDIS User I/O driver
+ * FILE: readwrite.c
+ * PURPOSE: Handles IRP_MJ_READ and IRP_MJ_WRITE
+ * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
+ */
+
+#include "ndisuio.h"
+
+#define NDEBUG
+#include
+
+static
+VOID
+NTAPI
+ReadIrpCancel(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
+ PNDISUIO_PACKET_ENTRY PacketEntry;
+
+ /* Release the cancel spin lock */
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+ /* Indicate a 0-byte packet on the queue to cancel the read */
+ PacketEntry = ExAllocatePool(NonPagedPool, sizeof(NDISUIO_PACKET_ENTRY));
+ if (PacketEntry)
+ {
+ PacketEntry->PacketLength = 0;
+
+ ExInterlockedInsertHeadList(&AdapterContext->PacketList,
+ &PacketEntry->ListEntry,
+ &AdapterContext->Spinlock);
+
+ KeSetEvent(&AdapterContext->PacketReadEvent, IO_NO_INCREMENT, FALSE);
+ }
+}
+
+NTSTATUS
+NTAPI
+NduDispatchRead(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
+ PNDISUIO_OPEN_ENTRY OpenEntry = IrpSp->FileObject->FsContext2;
+ KIRQL OldIrql, OldCancelIrql;
+ NTSTATUS Status;
+ PLIST_ENTRY ListEntry;
+ PNDISUIO_PACKET_ENTRY PacketEntry = NULL;
+ ULONG BytesCopied = 0;
+
+ ASSERT(DeviceObject == GlobalDeviceObject);
+
+ if (OpenEntry->WriteOnly)
+ {
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Make the read cancellable */
+ IoAcquireCancelSpinLock(&OldCancelIrql);
+ IoSetCancelRoutine(Irp, ReadIrpCancel);
+ if (Irp->Cancel)
+ {
+ IoReleaseCancelSpinLock(OldCancelIrql);
+
+ /* Indicate a 0 byte read */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return STATUS_SUCCESS;
+ }
+ IoReleaseCancelSpinLock(OldCancelIrql);
+
+ while (TRUE)
+ {
+ KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql);
+
+ /* Check if we have a packet */
+ if (IsListEmpty(&AdapterContext->PacketList))
+ {
+ KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
+
+ /* Wait for a packet (in the context of the calling user thread) */
+ Status = KeWaitForSingleObject(&AdapterContext->PacketReadEvent,
+ UserRequest,
+ UserMode,
+ TRUE,
+ NULL);
+ if (Status != STATUS_SUCCESS)
+ {
+ /* Remove the cancel routine */
+ IoAcquireCancelSpinLock(&OldCancelIrql);
+ IoSetCancelRoutine(Irp, NULL);
+ IoReleaseCancelSpinLock(OldCancelIrql);
+
+ break;
+ }
+ }
+ else
+ {
+ /* Remove the cancel routine */
+ IoAcquireCancelSpinLock(&OldCancelIrql);
+ IoSetCancelRoutine(Irp, NULL);
+ IoReleaseCancelSpinLock(OldCancelIrql);
+
+ /* Remove the first packet in the list */
+ ListEntry = RemoveHeadList(&AdapterContext->PacketList);
+ PacketEntry = CONTAINING_RECORD(ListEntry, NDISUIO_PACKET_ENTRY, ListEntry);
+
+ /* Release the adapter lock */
+ KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
+
+ /* And we're done with this loop */
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ /* Check if we got a packet */
+ if (PacketEntry != NULL)
+ {
+ /* Find the right amount of bytes to copy */
+ BytesCopied = PacketEntry->PacketLength;
+ if (BytesCopied > IrpSp->Parameters.Read.Length)
+ BytesCopied = IrpSp->Parameters.Read.Length;
+
+ /* Copy the packet */
+ RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
+ &PacketEntry->PacketData[0],
+ BytesCopied);
+
+ /* Free the packet entry */
+ ExFreePool(PacketEntry);
+ }
+ else
+ {
+ /* Something failed */
+ BytesCopied = 0;
+ }
+
+ /* Complete the IRP */
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = BytesCopied;
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+NduDispatchWrite(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
+ PNDIS_PACKET Packet;
+ NDIS_STATUS Status;
+ ULONG BytesCopied = 0;
+
+ ASSERT(DeviceObject == GlobalDeviceObject);
+
+ /* Create a packet and buffer descriptor for this user buffer */
+ Packet = CreatePacketFromPoolBuffer(AdapterContext,
+ Irp->AssociatedIrp.SystemBuffer,
+ IrpSp->Parameters.Write.Length);
+ if (Packet)
+ {
+ /* Send it via NDIS */
+ NdisSend(&Status,
+ AdapterContext->BindingHandle,
+ Packet);
+
+ /* Wait for the send */
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&AdapterContext->AsyncEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ Status = AdapterContext->AsyncStatus;
+ }
+
+ /* Check if it succeeded */
+ if (Status == NDIS_STATUS_SUCCESS)
+ BytesCopied = IrpSp->Parameters.Write.Length;
+
+ CleanupAndFreePacket(Packet, FALSE);
+ }
+ else
+ {
+ /* No memory */
+ Status = STATUS_NO_MEMORY;
+ }
+
+ /* Complete the IRP */
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = BytesCopied;
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return Status;
+}
\ No newline at end of file
diff --git a/reactos/include/psdk/ntddndis.h b/reactos/include/psdk/ntddndis.h
index 10d62d19d4c..720eeeec86d 100644
--- a/reactos/include/psdk/ntddndis.h
+++ b/reactos/include/psdk/ntddndis.h
@@ -42,6 +42,22 @@ typedef enum _NDIS_DEVICE_POWER_STATE {
NdisDeviceStateMaximum
} NDIS_DEVICE_POWER_STATE, *PNDIS_DEVICE_POWER_STATE;
+typedef enum _NDIS_802_11_WEP_STATUS
+{
+ Ndis802_11WEPEnabled,
+ Ndis802_11WEPDisabled,
+ Ndis802_11WEPKeyAbsent,
+ Ndis802_11WEPNotSupported
+} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS;
+
+typedef enum _NDIS_802_11_AUTHENTICATION_MODE
+{
+ Ndis802_11AuthModeOpen,
+ Ndis802_11AuthModeShared,
+ Ndis802_11AuthModeAutoSwitch,
+ Ndis802_11AuthModeMax
+} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE;
+
typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE
{
Ndis802_11IBSS,
@@ -117,6 +133,14 @@ typedef struct _NDIS_802_11_BSSID_LIST
NDIS_WLAN_BSSID Bssid[1];
} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST;
+typedef struct _NDIS_802_11_WEP
+{
+ ULONG Length;
+ ULONG KeyIndex;
+ ULONG KeyLength;
+ UCHAR KeyMaterial[1];
+} NDIS_802_11_WEP, *PNDIS_802_11_WEP;
+
typedef struct _NDIS_PM_WAKE_UP_CAPABILITIES {
NDIS_DEVICE_POWER_STATE MinMagicPacketWakeUp;
NDIS_DEVICE_POWER_STATE MinPatternWakeUp;
@@ -265,8 +289,34 @@ typedef ULONG NDIS_OID, *PNDIS_OID;
#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206
#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207
-#define OID_802_11_BSSID_LIST 0x0D010217
-#define OID_802_11_BSSID_LIST_SCAN 0x0D01011A
+/* IEEE 802.11 (WLAN) OIDs */
+#define OID_802_11_BSSID 0x0D010101
+#define OID_802_11_SSID 0x0D010102
+#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x0D010203
+#define OID_802_11_NETWORK_TYPE_IN_USE 0x0D010204
+#define OID_802_11_TX_POWER_LEVEL 0x0D010205
+#define OID_802_11_RSSI 0x0D010206
+#define OID_802_11_RSSI_TRIGGER 0x0D010207
+#define OID_802_11_INFRASTRUCTURE_MODE 0x0D010108
+#define OID_802_11_FRAGMENTATION_THRESHOLD 0x0D010209
+#define OID_802_11_RTS_THRESHOLD 0x0D01020A
+#define OID_802_11_NUMBER_OF_ANTENNAS 0x0D01020B
+#define OID_802_11_RX_ANTENNA_SELECTED 0x0D01020C
+#define OID_802_11_TX_ANTENNA_SELECTED 0x0D01020D
+#define OID_802_11_SUPPORTED_RATES 0x0D01020E
+#define OID_802_11_DESIRED_RATES 0x0D010210
+#define OID_802_11_CONFIGURATION 0x0D010211
+#define OID_802_11_STATISTICS 0x0D020212
+#define OID_802_11_ADD_WEP 0x0D010113
+#define OID_802_11_REMOVE_WEP 0x0D010114
+#define OID_802_11_DISASSOCIATE 0x0D010115
+#define OID_802_11_POWER_MODE 0x0D010216
+#define OID_802_11_BSSID_LIST 0x0D010217
+#define OID_802_11_AUTHENTICATION_MODE 0x0D010118
+#define OID_802_11_PRIVACY_FILTER 0x0D010119
+#define OID_802_11_BSSID_LIST_SCAN 0x0D01011A
+#define OID_802_11_WEP_STATUS 0x0D01011B
+#define OID_802_11_RELOAD_DEFAULTS 0x0D01011C
/* OID_GEN_MINIPORT_INFO constants */
#define NDIS_MINIPORT_BUS_MASTER 0x00000001
diff --git a/reactos/include/reactos/drivers/ndisuio/nuiouser.h b/reactos/include/reactos/drivers/ndisuio/nuiouser.h
new file mode 100755
index 00000000000..36c1a9bdca7
--- /dev/null
+++ b/reactos/include/reactos/drivers/ndisuio/nuiouser.h
@@ -0,0 +1,59 @@
+#ifndef __NUIOUSER_H
+#define __NUIOUSER_H
+
+/* Device names (NT and DOS style) */
+#define NDISUIO_DEVICE_NAME_NT L"\\Device\\Ndisuio"
+#define NDISUIO_DEVICE_NAME_DOS L"\\DosDevices\\Ndisuio"
+
+/* Device name for user apps */
+#define NDISUIO_DEVICE_NAME L"\\\\.\\\\Ndisuio"
+
+/* Links a file handle with a bound NIC */
+#define IOCTL_NDISUIO_OPEN_DEVICE \
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x200, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/* Queries an OID for the bound NIC */
+#define IOCTL_NDISUIO_QUERY_OID_VALUE \
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x201, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_NDISUIO_SET_ETHER_TYPE \
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x202, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/* Queries binding information during enumeration */
+#define IOCTL_NDISUIO_QUERY_BINDING \
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x203, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/* Waits for any pending bindings */
+#define IOCTL_NDISUIO_BIND_WAIT \
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x204, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/* Sets an OID for a bound NIC */
+#define IOCTL_NDISUIO_SET_OID_VALUE \
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x205, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/* Passed as a parameter to IOCTL_NDISUIO_QUERY_OID_VALUE */
+typedef struct _NDISUIO_QUERY_OID
+{
+ NDIS_OID Oid;
+ UCHAR Data[sizeof(ULONG)];
+} NDISUIO_QUERY_OID, *PNDISUIO_QUERY_OID;
+
+/* Passed as a parameter to IOCTL_NDISUIO_SET_OID_VALUE */
+typedef struct _NDISUIO_SET_OID
+{
+ NDIS_OID Oid;
+ UCHAR Data[sizeof(ULONG)];
+} NDISUIO_SET_OID, *PNDISUIO_SET_OID;
+
+/* Passed as a parameter to IOCTL_NDISUIO_QUERY_BINDING */
+typedef struct _NDISUIO_QUERY_BINDING
+{
+ ULONG BindingIndex;
+ ULONG DeviceNameOffset;
+ ULONG DeviceNameLength;
+ ULONG DeviceDescrOffset;
+ ULONG DeviceDescrLength;
+} NDISUIO_QUERY_BINDING, *PNDISUIO_QUERY_BINDING;
+
+#endif
+