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