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