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