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