1 /*
2  * PROJECT:     ReactOS WLAN command-line configuration utility
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Allows WLAN configuration via the command prompt
5  * COPYRIGHT:   Copyright 2012 Cameron Gutman <cameron.gutman@reactos.org>
6  */
7 
8 #include <stdio.h>
9 #include <stdarg.h>
10 #include <tchar.h>
11 
12 #include <windef.h>
13 #include <winbase.h>
14 #include <devioctl.h>
15 #include <ntddndis.h>
16 #include <nuiouser.h>
17 #include <iphlpapi.h>
18 
19 #include <conutils.h>
20 
21 #include "resource.h"
22 
23 BOOL bScan = FALSE;
24 
25 BOOL bConnect = FALSE;
26 WCHAR *sSsid = NULL;
27 WCHAR *sWepKey = NULL;
28 BOOL bAdhoc = FALSE;
29 
30 BOOL bDisconnect = FALSE;
31 
32 VOID DoFormatMessage(DWORD ErrorCode)
33 {
34     if (ErrorCode == ERROR_SUCCESS)
35         return;
36 
37     ConMsgPuts(StdErr, FORMAT_MESSAGE_FROM_SYSTEM,
38                NULL, ErrorCode, LANG_USER_DEFAULT);
39 }
40 
41 HANDLE
42 OpenDriverHandle(VOID)
43 {
44     HANDLE hDriver;
45     DWORD dwBytesReturned;
46     BOOL bSuccess;
47 
48     /* Open a handle to the NDISUIO driver */
49     hDriver = CreateFileW(NDISUIO_DEVICE_NAME,
50                           GENERIC_READ | GENERIC_WRITE,
51                           0,
52                           NULL,
53                           OPEN_EXISTING,
54                           FILE_ATTRIBUTE_NORMAL,
55                           NULL);
56     if (hDriver == INVALID_HANDLE_VALUE)
57         return INVALID_HANDLE_VALUE;
58 
59     /* Wait for binds */
60     bSuccess = DeviceIoControl(hDriver,
61                                IOCTL_NDISUIO_BIND_WAIT,
62                                NULL,
63                                0,
64                                NULL,
65                                0,
66                                &dwBytesReturned,
67                                NULL);
68     if (!bSuccess)
69     {
70         CloseHandle(hDriver);
71         return INVALID_HANDLE_VALUE;
72     }
73 
74     return hDriver;
75 }
76 
77 BOOL
78 IsWlanAdapter(HANDLE hAdapter)
79 {
80     BOOL bSuccess;
81     DWORD dwBytesReturned;
82     NDISUIO_QUERY_OID QueryOid;
83 
84     /* WLAN drivers must support this OID */
85     QueryOid.Oid = OID_GEN_PHYSICAL_MEDIUM;
86 
87     bSuccess = DeviceIoControl(hAdapter,
88                                IOCTL_NDISUIO_QUERY_OID_VALUE,
89                                &QueryOid,
90                                sizeof(QueryOid),
91                                &QueryOid,
92                                sizeof(QueryOid),
93                                &dwBytesReturned,
94                                NULL);
95     if (!bSuccess || *(PULONG)QueryOid.Data != NdisPhysicalMediumWirelessLan)
96         return FALSE;
97 
98     return TRUE;
99 }
100 
101 BOOL
102 OpenAdapterHandle(DWORD Index, HANDLE *hAdapter, IP_ADAPTER_INDEX_MAP *IpInfo)
103 {
104     HANDLE hDriver;
105     BOOL bSuccess;
106     DWORD dwBytesReturned;
107     DWORD QueryBindingSize = sizeof(NDISUIO_QUERY_BINDING) + (1024 * sizeof(WCHAR));
108     PNDISUIO_QUERY_BINDING QueryBinding;
109     DWORD dwStatus, dwSize;
110     LONG i;
111     PIP_INTERFACE_INFO InterfaceInfo = NULL;
112 
113     /* Open the driver handle */
114     hDriver = OpenDriverHandle();
115     if (hDriver == INVALID_HANDLE_VALUE)
116         return FALSE;
117 
118     /* Allocate the binding struct */
119     QueryBinding = HeapAlloc(GetProcessHeap(), 0, QueryBindingSize);
120     if (!QueryBinding)
121     {
122         CloseHandle(hDriver);
123         return FALSE;
124     }
125 
126     /* Query the adapter binding information */
127     QueryBinding->BindingIndex = Index;
128     bSuccess = DeviceIoControl(hDriver,
129                                IOCTL_NDISUIO_QUERY_BINDING,
130                                QueryBinding,
131                                QueryBindingSize,
132                                QueryBinding,
133                                QueryBindingSize,
134                                &dwBytesReturned,
135                                NULL);
136 
137     if (!bSuccess)
138     {
139         HeapFree(GetProcessHeap(), 0, QueryBinding);
140         CloseHandle(hDriver);
141         return FALSE;
142     }
143 
144     /* Bind to the adapter */
145     bSuccess = DeviceIoControl(hDriver,
146                                IOCTL_NDISUIO_OPEN_DEVICE,
147                                (PUCHAR)QueryBinding + QueryBinding->DeviceNameOffset,
148                                QueryBinding->DeviceNameLength,
149                                NULL,
150                                0,
151                                &dwBytesReturned,
152                                NULL);
153 
154     if (!bSuccess)
155     {
156         HeapFree(GetProcessHeap(), 0, QueryBinding);
157         CloseHandle(hDriver);
158         return FALSE;
159     }
160 
161     /* Get interface info from the IP helper */
162     dwSize = sizeof(IP_INTERFACE_INFO);
163     do {
164         if (InterfaceInfo) HeapFree(GetProcessHeap(), 0, InterfaceInfo);
165         InterfaceInfo = HeapAlloc(GetProcessHeap(), 0, dwSize);
166         if (!InterfaceInfo)
167         {
168             HeapFree(GetProcessHeap(), 0, QueryBinding);
169             CloseHandle(hDriver);
170             return FALSE;
171         }
172         dwStatus = GetInterfaceInfo(InterfaceInfo, &dwSize);
173     } while (dwStatus == ERROR_INSUFFICIENT_BUFFER);
174 
175     if (dwStatus != NO_ERROR)
176     {
177         HeapFree(GetProcessHeap(), 0, QueryBinding);
178         HeapFree(GetProcessHeap(), 0, InterfaceInfo);
179         CloseHandle(hDriver);
180         return FALSE;
181     }
182 
183     for (i = 0; i < InterfaceInfo->NumAdapters; i++)
184     {
185         PWCHAR InterfaceGuid = wcschr(InterfaceInfo->Adapter[i].Name, L'{');
186 
187         if (InterfaceGuid == NULL)
188             continue;
189 
190         if (wcsstr((PWCHAR)((PUCHAR)QueryBinding + QueryBinding->DeviceNameOffset),
191                    InterfaceGuid))
192         {
193             *IpInfo = InterfaceInfo->Adapter[i];
194             *hAdapter = hDriver;
195 
196             HeapFree(GetProcessHeap(), 0, QueryBinding);
197             HeapFree(GetProcessHeap(), 0, InterfaceInfo);
198 
199             return TRUE;
200         }
201     }
202 
203     HeapFree(GetProcessHeap(), 0, QueryBinding);
204     HeapFree(GetProcessHeap(), 0, InterfaceInfo);
205     CloseHandle(hDriver);
206 
207     return FALSE;
208 }
209 
210 /* Only works with the first adapter for now */
211 BOOL
212 OpenWlanAdapter(HANDLE *hAdapter, IP_ADAPTER_INDEX_MAP *IpInfo)
213 {
214     DWORD dwCurrentIndex;
215 
216     for (dwCurrentIndex = 0; ; dwCurrentIndex++)
217     {
218         if (!OpenAdapterHandle(dwCurrentIndex, hAdapter, IpInfo))
219             break;
220 
221         if (IsWlanAdapter(*hAdapter))
222             return TRUE;
223         else
224             CloseHandle(*hAdapter);
225     }
226 
227     return FALSE;
228 }
229 
230 BOOL
231 WlanDisconnect(HANDLE hAdapter, PIP_ADAPTER_INDEX_MAP IpInfo)
232 {
233     BOOL bSuccess;
234     DWORD dwBytesReturned;
235     NDISUIO_SET_OID SetOid;
236 
237     /* Release this IP address */
238     IpReleaseAddress(IpInfo);
239 
240     /* Disassociate from the AP */
241     SetOid.Oid = OID_802_11_DISASSOCIATE;
242     bSuccess = DeviceIoControl(hAdapter,
243                                IOCTL_NDISUIO_SET_OID_VALUE,
244                                &SetOid,
245                                FIELD_OFFSET(NDISUIO_SET_OID, Data),
246                                NULL,
247                                0,
248                                &dwBytesReturned,
249                                NULL);
250     if (!bSuccess)
251         return FALSE;
252 
253     ConResPuts(StdOut, IDS_SUCCESS);
254     return TRUE;
255 }
256 
257 static
258 UCHAR
259 CharToHex(WCHAR Char)
260 {
261     if ((Char >= L'0') && (Char <= L'9'))
262         return Char - L'0';
263 
264     if ((Char >= L'a') && (Char <= L'f'))
265         return Char - L'a' + 10;
266 
267     if ((Char >= L'A') && (Char <= L'F'))
268         return Char - L'A' + 10;
269 
270     return 0;
271 }
272 
273 BOOL
274 WlanPrintCurrentStatus(HANDLE hAdapter)
275 {
276     PNDISUIO_QUERY_OID QueryOid;
277     DWORD QueryOidSize;
278     BOOL bSuccess;
279     DWORD dwBytesReturned;
280     PNDIS_802_11_SSID SsidInfo;
281     CHAR SsidBuffer[NDIS_802_11_LENGTH_SSID + 1];
282     DWORD i;
283     WCHAR szMsgBuf[128];
284 
285     QueryOidSize = FIELD_OFFSET(NDISUIO_QUERY_OID, Data) + sizeof(NDIS_802_11_SSID);
286     QueryOid = HeapAlloc(GetProcessHeap(), 0, QueryOidSize);
287     if (!QueryOid)
288         return FALSE;
289 
290     QueryOid->Oid = OID_802_11_SSID;
291     SsidInfo = (PNDIS_802_11_SSID)QueryOid->Data;
292 
293     bSuccess = DeviceIoControl(hAdapter,
294                                IOCTL_NDISUIO_QUERY_OID_VALUE,
295                                QueryOid,
296                                QueryOidSize,
297                                QueryOid,
298                                QueryOidSize,
299                                &dwBytesReturned,
300                                NULL);
301     if (!bSuccess)
302     {
303         HeapFree(GetProcessHeap(), 0, QueryOid);
304         return FALSE;
305     }
306 
307     /* Copy the SSID to our internal buffer and terminate it */
308     RtlCopyMemory(SsidBuffer, SsidInfo->Ssid, SsidInfo->SsidLength);
309     SsidBuffer[SsidInfo->SsidLength] = 0;
310 
311     HeapFree(GetProcessHeap(), 0, QueryOid);
312     QueryOidSize = FIELD_OFFSET(NDISUIO_QUERY_OID, Data) + sizeof(NDIS_802_11_MAC_ADDRESS);
313     QueryOid = HeapAlloc(GetProcessHeap(), 0, QueryOidSize);
314     if (!QueryOid)
315         return FALSE;
316 
317     QueryOid->Oid = OID_802_11_BSSID;
318 
319     bSuccess = DeviceIoControl(hAdapter,
320                                IOCTL_NDISUIO_QUERY_OID_VALUE,
321                                QueryOid,
322                                QueryOidSize,
323                                QueryOid,
324                                QueryOidSize,
325                                &dwBytesReturned,
326                                NULL);
327     if (SsidInfo->SsidLength == 0 || !bSuccess)
328     {
329         ConResPuts(StdOut, IDS_WLAN_DISCONNECT);
330         HeapFree(GetProcessHeap(), 0, QueryOid);
331         return TRUE;
332     }
333     else
334     {
335         ConResPuts(StdOut, IDS_MSG_CURRENT_WIRELESS);
336     }
337 
338     printf("SSID: %s\n", SsidBuffer);
339 
340     printf("BSSID: ");
341     for (i = 0; i < sizeof(NDIS_802_11_MAC_ADDRESS); i++)
342     {
343         UINT BssidData = QueryOid->Data[i];
344 
345         printf("%.2x", BssidData);
346 
347         if (i != sizeof(NDIS_802_11_MAC_ADDRESS) - 1)
348             printf(":");
349     }
350     printf("\n");
351 
352     HeapFree(GetProcessHeap(), 0, QueryOid);
353     QueryOidSize = sizeof(NDISUIO_QUERY_OID);
354     QueryOid = HeapAlloc(GetProcessHeap(), 0, QueryOidSize);
355     if (!QueryOid)
356         return FALSE;
357 
358     QueryOid->Oid = OID_802_11_INFRASTRUCTURE_MODE;
359 
360     bSuccess = DeviceIoControl(hAdapter,
361                                IOCTL_NDISUIO_QUERY_OID_VALUE,
362                                QueryOid,
363                                QueryOidSize,
364                                QueryOid,
365                                QueryOidSize,
366                                &dwBytesReturned,
367                                NULL);
368     if (!bSuccess)
369     {
370         HeapFree(GetProcessHeap(), 0, QueryOid);
371         return FALSE;
372     }
373 
374     K32LoadStringW(GetModuleHandle(NULL),
375                    *(PUINT)QueryOid->Data == Ndis802_11IBSS ? IDS_ADHOC : IDS_INFRASTRUCTURE,
376                    szMsgBuf,
377                    ARRAYSIZE(szMsgBuf));
378     ConResPrintf(StdOut, IDS_MSG_NETWORK_MODE, szMsgBuf);
379 
380     QueryOid->Oid = OID_802_11_WEP_STATUS;
381 
382     bSuccess = DeviceIoControl(hAdapter,
383                                IOCTL_NDISUIO_QUERY_OID_VALUE,
384                                QueryOid,
385                                QueryOidSize,
386                                QueryOid,
387                                QueryOidSize,
388                                &dwBytesReturned,
389                                NULL);
390     if (!bSuccess)
391     {
392         HeapFree(GetProcessHeap(), 0, QueryOid);
393         return FALSE;
394     }
395 
396     K32LoadStringW(GetModuleHandle(NULL),
397                    *(PUINT)QueryOid->Data == Ndis802_11WEPEnabled ? IDS_YES : IDS_NO,
398                    szMsgBuf,
399                    ARRAYSIZE(szMsgBuf));
400     ConResPrintf(StdOut, IDS_MSG_WEP_ENABLED, szMsgBuf);
401 
402     printf("\n");
403     QueryOid->Oid = OID_802_11_RSSI;
404 
405     bSuccess = DeviceIoControl(hAdapter,
406                                IOCTL_NDISUIO_QUERY_OID_VALUE,
407                                QueryOid,
408                                QueryOidSize,
409                                QueryOid,
410                                QueryOidSize,
411                                &dwBytesReturned,
412                                NULL);
413     if (bSuccess)
414     {
415         /* This OID is optional */
416         printf("RSSI: %i dBm\n", *(PINT)QueryOid->Data);
417     }
418 
419     QueryOid->Oid = OID_802_11_TX_POWER_LEVEL;
420 
421     bSuccess = DeviceIoControl(hAdapter,
422                                IOCTL_NDISUIO_QUERY_OID_VALUE,
423                                QueryOid,
424                                QueryOidSize,
425                                QueryOid,
426                                QueryOidSize,
427                                &dwBytesReturned,
428                                NULL);
429     if (bSuccess)
430     {
431         /* This OID is optional */
432         ConResPrintf(StdOut, IDS_MSG_TRANSMISSION_POWER, *(PUINT)QueryOid->Data);
433     }
434 
435     printf("\n");
436 
437     QueryOid->Oid = OID_802_11_NUMBER_OF_ANTENNAS;
438 
439     bSuccess = DeviceIoControl(hAdapter,
440                                IOCTL_NDISUIO_QUERY_OID_VALUE,
441                                QueryOid,
442                                QueryOidSize,
443                                QueryOid,
444                                QueryOidSize,
445                                &dwBytesReturned,
446                                NULL);
447     if (bSuccess)
448     {
449         /* This OID is optional */
450         ConResPrintf(StdOut, IDS_MSG_ANTENNA_COUNT, *(PUINT)QueryOid->Data);
451     }
452 
453     QueryOid->Oid = OID_802_11_TX_ANTENNA_SELECTED;
454 
455     bSuccess = DeviceIoControl(hAdapter,
456                                IOCTL_NDISUIO_QUERY_OID_VALUE,
457                                QueryOid,
458                                QueryOidSize,
459                                QueryOid,
460                                QueryOidSize,
461                                &dwBytesReturned,
462                                NULL);
463     if (bSuccess)
464     {
465         UINT TransmitAntenna = *(PUINT)QueryOid->Data;
466 
467         if (TransmitAntenna != 0xFFFFFFFF)
468             ConResPrintf(StdOut, IDS_MSG_TRANSMIT_ANTENNA, TransmitAntenna);
469         else
470             ConResPuts(StdOut, IDS_MSG_TRANSMIT_ANTENNA_ANY);
471     }
472 
473     QueryOid->Oid = OID_802_11_RX_ANTENNA_SELECTED;
474 
475     bSuccess = DeviceIoControl(hAdapter,
476                                IOCTL_NDISUIO_QUERY_OID_VALUE,
477                                QueryOid,
478                                QueryOidSize,
479                                QueryOid,
480                                QueryOidSize,
481                                &dwBytesReturned,
482                                NULL);
483     if (bSuccess)
484     {
485         UINT ReceiveAntenna = *(PUINT)QueryOid->Data;
486 
487         if (ReceiveAntenna != 0xFFFFFFFF)
488             ConResPrintf(StdOut, IDS_MSG_RECEIVE_ANTENNA, ReceiveAntenna);
489         else
490             ConResPuts(StdOut, IDS_MSG_RECEIVE_ANTENNA_ANY);
491     }
492 
493     printf("\n");
494 
495     QueryOid->Oid = OID_802_11_FRAGMENTATION_THRESHOLD;
496 
497     bSuccess = DeviceIoControl(hAdapter,
498                                IOCTL_NDISUIO_QUERY_OID_VALUE,
499                                QueryOid,
500                                QueryOidSize,
501                                QueryOid,
502                                QueryOidSize,
503                                &dwBytesReturned,
504                                NULL);
505     if (bSuccess)
506     {
507         /* This OID is optional */
508         ConResPrintf(StdOut, IDS_MSG_FRAGMENT_THRESHOLD, *(PUINT)QueryOid->Data);
509     }
510 
511     QueryOid->Oid = OID_802_11_RTS_THRESHOLD;
512 
513     bSuccess = DeviceIoControl(hAdapter,
514                                IOCTL_NDISUIO_QUERY_OID_VALUE,
515                                QueryOid,
516                                QueryOidSize,
517                                QueryOid,
518                                QueryOidSize,
519                                &dwBytesReturned,
520                                NULL);
521     if (bSuccess)
522     {
523         /* This OID is optional */
524         ConResPrintf(StdOut, IDS_MSG_RTS_THRESHOLD, *(PUINT)QueryOid->Data);
525     }
526 
527     HeapFree(GetProcessHeap(), 0, QueryOid);
528 
529     printf("\n");
530     return TRUE;
531 }
532 
533 BOOL
534 WlanConnect(HANDLE hAdapter)
535 {
536     CHAR SsidBuffer[NDIS_802_11_LENGTH_SSID + 1];
537     BOOL bSuccess;
538     DWORD dwBytesReturned, SetOidSize;
539     PNDISUIO_SET_OID SetOid;
540     PNDIS_802_11_SSID Ssid;
541     DWORD i;
542 
543     SetOidSize = sizeof(NDISUIO_SET_OID);
544     SetOid = HeapAlloc(GetProcessHeap(), 0, SetOidSize);
545     if (!SetOid)
546         return FALSE;
547 
548     /* Set the network mode */
549     SetOid->Oid = OID_802_11_INFRASTRUCTURE_MODE;
550     *(PULONG)SetOid->Data = bAdhoc ? Ndis802_11IBSS : Ndis802_11Infrastructure;
551 
552     bSuccess = DeviceIoControl(hAdapter,
553                                IOCTL_NDISUIO_SET_OID_VALUE,
554                                SetOid,
555                                SetOidSize,
556                                NULL,
557                                0,
558                                &dwBytesReturned,
559                                NULL);
560     if (!bSuccess)
561     {
562         HeapFree(GetProcessHeap(), 0, SetOid);
563         return FALSE;
564     }
565 
566     /* Set the authentication mode */
567     SetOid->Oid = OID_802_11_AUTHENTICATION_MODE;
568     *(PULONG)SetOid->Data = sWepKey ? Ndis802_11AuthModeShared : Ndis802_11AuthModeOpen;
569 
570     bSuccess = DeviceIoControl(hAdapter,
571                                IOCTL_NDISUIO_SET_OID_VALUE,
572                                SetOid,
573                                SetOidSize,
574                                NULL,
575                                0,
576                                &dwBytesReturned,
577                                NULL);
578     if (!bSuccess)
579     {
580         HeapFree(GetProcessHeap(), 0, SetOid);
581         return FALSE;
582     }
583 
584     if (sWepKey)
585     {
586         PNDIS_802_11_WEP WepData;
587 
588         HeapFree(GetProcessHeap(), 0, SetOid);
589 
590         SetOidSize = FIELD_OFFSET(NDISUIO_SET_OID, Data) +
591                      FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial) +
592                      (wcslen(sWepKey) >> 1);
593         SetOid = HeapAlloc(GetProcessHeap(), 0, SetOidSize);
594         if (!SetOid)
595             return FALSE;
596 
597         /* Add the WEP key */
598         SetOid->Oid = OID_802_11_ADD_WEP;
599         WepData = (PNDIS_802_11_WEP)SetOid->Data;
600 
601         WepData->KeyIndex = 0x80000000;
602         WepData->KeyLength = wcslen(sWepKey) >> 1;
603         WepData->Length = FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial) + WepData->KeyLength;
604 
605         /* Assemble the hex key */
606         i = 0;
607         while (sWepKey[i << 1] != '\0')
608         {
609             WepData->KeyMaterial[i] = CharToHex(sWepKey[i << 1]) << 4;
610             WepData->KeyMaterial[i] |= CharToHex(sWepKey[(i << 1) + 1]);
611             i++;
612         }
613 
614         bSuccess = DeviceIoControl(hAdapter,
615                                    IOCTL_NDISUIO_SET_OID_VALUE,
616                                    SetOid,
617                                    SetOidSize,
618                                    NULL,
619                                    0,
620                                    &dwBytesReturned,
621                                    NULL);
622         if (!bSuccess)
623         {
624             HeapFree(GetProcessHeap(), 0, SetOid);
625             return FALSE;
626         }
627     }
628 
629     /* Set the encryption status */
630     SetOid->Oid = OID_802_11_WEP_STATUS;
631     *(PULONG)SetOid->Data = sWepKey ? Ndis802_11WEPEnabled : Ndis802_11WEPDisabled;
632 
633     bSuccess = DeviceIoControl(hAdapter,
634                                IOCTL_NDISUIO_SET_OID_VALUE,
635                                SetOid,
636                                SetOidSize,
637                                NULL,
638                                0,
639                                &dwBytesReturned,
640                                NULL);
641     if (!bSuccess)
642     {
643         HeapFree(GetProcessHeap(), 0, SetOid);
644         return FALSE;
645     }
646 
647     HeapFree(GetProcessHeap(), 0, SetOid);
648     SetOidSize = FIELD_OFFSET(NDISUIO_SET_OID, Data) + sizeof(NDIS_802_11_MAC_ADDRESS);
649     SetOid = HeapAlloc(GetProcessHeap(), 0, SetOidSize);
650     if (!SetOid)
651         return FALSE;
652 
653     /* Set the BSSID */
654     SetOid->Oid = OID_802_11_BSSID;
655     RtlFillMemory(SetOid->Data, sizeof(NDIS_802_11_MAC_ADDRESS), 0xFF);
656 
657     bSuccess = DeviceIoControl(hAdapter,
658                                IOCTL_NDISUIO_SET_OID_VALUE,
659                                SetOid,
660                                SetOidSize,
661                                NULL,
662                                0,
663                                &dwBytesReturned,
664                                NULL);
665     if (!bSuccess)
666     {
667         HeapFree(GetProcessHeap(), 0, SetOid);
668         return FALSE;
669     }
670 
671     HeapFree(GetProcessHeap(), 0, SetOid);
672     SetOidSize = FIELD_OFFSET(NDISUIO_SET_OID, Data) + sizeof(NDIS_802_11_SSID);
673     SetOid = HeapAlloc(GetProcessHeap(), 0, SetOidSize);
674     if (!SetOid)
675         return FALSE;
676 
677     /* Finally, set the SSID */
678     SetOid->Oid = OID_802_11_SSID;
679     Ssid = (PNDIS_802_11_SSID)SetOid->Data;
680 
681     snprintf(SsidBuffer, sizeof(SsidBuffer), "%S", sSsid);
682     RtlCopyMemory(Ssid->Ssid, SsidBuffer, strlen(SsidBuffer));
683     Ssid->SsidLength = strlen(SsidBuffer);
684 
685     bSuccess = DeviceIoControl(hAdapter,
686                                IOCTL_NDISUIO_SET_OID_VALUE,
687                                SetOid,
688                                SetOidSize,
689                                NULL,
690                                0,
691                                &dwBytesReturned,
692                                NULL);
693 
694     HeapFree(GetProcessHeap(), 0, SetOid);
695 
696     if (!bSuccess)
697         return FALSE;
698 
699     ConResPuts(StdOut, IDS_SUCCESS);
700     return TRUE;
701 }
702 
703 BOOL
704 WlanScan(HANDLE hAdapter)
705 {
706     BOOL bSuccess;
707     DWORD dwBytesReturned;
708     NDISUIO_SET_OID SetOid;
709     PNDISUIO_QUERY_OID QueryOid;
710     DWORD QueryOidSize;
711     PNDIS_802_11_BSSID_LIST BssidList;
712     DWORD i, j;
713     DWORD dwNetworkCount;
714     WCHAR szMsgBuf[128];
715 
716     SetOid.Oid = OID_802_11_BSSID_LIST_SCAN;
717 
718     /* Send the scan OID */
719     bSuccess = DeviceIoControl(hAdapter,
720                                IOCTL_NDISUIO_SET_OID_VALUE,
721                                &SetOid,
722                                FIELD_OFFSET(NDISUIO_SET_OID, Data),
723                                NULL,
724                                0,
725                                &dwBytesReturned,
726                                NULL);
727     if (!bSuccess)
728         return FALSE;
729 
730     /* Wait 2 seconds for the scan to return some results */
731     Sleep(2000);
732 
733     /* Allocate space for 10 networks to be returned initially */
734     QueryOid = NULL;
735     dwNetworkCount = 10;
736     for (;;)
737     {
738         if (QueryOid)
739             HeapFree(GetProcessHeap(), 0, QueryOid);
740 
741         QueryOidSize = sizeof(NDISUIO_QUERY_OID) + (sizeof(NDIS_WLAN_BSSID) * dwNetworkCount);
742         QueryOid = HeapAlloc(GetProcessHeap(), 0, QueryOidSize);
743         if (!QueryOid)
744             return FALSE;
745 
746         QueryOid->Oid = OID_802_11_BSSID_LIST;
747         BssidList = (PNDIS_802_11_BSSID_LIST)QueryOid->Data;
748 
749         bSuccess = DeviceIoControl(hAdapter,
750                                    IOCTL_NDISUIO_QUERY_OID_VALUE,
751                                    QueryOid,
752                                    QueryOidSize,
753                                    QueryOid,
754                                    QueryOidSize,
755                                    &dwBytesReturned,
756                                    NULL);
757         if (!bSuccess && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
758         {
759             /* Try allocating space for 10 more networks */
760             dwNetworkCount += 10;
761         }
762         else
763         {
764             break;
765         }
766     }
767 
768     if (!bSuccess)
769     {
770         HeapFree(GetProcessHeap(), 0, QueryOid);
771         return FALSE;
772     }
773 
774     if (BssidList->NumberOfItems == 0)
775     {
776         ConResPuts(StdOut, IDS_NO_NETWORK);
777     }
778     else
779     {
780         PNDIS_WLAN_BSSID BssidInfo = BssidList->Bssid;
781         for (i = 0; i < BssidList->NumberOfItems; i++)
782         {
783             PNDIS_802_11_SSID Ssid = &BssidInfo->Ssid;
784             NDIS_802_11_RSSI Rssi = BssidInfo->Rssi;
785             NDIS_802_11_NETWORK_INFRASTRUCTURE NetworkType = BssidInfo->InfrastructureMode;
786             CHAR SsidBuffer[NDIS_802_11_LENGTH_SSID + 1];
787             UINT Rate;
788 
789             /* SSID member is a non-null terminated ASCII string */
790             RtlCopyMemory(SsidBuffer, Ssid->Ssid, Ssid->SsidLength);
791             SsidBuffer[Ssid->SsidLength] = 0;
792 
793             printf("\nSSID: %s\n", SsidBuffer);
794 
795             printf("BSSID: ");
796             for (j = 0; j < sizeof(NDIS_802_11_MAC_ADDRESS); j++)
797             {
798                 UINT BssidData = BssidInfo->MacAddress[j];
799 
800                 printf("%.2x", BssidData);
801 
802                 if (j != sizeof(NDIS_802_11_MAC_ADDRESS) - 1)
803                     printf(":");
804             }
805             printf("\n");
806 
807             K32LoadStringW(GetModuleHandle(NULL),
808                            BssidInfo->Privacy == 0 ? IDS_NO : IDS_YES,
809                            szMsgBuf,
810                            ARRAYSIZE(szMsgBuf));
811             ConResPrintf(StdOut, IDS_MSG_ENCRYPTED, szMsgBuf);
812             K32LoadStringW(GetModuleHandle(NULL),
813                            NetworkType == Ndis802_11IBSS ? IDS_ADHOC : IDS_INFRASTRUCTURE,
814                            szMsgBuf,
815                            ARRAYSIZE(szMsgBuf));
816             ConResPrintf(StdOut, IDS_MSG_NETWORK_TYPE, szMsgBuf);
817             ConResPrintf(StdOut, IDS_MSG_RSSI, (int)Rssi);
818             ConResPuts(StdOut, IDS_MSG_SUPPORT_RATE);
819 
820             for (j = 0; j < NDIS_802_11_LENGTH_RATES; j++)
821             {
822                 Rate = BssidInfo->SupportedRates[j];
823                 if (Rate != 0)
824                 {
825                     /* Bit 7 is the basic rates bit */
826                     Rate = Rate & 0x7F;
827 
828                     /* SupportedRates are in units of .5 */
829                     if (Rate & 0x01)
830                     {
831                         /* Bit 0 is set so we need to add 0.5 */
832                         printf("%u.5 ", (Rate >> 1));
833                     }
834                     else
835                     {
836                         /* Bit 0 is clear so just print the conversion */
837                         printf("%u ", (Rate >> 1));
838                     }
839                 }
840             }
841             printf("\n");
842 
843             /* Move to the next entry */
844             BssidInfo = (PNDIS_WLAN_BSSID)((PUCHAR)BssidInfo + BssidInfo->Length);
845         }
846     }
847 
848     HeapFree(GetProcessHeap(), 0, QueryOid);
849 
850     return bSuccess;
851 }
852 
853 BOOL ParseCmdline(int argc, WCHAR *argv[])
854 {
855     INT i;
856 
857     for (i = 1; i < argc; i++)
858     {
859         if (argv[i][0] == L'-')
860         {
861             switch (argv[i][1])
862             {
863                 case L's':
864                     bScan = TRUE;
865                     break;
866                 case L'd':
867                     bDisconnect = TRUE;
868                     break;
869                 case L'c':
870                     if (i == argc - 1)
871                     {
872                         ConResPuts(StdOut, IDS_USAGE);
873                         return FALSE;
874                     }
875                     bConnect = TRUE;
876                     sSsid = argv[++i];
877                     break;
878                 case L'w':
879                     if (i == argc - 1)
880                     {
881                         ConResPuts(StdOut, IDS_USAGE);
882                         return FALSE;
883                     }
884                     sWepKey = argv[++i];
885                     break;
886                 case L'a':
887                     bAdhoc = TRUE;
888                     break;
889                 default :
890                     ConResPuts(StdOut, IDS_USAGE);
891                     return FALSE;
892             }
893 
894         }
895         else
896         {
897             ConResPuts(StdOut, IDS_USAGE);
898             return FALSE;
899         }
900     }
901 
902     return TRUE;
903 }
904 
905 int wmain(int argc, WCHAR *argv[])
906 {
907     HANDLE hAdapter;
908     IP_ADAPTER_INDEX_MAP IpInfo;
909 
910     /* Initialize the Console Standard Streams */
911     ConInitStdStreams();
912 
913     if (!ParseCmdline(argc, argv))
914         return -1;
915 
916     if (!OpenWlanAdapter(&hAdapter, &IpInfo))
917     {
918         ConResPuts(StdOut, IDS_NO_WLAN_ADAPTER);
919         return -1;
920     }
921 
922     if (bScan)
923     {
924         if (!WlanScan(hAdapter))
925         {
926             DoFormatMessage(GetLastError());
927             CloseHandle(hAdapter);
928             return -1;
929         }
930     }
931     else if (bDisconnect)
932     {
933         if (!WlanDisconnect(hAdapter, &IpInfo))
934         {
935             DoFormatMessage(GetLastError());
936             CloseHandle(hAdapter);
937             return -1;
938         }
939     }
940     else if (bConnect)
941     {
942         if (!WlanConnect(hAdapter))
943         {
944             DoFormatMessage(GetLastError());
945             CloseHandle(hAdapter);
946             return -1;
947         }
948     }
949     else
950     {
951         if (!WlanPrintCurrentStatus(hAdapter))
952         {
953             DoFormatMessage(GetLastError());
954             CloseHandle(hAdapter);
955             return -1;
956         }
957     }
958 
959     CloseHandle(hAdapter);
960     return 0;
961 }
962