df056523b1ebff9c82ececb498962ab3b515e70d
[reactos.git] / base / applications / network / wlanconf / wlanconf.c
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 <windows.h>
10 #include <tchar.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <ntddndis.h>
14 #include <nuiouser.h>
15
16 BOOL bScan = FALSE;
17
18 BOOL bConnect = FALSE;
19 char* sSsid = NULL;
20 char* sWepKey = NULL;
21 BOOL bAdhoc = FALSE;
22
23 BOOL bDisconnect = FALSE;
24
25 DWORD DoFormatMessage(DWORD ErrorCode)
26 {
27 LPVOID lpMsgBuf;
28 DWORD RetVal;
29
30 if ((RetVal = FormatMessage(
31 FORMAT_MESSAGE_ALLOCATE_BUFFER |
32 FORMAT_MESSAGE_FROM_SYSTEM |
33 FORMAT_MESSAGE_IGNORE_INSERTS,
34 NULL,
35 ErrorCode,
36 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
37 (LPTSTR) &lpMsgBuf,
38 0,
39 NULL )))
40 {
41 _tprintf(_T("%s"), (LPTSTR)lpMsgBuf);
42
43 LocalFree(lpMsgBuf);
44
45 /* return number of TCHAR's stored in output buffer
46 * excluding '\0' - as FormatMessage does*/
47 return RetVal;
48 }
49 else
50 return 0;
51 }
52
53 HANDLE
54 OpenDriverHandle(VOID)
55 {
56 HANDLE hDriver;
57 DWORD dwBytesReturned;
58 BOOL bSuccess;
59
60 /* Open a handle to the NDISUIO driver */
61 hDriver = CreateFileW(NDISUIO_DEVICE_NAME,
62 GENERIC_READ | GENERIC_WRITE,
63 0,
64 NULL,
65 OPEN_EXISTING,
66 FILE_ATTRIBUTE_NORMAL,
67 NULL);
68 if (hDriver == INVALID_HANDLE_VALUE)
69 return INVALID_HANDLE_VALUE;
70
71 /* Wait for binds */
72 bSuccess = DeviceIoControl(hDriver,
73 IOCTL_NDISUIO_BIND_WAIT,
74 NULL,
75 0,
76 NULL,
77 0,
78 &dwBytesReturned,
79 NULL);
80 if (!bSuccess)
81 {
82 CloseHandle(hDriver);
83 return INVALID_HANDLE_VALUE;
84 }
85
86 return hDriver;
87 }
88
89 BOOL
90 IsWlanAdapter(HANDLE hAdapter)
91 {
92 BOOL bSuccess;
93 DWORD dwBytesReturned;
94 PNDISUIO_QUERY_OID QueryOid;
95 DWORD QueryOidSize;
96
97 QueryOidSize = sizeof(NDISUIO_QUERY_OID) + sizeof(NDIS_802_11_SSID);
98 QueryOid = HeapAlloc(GetProcessHeap(), 0, QueryOidSize);
99 if (!QueryOid)
100 return FALSE;
101
102 /* We're just going to do a OID_802_11_SSID query. WLAN drivers should
103 * always succeed this query (returning SsidLength = 0 if not associated) */
104 QueryOid->Oid = OID_802_11_SSID;
105
106 bSuccess = DeviceIoControl(hAdapter,
107 IOCTL_NDISUIO_QUERY_OID_VALUE,
108 QueryOid,
109 QueryOidSize,
110 QueryOid,
111 QueryOidSize,
112 &dwBytesReturned,
113 NULL);
114
115 HeapFree(GetProcessHeap(), 0, QueryOid);
116
117 return bSuccess;
118 }
119
120 HANDLE
121 OpenAdapterHandle(DWORD Index)
122 {
123 HANDLE hDriver;
124 BOOL bSuccess;
125 DWORD dwBytesReturned;
126 DWORD QueryBindingSize = sizeof(NDISUIO_QUERY_BINDING) + (1024 * sizeof(WCHAR));
127 PNDISUIO_QUERY_BINDING QueryBinding;
128
129 /* Open the driver handle */
130 hDriver = OpenDriverHandle();
131 if (hDriver == INVALID_HANDLE_VALUE)
132 return INVALID_HANDLE_VALUE;
133
134 /* Allocate the binding struct */
135 QueryBinding = HeapAlloc(GetProcessHeap(), 0, QueryBindingSize);
136 if (!QueryBinding)
137 {
138 CloseHandle(hDriver);
139 return INVALID_HANDLE_VALUE;
140 }
141
142 /* Query the adapter binding information */
143 QueryBinding->BindingIndex = Index;
144 bSuccess = DeviceIoControl(hDriver,
145 IOCTL_NDISUIO_QUERY_BINDING,
146 QueryBinding,
147 QueryBindingSize,
148 QueryBinding,
149 QueryBindingSize,
150 &dwBytesReturned,
151 NULL);
152
153 if (!bSuccess)
154 {
155 HeapFree(GetProcessHeap(), 0, QueryBinding);
156 CloseHandle(hDriver);
157 return INVALID_HANDLE_VALUE;
158 }
159
160 /* Bind to the adapter */
161 bSuccess = DeviceIoControl(hDriver,
162 IOCTL_NDISUIO_OPEN_DEVICE,
163 (PUCHAR)QueryBinding + QueryBinding->DeviceNameOffset,
164 QueryBinding->DeviceNameLength,
165 NULL,
166 0,
167 &dwBytesReturned,
168 NULL);
169 HeapFree(GetProcessHeap(), 0, QueryBinding);
170
171 if (!bSuccess)
172 {
173 CloseHandle(hDriver);
174 return INVALID_HANDLE_VALUE;
175 }
176
177 return hDriver;
178 }
179
180 /* Only works with the first adapter for now */
181 HANDLE
182 OpenWlanAdapter(VOID)
183 {
184 DWORD dwCurrentIndex;
185 HANDLE hCurrentAdapter;
186
187 for (dwCurrentIndex = 0; ; dwCurrentIndex++)
188 {
189 hCurrentAdapter = OpenAdapterHandle(dwCurrentIndex);
190 if (hCurrentAdapter == INVALID_HANDLE_VALUE)
191 break;
192
193 if (IsWlanAdapter(hCurrentAdapter))
194 return hCurrentAdapter;
195 else
196 CloseHandle(hCurrentAdapter);
197 }
198
199 return INVALID_HANDLE_VALUE;
200 }
201
202 BOOL
203 WlanDisconnect(HANDLE hAdapter)
204 {
205 BOOL bSuccess;
206 DWORD dwBytesReturned;
207 NDISUIO_SET_OID SetOid;
208
209 SetOid.Oid = OID_802_11_DISASSOCIATE;
210
211 bSuccess = DeviceIoControl(hAdapter,
212 IOCTL_NDISUIO_SET_OID_VALUE,
213 &SetOid,
214 sizeof(SetOid),
215 NULL,
216 0,
217 &dwBytesReturned,
218 NULL);
219
220 return bSuccess;
221 }
222
223 static
224 UCHAR
225 CharToHex(CHAR Char)
226 {
227 Char = toupper(Char);
228
229 switch (Char)
230 {
231 case '0':
232 return 0x0;
233 case '1':
234 return 0x1;
235 case '2':
236 return 0x2;
237 case '3':
238 return 0x3;
239 case '4':
240 return 0x4;
241 case '5':
242 return 0x5;
243 case '6':
244 return 0x6;
245 case '7':
246 return 0x7;
247 case '8':
248 return 0x8;
249 case '9':
250 return 0x9;
251 case 'A':
252 return 0xA;
253 case 'B':
254 return 0xB;
255 case 'C':
256 return 0xC;
257 case 'D':
258 return 0xD;
259 case 'E':
260 return 0xE;
261 case 'F':
262 return 0xF;
263 default:
264 return 0;
265 }
266 }
267
268 BOOL
269 WlanConnect(HANDLE hAdapter)
270 {
271 BOOL bSuccess;
272 DWORD dwBytesReturned, SetOidSize;
273 PNDISUIO_SET_OID SetOid;
274 PNDIS_802_11_SSID Ssid;
275 DWORD i;
276
277 SetOidSize = sizeof(NDISUIO_SET_OID);
278 SetOid = HeapAlloc(GetProcessHeap(), 0, SetOidSize);
279 if (!SetOid)
280 return FALSE;
281
282 /* Set the network mode */
283 SetOid->Oid = OID_802_11_INFRASTRUCTURE_MODE;
284 *(PULONG)SetOid->Data = bAdhoc ? Ndis802_11IBSS : Ndis802_11Infrastructure;
285
286 bSuccess = DeviceIoControl(hAdapter,
287 IOCTL_NDISUIO_SET_OID_VALUE,
288 SetOid,
289 SetOidSize,
290 NULL,
291 0,
292 &dwBytesReturned,
293 NULL);
294 if (!bSuccess)
295 {
296 HeapFree(GetProcessHeap(), 0, SetOid);
297 return FALSE;
298 }
299
300 /* Set the authentication mode */
301 SetOid->Oid = OID_802_11_AUTHENTICATION_MODE;
302 *(PULONG)SetOid->Data = sWepKey ? Ndis802_11AuthModeShared : Ndis802_11AuthModeOpen;
303
304 bSuccess = DeviceIoControl(hAdapter,
305 IOCTL_NDISUIO_SET_OID_VALUE,
306 SetOid,
307 SetOidSize,
308 NULL,
309 0,
310 &dwBytesReturned,
311 NULL);
312 if (!bSuccess)
313 {
314 HeapFree(GetProcessHeap(), 0, SetOid);
315 return FALSE;
316 }
317
318 if (sWepKey)
319 {
320 PNDIS_802_11_WEP WepData;
321
322 HeapFree(GetProcessHeap(), 0, SetOid);
323
324 SetOidSize = sizeof(NDISUIO_SET_OID) + FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial) +
325 (strlen(sWepKey) >> 1);
326 SetOid = HeapAlloc(GetProcessHeap(), 0, SetOidSize);
327 if (!SetOid)
328 return FALSE;
329
330 /* Add the WEP key */
331 SetOid->Oid = OID_802_11_ADD_WEP;
332 WepData = (PNDIS_802_11_WEP)SetOid->Data;
333
334 WepData->KeyIndex = 0x80000000;
335 WepData->KeyLength = strlen(sWepKey) >> 1;
336 WepData->Length = FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial) + WepData->KeyLength;
337
338 /* Assemble the hex key */
339 i = 0;
340 while (sWepKey[i << 1] != '\0')
341 {
342 WepData->KeyMaterial[i] = CharToHex(sWepKey[i << 1]) << 4;
343 WepData->KeyMaterial[i] |= CharToHex(sWepKey[(i << 1) + 1]);
344 i++;
345 }
346
347 bSuccess = DeviceIoControl(hAdapter,
348 IOCTL_NDISUIO_SET_OID_VALUE,
349 SetOid,
350 SetOidSize,
351 NULL,
352 0,
353 &dwBytesReturned,
354 NULL);
355 if (!bSuccess)
356 {
357 HeapFree(GetProcessHeap(), 0, SetOid);
358 return FALSE;
359 }
360 }
361
362 /* Set the encryption status */
363 SetOid->Oid = OID_802_11_WEP_STATUS;
364 *(PULONG)SetOid->Data = sWepKey ? Ndis802_11WEPEnabled : Ndis802_11WEPDisabled;
365
366 bSuccess = DeviceIoControl(hAdapter,
367 IOCTL_NDISUIO_SET_OID_VALUE,
368 SetOid,
369 SetOidSize,
370 NULL,
371 0,
372 &dwBytesReturned,
373 NULL);
374 if (!bSuccess)
375 {
376 HeapFree(GetProcessHeap(), 0, SetOid);
377 return FALSE;
378 }
379
380 HeapFree(GetProcessHeap(), 0, SetOid);
381 SetOidSize = sizeof(NDISUIO_SET_OID) + sizeof(NDIS_802_11_MAC_ADDRESS);
382 SetOid = HeapAlloc(GetProcessHeap(), 0, SetOidSize);
383 if (!SetOid)
384 return FALSE;
385
386 /* Set the BSSID */
387 SetOid->Oid = OID_802_11_BSSID;
388 RtlFillMemory(SetOid->Data, sizeof(NDIS_802_11_MAC_ADDRESS), 0xFF);
389
390 bSuccess = DeviceIoControl(hAdapter,
391 IOCTL_NDISUIO_SET_OID_VALUE,
392 SetOid,
393 SetOidSize,
394 NULL,
395 0,
396 &dwBytesReturned,
397 NULL);
398 if (!bSuccess)
399 {
400 HeapFree(GetProcessHeap(), 0, SetOid);
401 return FALSE;
402 }
403
404 HeapFree(GetProcessHeap(), 0, SetOid);
405 SetOidSize = sizeof(NDISUIO_SET_OID) + sizeof(NDIS_802_11_SSID);
406 SetOid = HeapAlloc(GetProcessHeap(), 0, SetOidSize);
407 if (!SetOid)
408 return FALSE;
409
410 /* Finally, set the SSID */
411 SetOid->Oid = OID_802_11_SSID;
412 Ssid = (PNDIS_802_11_SSID)SetOid->Data;
413
414 RtlCopyMemory(Ssid->Ssid, sSsid, strlen(sSsid));
415 Ssid->SsidLength = strlen(sSsid);
416
417 bSuccess = DeviceIoControl(hAdapter,
418 IOCTL_NDISUIO_SET_OID_VALUE,
419 SetOid,
420 SetOidSize,
421 NULL,
422 0,
423 &dwBytesReturned,
424 NULL);
425
426 HeapFree(GetProcessHeap(), 0, SetOid);
427
428 return bSuccess;
429 }
430
431 BOOL
432 WlanScan(HANDLE hAdapter)
433 {
434 BOOL bSuccess;
435 DWORD dwBytesReturned;
436 NDISUIO_SET_OID SetOid;
437 PNDISUIO_QUERY_OID QueryOid;
438 DWORD QueryOidSize;
439 PNDIS_802_11_BSSID_LIST BssidList;
440 DWORD i, j;
441
442 SetOid.Oid = OID_802_11_BSSID_LIST_SCAN;
443
444 /* Send the scan OID */
445 bSuccess = DeviceIoControl(hAdapter,
446 IOCTL_NDISUIO_SET_OID_VALUE,
447 &SetOid,
448 sizeof(SetOid),
449 NULL,
450 0,
451 &dwBytesReturned,
452 NULL);
453 if (!bSuccess)
454 return FALSE;
455
456 /* Allocate space for 15 networks to be returned */
457 QueryOidSize = sizeof(NDISUIO_QUERY_OID) + (sizeof(NDIS_WLAN_BSSID) * 15);
458 QueryOid = HeapAlloc(GetProcessHeap(), 0, QueryOidSize);
459 if (!QueryOid)
460 return FALSE;
461
462 QueryOid->Oid = OID_802_11_BSSID_LIST;
463 BssidList = (PNDIS_802_11_BSSID_LIST)QueryOid->Data;
464
465 bSuccess = DeviceIoControl(hAdapter,
466 IOCTL_NDISUIO_QUERY_OID_VALUE,
467 QueryOid,
468 QueryOidSize,
469 QueryOid,
470 QueryOidSize,
471 &dwBytesReturned,
472 NULL);
473 if (!bSuccess)
474 {
475 HeapFree(GetProcessHeap(), 0, QueryOid);
476 return FALSE;
477 }
478
479 if (BssidList->NumberOfItems == 0)
480 {
481 _tprintf(_T("No networks found in range\n"));
482 }
483 else
484 {
485 PNDIS_WLAN_BSSID BssidInfo = BssidList->Bssid;
486 for (i = 0; i < BssidList->NumberOfItems; i++)
487 {
488 PNDIS_802_11_SSID Ssid = &BssidInfo->Ssid;
489 NDIS_802_11_RSSI Rssi = BssidInfo->Rssi;
490 NDIS_802_11_NETWORK_INFRASTRUCTURE NetworkType = BssidInfo->InfrastructureMode;
491 CHAR SsidBuffer[NDIS_802_11_LENGTH_SSID + 1];
492 UINT Rate;
493
494 /* SSID member is a non-null terminated ASCII string */
495 RtlCopyMemory(SsidBuffer, Ssid->Ssid, Ssid->SsidLength);
496 SsidBuffer[Ssid->SsidLength] = 0;
497
498 _tprintf(_T("\nSSID: %s\n"
499 "Encrypted: %s\n"
500 "Network Type: %s\n"
501 "RSSI: %i dBm\n"
502 "Supported Rates (Mbps): "),
503 SsidBuffer,
504 BssidInfo->Privacy == 0 ? "No" : "Yes",
505 NetworkType == Ndis802_11IBSS ? "Adhoc" : "Infrastructure",
506 (int)Rssi);
507
508 for (j = 0; j < NDIS_802_11_LENGTH_RATES; j++)
509 {
510 Rate = BssidInfo->SupportedRates[j];
511 if (Rate != 0)
512 {
513 /* Bit 7 is the basic rates bit */
514 Rate = Rate & 0x7F;
515
516 /* SupportedRates are in units of .5 */
517 Rate = Rate >> 1;
518
519 _tprintf(_T("%u "), Rate);
520 }
521 }
522 _tprintf(_T("\n"));
523
524 /* Move to the next entry */
525 BssidInfo = (PNDIS_WLAN_BSSID)((PUCHAR)BssidInfo + BssidInfo->Length);
526 }
527 }
528
529 HeapFree(GetProcessHeap(), 0, QueryOid);
530
531 return bSuccess;
532 }
533
534 VOID Usage()
535 {
536 _tprintf(_T("\nConfigures a WLAN adapter.\n\n"
537 "WLANCONF [-c SSID [-w WEP] [-a]] [-d] [-s]\n\n"
538 " -c SSID Connects to a supplied SSID.\n"
539 " -w WEP Specifies a WEP key to use.\n"
540 " -a Specifies the target network is ad-hoc\n"
541 " -d Disconnects from the current AP.\n"
542 " -s Scans and displays a list of access points in range.\n"));
543 }
544
545
546 BOOL ParseCmdline(int argc, char* argv[])
547 {
548 INT i;
549
550 for (i = 1; i < argc; i++)
551 {
552 if (argv[i][0] == '-')
553 {
554 switch (argv[i][1])
555 {
556 case 's':
557 bScan = TRUE;
558 break;
559 case 'd':
560 bDisconnect = TRUE;
561 break;
562 case 'c':
563 if (i == argc - 1)
564 {
565 Usage();
566 return FALSE;
567 }
568 bConnect = TRUE;
569 sSsid = argv[++i];
570 break;
571 case 'w':
572 if (i == argc - 1)
573 {
574 Usage();
575 return FALSE;
576 }
577 sWepKey = argv[++i];
578 break;
579 case 'a':
580 bAdhoc = TRUE;
581 break;
582 default :
583 Usage();
584 return FALSE;
585 }
586
587 }
588 else
589 {
590 Usage();
591 return FALSE;
592 }
593 }
594
595 if (!bScan && !bDisconnect && !bConnect)
596 {
597 Usage();
598 return FALSE;
599 }
600
601 return TRUE;
602 }
603
604 int main(int argc, char* argv[])
605 {
606 HANDLE hAdapter;
607
608 if (!ParseCmdline(argc, argv))
609 return -1;
610
611 hAdapter = OpenWlanAdapter();
612 if (hAdapter == INVALID_HANDLE_VALUE)
613 {
614 DoFormatMessage(GetLastError());
615 return -1;
616 }
617
618 if (bScan)
619 {
620 if (!WlanScan(hAdapter))
621 {
622 DoFormatMessage(GetLastError());
623 CloseHandle(hAdapter);
624 return -1;
625 }
626 }
627 else if (bDisconnect)
628 {
629 if (!WlanDisconnect(hAdapter))
630 {
631 DoFormatMessage(GetLastError());
632 CloseHandle(hAdapter);
633 return -1;
634 }
635 }
636 else
637 {
638 if (!WlanConnect(hAdapter))
639 {
640 DoFormatMessage(GetLastError());
641 CloseHandle(hAdapter);
642 return -1;
643 }
644 }
645
646 CloseHandle(hAdapter);
647 return 0;
648 }