netcon.c 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550
  1. /*++
  2. Copyright (c) 2016 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. netcon.c
  9. Abstract:
  10. This module implements the network configuration program.
  11. Author:
  12. Chris Stevens 14-Mar-2016
  13. Environment:
  14. User
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/lib/minocaos.h>
  20. #include <minoca/net/netdrv.h>
  21. #include <minoca/net/net80211.h>
  22. #include <minoca/net/netlink.h>
  23. #include <minoca/lib/mlibc.h>
  24. #include <minoca/lib/netlink.h>
  25. #include <assert.h>
  26. #include <errno.h>
  27. #include <getopt.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <unistd.h>
  32. #include <netinet/in.h>
  33. #include <arpa/inet.h>
  34. //
  35. // ---------------------------------------------------------------- Definitions
  36. //
  37. #define NETCON_VERSION_MAJOR 1
  38. #define NETCON_VERSION_MINOR 0
  39. #define NETCON_USAGE \
  40. "usage: netcon [-d device] [-j ssid -p] [-l] [-s] [-v]\n\n" \
  41. "The netcon utility configures network devices.\n\n" \
  42. "Options:\n" \
  43. " -d --device=device -- Specifies the network device to configure.\n" \
  44. " This is optional for wireless commands if there is only 1\n" \
  45. " wireless device on the system.\n" \
  46. " -j --join=ssid -- Attempts to join the given wireless network.\n" \
  47. " -l --leave -- Attempts to leave the current wireless network.\n" \
  48. " -p --password -- Indicates that the user wants to be prompted for a\n" \
  49. " password during a join operation.\n" \
  50. " -s --scan -- Displays the list of wireless networks available to\n" \
  51. " the network device specified by -d.\n" \
  52. " -v --verbose -- Display more detailed information.\n" \
  53. " --help -- Display this help text.\n" \
  54. " --version -- Display the application version and exit.\n\n"
  55. #define NETCON_OPTIONS_STRING "d:j:lspvh"
  56. //
  57. // Define the set of network configuration flags.
  58. //
  59. #define NETCON_FLAG_DEVICE_ID 0x00000001
  60. #define NETCON_FLAG_JOIN 0x00000002
  61. #define NETCON_FLAG_LEAVE 0x00000004
  62. #define NETCON_FLAG_PASSWORD 0x00000008
  63. #define NETCON_FLAG_SCAN 0x00000010
  64. #define NETCON_FLAG_VERBOSE 0x00000020
  65. #define NETCON_FLAG_WIRELESS_MASK \
  66. (NETCON_FLAG_JOIN | NETCON_FLAG_LEAVE | NETCON_FLAG_SCAN)
  67. //
  68. // Define the set of network device description flags.
  69. //
  70. #define NETCON_DEVICE_FLAG_IP4 0x00000001
  71. #define NETCON_DEVICE_FLAG_IP6 0x00000002
  72. #define NETCON_DEVICE_FLAG_80211 0x00000004
  73. //
  74. // ------------------------------------------------------ Data Type Definitions
  75. //
  76. /*++
  77. Structure Description:
  78. This structure defines the context for network configuration requests.
  79. Members:
  80. Flags - Stores a bitmask of network configuration flags. See NETCON_FLAG_*
  81. for definitions.
  82. Device - Stores the ID of the network device that is being configured.
  83. Ssid - Stores a pointer to the SSID of the network to join.
  84. --*/
  85. typedef struct _NETCON_CONTEXT {
  86. ULONG Flags;
  87. DEVICE_ID DeviceId;
  88. PSTR Ssid;
  89. } NETCON_CONTEXT, *PNETCON_CONTEXT;
  90. /*++
  91. Structure Description:
  92. This structure defines a network device.
  93. Members:
  94. Flags - Stores a bitmask of flags. See NETCON_DEVICE_FLAG_* for definitions.
  95. DeviceId - Stores the network device's ID.
  96. NetworkIp4 - Stores the IPv4 network information.
  97. NetworkIp6 - Stores the IPv6 network information.
  98. Net80211 - Stores the 802.11 device information.
  99. --*/
  100. typedef struct _NETCON_DEVICE_DESCRIPTION {
  101. ULONG Flags;
  102. DEVICE_ID DeviceId;
  103. NETWORK_DEVICE_INFORMATION NetworkIp4;
  104. NETWORK_DEVICE_INFORMATION NetworkIp6;
  105. NETWORK_80211_DEVICE_INFORMATION Net80211;
  106. } NETCON_DEVICE_DESCRIPTION, *PNETCON_DEVICE_DESCRIPTION;
  107. /*++
  108. Structure Description:
  109. This structure defines a BSS scan result.
  110. Members:
  111. Bssid - Stores the BSSID.
  112. SignalStrength - Stores the BSS's signal strength in MBM's.
  113. Status - Stores the BSS's status.
  114. Capability - Stores the BSS's capability flags.
  115. BeaconInterval - Stores the BSS's beacon interval.
  116. Elements - Stores a pointer to the BSS's information elements. These
  117. include the SSID, channel, and security information.
  118. ElementsSize - Stores the size of the information elements, in bytes.
  119. --*/
  120. typedef struct _NETCON_BSS {
  121. NETWORK_ADDRESS Bssid;
  122. LONG SignalStrength;
  123. ULONG Status;
  124. USHORT BeaconInterval;
  125. USHORT Capabilities;
  126. PVOID Elements;
  127. ULONG ElementsSize;
  128. } NETCON_BSS, *PNETCON_BSS;
  129. /*++
  130. Structure Description:
  131. This structure defines a set of scan results.
  132. Members:
  133. Valid - Stores a boolean indicating whether or not the results are valid.
  134. BssCount - Stores the number of BSS element pointers in the array.
  135. BssArray - Stores an array of pointers to the BSS elements.
  136. --*/
  137. typedef struct _NETCON_SCAN_RESULTS {
  138. BOOL Valid;
  139. ULONG BssCount;
  140. PNETCON_BSS *BssArray;
  141. } NETCON_SCAN_RESULTS, *PNETCON_SCAN_RESULTS;
  142. //
  143. // ----------------------------------------------- Internal Function Prototypes
  144. //
  145. VOID
  146. NetconListDevices (
  147. VOID
  148. );
  149. INT
  150. NetconEnumerateDevices (
  151. PNETCON_DEVICE_DESCRIPTION *DeviceArray,
  152. PULONG DeviceCount
  153. );
  154. INT
  155. NetconGetDeviceInformation (
  156. DEVICE_ID DeviceId,
  157. PNETCON_DEVICE_DESCRIPTION Device
  158. );
  159. VOID
  160. NetconJoinNetwork (
  161. PNETCON_CONTEXT Context
  162. );
  163. VOID
  164. NetconLeaveNetwork (
  165. PNETCON_CONTEXT Context
  166. );
  167. VOID
  168. NetconScanForNetworks (
  169. PNETCON_CONTEXT Context
  170. );
  171. VOID
  172. NetconParseScanNotification (
  173. PNL_SOCKET Socket,
  174. PNL_RECEIVE_CONTEXT Context,
  175. PVOID Message
  176. );
  177. VOID
  178. NetconParseScanResult (
  179. PNL_SOCKET Socket,
  180. PNL_RECEIVE_CONTEXT Context,
  181. PVOID Message
  182. );
  183. VOID
  184. NetconPrintScanResults (
  185. PNETCON_CONTEXT Context,
  186. PNETCON_SCAN_RESULTS Results
  187. );
  188. PVOID
  189. NetconGet80211InformationElement (
  190. PVOID Elements,
  191. ULONG ElementsSize,
  192. UCHAR ElementId
  193. );
  194. VOID
  195. NetconPrintRsnInformation (
  196. PUCHAR Rsn
  197. );
  198. VOID
  199. NetconPrintDeviceInformation (
  200. PNETCON_DEVICE_DESCRIPTION Device
  201. );
  202. VOID
  203. NetconPrintAddress (
  204. PNETWORK_ADDRESS Address
  205. );
  206. VOID
  207. NetconPrintEncryption (
  208. NETWORK_ENCRYPTION_TYPE EncryptionType
  209. );
  210. VOID
  211. NetconPrintCipherSuite (
  212. ULONG Suite
  213. );
  214. VOID
  215. NetconPrintRssi (
  216. LONG Rssi
  217. );
  218. VOID
  219. NetconPrintRates (
  220. PVOID RatesElement
  221. );
  222. INT
  223. NetconGet80211DeviceId (
  224. PDEVICE_ID DeviceId
  225. );
  226. //
  227. // -------------------------------------------------------------------- Globals
  228. //
  229. struct option NetconLongOptions[] = {
  230. {"device", required_argument, 0, 'd'},
  231. {"join", required_argument, 0, 'j'},
  232. {"leave", no_argument, 0, 'l'},
  233. {"password", no_argument, 0, 'p'},
  234. {"scan", no_argument, 0, 's'},
  235. {"verbose", no_argument, 0, 'v'},
  236. {"help", no_argument, 0, 'h'},
  237. {"version", no_argument, 0, 'V'},
  238. {NULL, 0, 0, 0}
  239. };
  240. UUID NetconDeviceInformationUuid = NETWORK_DEVICE_INFORMATION_UUID;
  241. UUID Netcon80211DeviceInformationUuid = NETWORK_80211_DEVICE_INFORMATION_UUID;
  242. //
  243. // ------------------------------------------------------------------ Functions
  244. //
  245. INT
  246. main (
  247. INT ArgumentCount,
  248. CHAR **Arguments
  249. )
  250. /*++
  251. Routine Description:
  252. This routine implements the network configuration user mode program.
  253. Arguments:
  254. ArgumentCount - Supplies the number of elements in the arguments array.
  255. Arguments - Supplies an array of strings. The array count is bounded by the
  256. previous parameter, and the strings are null-terminated.
  257. Return Value:
  258. 0 on success.
  259. Non-zero on failure.
  260. --*/
  261. {
  262. PSTR AfterScan;
  263. NETCON_CONTEXT Context;
  264. NETCON_DEVICE_DESCRIPTION Device;
  265. INT Option;
  266. INT ReturnValue;
  267. memset(&Context, 0, sizeof(NETCON_CONTEXT));
  268. ReturnValue = 0;
  269. NlInitialize(NULL);
  270. //
  271. // Process the control arguments.
  272. //
  273. while (TRUE) {
  274. Option = getopt_long(ArgumentCount,
  275. Arguments,
  276. NETCON_OPTIONS_STRING,
  277. NetconLongOptions,
  278. NULL);
  279. if (Option == -1) {
  280. break;
  281. }
  282. if ((Option == '?') || (Option == ':')) {
  283. ReturnValue = 1;
  284. goto mainEnd;
  285. }
  286. switch (Option) {
  287. case 'd':
  288. Context.DeviceId = strtoull(optarg, &AfterScan, 0);
  289. if (AfterScan == optarg) {
  290. fprintf(stderr, "Error: Invalid device id '%s'.\n", optarg);
  291. ReturnValue = EINVAL;
  292. goto mainEnd;
  293. }
  294. Context.Flags |= NETCON_FLAG_DEVICE_ID;
  295. break;
  296. case 'j':
  297. Context.Ssid = optarg;
  298. Context.Flags |= NETCON_FLAG_JOIN;
  299. break;
  300. case 'l':
  301. Context.Flags |= NETCON_FLAG_LEAVE;
  302. break;
  303. case 's':
  304. Context.Flags |= NETCON_FLAG_SCAN;
  305. break;
  306. case 'p':
  307. Context.Flags |= NETCON_FLAG_PASSWORD;
  308. break;
  309. case 'v':
  310. Context.Flags |= NETCON_FLAG_VERBOSE;
  311. break;
  312. case 'V':
  313. printf("netcon version %d.%02d\n",
  314. NETCON_VERSION_MAJOR,
  315. NETCON_VERSION_MINOR);
  316. ReturnValue = 1;
  317. goto mainEnd;
  318. case 'h':
  319. printf(NETCON_USAGE);
  320. return 1;
  321. default:
  322. assert(FALSE);
  323. ReturnValue = 1;
  324. goto mainEnd;
  325. }
  326. }
  327. //
  328. // Wireless commands require a device ID to operate. If no ID is specified,
  329. // then attempt to find one. If there is more than one device present on
  330. // the system, an error will be printed along with the available devices.
  331. //
  332. if (((Context.Flags & NETCON_FLAG_DEVICE_ID) == 0) &&
  333. ((Context.Flags & NETCON_FLAG_WIRELESS_MASK) != 0)) {
  334. ReturnValue = NetconGet80211DeviceId(&(Context.DeviceId));
  335. if (ReturnValue != 0) {
  336. goto mainEnd;
  337. }
  338. Context.Flags |= NETCON_FLAG_DEVICE_ID;
  339. }
  340. //
  341. // Process the command.
  342. //
  343. if ((Context.Flags & NETCON_FLAG_JOIN) != 0) {
  344. NetconJoinNetwork(&Context);
  345. } else if ((Context.Flags & NETCON_FLAG_LEAVE) != 0) {
  346. NetconLeaveNetwork(&Context);
  347. } else if ((Context.Flags & NETCON_FLAG_SCAN) != 0) {
  348. NetconScanForNetworks(&Context);
  349. } else if ((Context.Flags & NETCON_FLAG_DEVICE_ID) != 0) {
  350. ReturnValue = NetconGetDeviceInformation(Context.DeviceId, &Device);
  351. if (ReturnValue != 0) {
  352. goto mainEnd;
  353. }
  354. NetconPrintDeviceInformation(&Device);
  355. } else {
  356. NetconListDevices();
  357. }
  358. mainEnd:
  359. if (ReturnValue == EINVAL) {
  360. printf(NETCON_USAGE);
  361. }
  362. return ReturnValue;
  363. }
  364. //
  365. // --------------------------------------------------------- Internal Functions
  366. //
  367. VOID
  368. NetconListDevices (
  369. VOID
  370. )
  371. /*++
  372. Routine Description:
  373. This routine prints the list of available network devices.
  374. Arguments:
  375. None.
  376. Return Value:
  377. None.
  378. --*/
  379. {
  380. PNETCON_DEVICE_DESCRIPTION DeviceArray;
  381. ULONG DeviceCount;
  382. ULONG Index;
  383. INT Result;
  384. Result = NetconEnumerateDevices(&DeviceArray, &DeviceCount);
  385. if (Result != 0) {
  386. return;
  387. }
  388. if (DeviceCount == 0) {
  389. printf("No network devices detected.\n");
  390. return;
  391. }
  392. printf("Minoca Network Configuration:\n\n");
  393. for (Index = 0; Index < DeviceCount; Index += 1) {
  394. NetconPrintDeviceInformation(&(DeviceArray[Index]));
  395. printf("\n");
  396. }
  397. free(DeviceArray);
  398. return;
  399. }
  400. INT
  401. NetconEnumerateDevices (
  402. PNETCON_DEVICE_DESCRIPTION *DeviceArray,
  403. PULONG DeviceCount
  404. )
  405. /*++
  406. Routine Description:
  407. This routine enumerates all the network devices on the system.
  408. Arguments:
  409. DeviceArray - Supplies a pointer where an array of network structures
  410. will be returned on success.
  411. DeviceCount - Supplies a pointer where the number of elements in the
  412. partition array will be returned on success.
  413. Return Value:
  414. 0 on success.
  415. Returns an error code on failure.
  416. --*/
  417. {
  418. UINTN AllocationSize;
  419. UINTN ArrayIndex;
  420. PNETCON_DEVICE_DESCRIPTION Devices;
  421. INT Result;
  422. ULONG ResultCount;
  423. UINTN ResultIndex;
  424. PDEVICE_INFORMATION_RESULT Results;
  425. KSTATUS Status;
  426. ArrayIndex = 0;
  427. Devices = NULL;
  428. ResultCount = 0;
  429. Results = NULL;
  430. //
  431. // Enumerate all the devices that support getting network device
  432. // information.
  433. //
  434. Status = OsLocateDeviceInformation(&NetconDeviceInformationUuid,
  435. NULL,
  436. NULL,
  437. &ResultCount);
  438. if (Status != STATUS_BUFFER_TOO_SMALL) {
  439. goto EnumerateDevicesEnd;
  440. }
  441. if (ResultCount == 0) {
  442. Status = STATUS_SUCCESS;
  443. goto EnumerateDevicesEnd;
  444. }
  445. AllocationSize = sizeof(DEVICE_INFORMATION_RESULT) * ResultCount;
  446. Results = malloc(AllocationSize);
  447. if (Results == NULL) {
  448. Status = STATUS_INSUFFICIENT_RESOURCES;
  449. goto EnumerateDevicesEnd;
  450. }
  451. memset(Results, 0, AllocationSize);
  452. Status = OsLocateDeviceInformation(&NetconDeviceInformationUuid,
  453. NULL,
  454. Results,
  455. &ResultCount);
  456. if (!KSUCCESS(Status)) {
  457. goto EnumerateDevicesEnd;
  458. }
  459. if (ResultCount == 0) {
  460. Status = STATUS_SUCCESS;
  461. goto EnumerateDevicesEnd;
  462. }
  463. //
  464. // Allocate the real array.
  465. //
  466. AllocationSize = sizeof(NETCON_DEVICE_DESCRIPTION) * ResultCount;
  467. Devices = malloc(AllocationSize);
  468. if (Devices == NULL) {
  469. Status = STATUS_INSUFFICIENT_RESOURCES;
  470. goto EnumerateDevicesEnd;
  471. }
  472. memset(Devices, 0, AllocationSize);
  473. //
  474. // Loop through the results setting up the structure elements.
  475. //
  476. for (ResultIndex = 0; ResultIndex < ResultCount; ResultIndex += 1) {
  477. Result = NetconGetDeviceInformation(Results[ResultIndex].DeviceId,
  478. &(Devices[ArrayIndex]));
  479. if (Result != 0) {
  480. continue;
  481. }
  482. ArrayIndex += 1;
  483. }
  484. Status = STATUS_SUCCESS;
  485. EnumerateDevicesEnd:
  486. if (Results != NULL) {
  487. free(Results);
  488. }
  489. if (!KSUCCESS(Status)) {
  490. if (Devices != NULL) {
  491. free(Devices);
  492. Devices = NULL;
  493. }
  494. return ClConvertKstatusToErrorNumber(Status);
  495. }
  496. *DeviceArray = Devices;
  497. *DeviceCount = ArrayIndex;
  498. return 0;
  499. }
  500. INT
  501. NetconGetDeviceInformation (
  502. DEVICE_ID DeviceId,
  503. PNETCON_DEVICE_DESCRIPTION Device
  504. )
  505. /*++
  506. Routine Description:
  507. This routine retrieves the network information for the given network device.
  508. Arguments:
  509. DeviceId - Supplies the device ID of the device whose information is to be
  510. retrieved.
  511. Device - Supplies a pointer to a network device descriptor that receives
  512. the retrieved device information.
  513. Return Value:
  514. 0 on success.
  515. Returns an error code on failure.
  516. --*/
  517. {
  518. UINTN DataSize;
  519. PNETWORK_80211_DEVICE_INFORMATION Net80211;
  520. PNETWORK_DEVICE_INFORMATION Network;
  521. PNETWORK_ADDRESS PhysicalAddress;
  522. KSTATUS Status;
  523. Device->Flags = 0;
  524. Device->DeviceId = DeviceId;
  525. PhysicalAddress = NULL;
  526. //
  527. // Get the IPv4 network information.
  528. //
  529. DataSize = sizeof(NETWORK_DEVICE_INFORMATION);
  530. Network = &(Device->NetworkIp4);
  531. Network->Version = NETWORK_DEVICE_INFORMATION_VERSION;
  532. Network->Domain = NetDomainIp4;
  533. Status = OsGetSetDeviceInformation(Device->DeviceId,
  534. &NetconDeviceInformationUuid,
  535. Network,
  536. &DataSize,
  537. FALSE);
  538. if (KSUCCESS(Status)) {
  539. Device->Flags |= NETCON_DEVICE_FLAG_IP4;
  540. PhysicalAddress = &(Network->PhysicalAddress);
  541. }
  542. //
  543. // Get the IPv6 network information.
  544. //
  545. DataSize = sizeof(NETWORK_DEVICE_INFORMATION);
  546. Network = &(Device->NetworkIp6);
  547. Network->Version = NETWORK_DEVICE_INFORMATION_VERSION;
  548. Network->Domain = NetDomainIp6;
  549. Status = OsGetSetDeviceInformation(Device->DeviceId,
  550. &NetconDeviceInformationUuid,
  551. Network,
  552. &DataSize,
  553. FALSE);
  554. if (KSUCCESS(Status)) {
  555. Device->Flags |= NETCON_DEVICE_FLAG_IP6;
  556. PhysicalAddress = &(Network->PhysicalAddress);
  557. }
  558. //
  559. // If the physical address is an 802.11 address, then attempt to get the
  560. // 802.11 information.
  561. //
  562. if ((PhysicalAddress != NULL) &&
  563. (PhysicalAddress->Domain == NetDomain80211)) {
  564. DataSize = sizeof(NETWORK_80211_DEVICE_INFORMATION);
  565. Net80211 = &(Device->Net80211);
  566. Net80211->Version = NETWORK_80211_DEVICE_INFORMATION_VERSION;
  567. Status = OsGetSetDeviceInformation(Device->DeviceId,
  568. &Netcon80211DeviceInformationUuid,
  569. Net80211,
  570. &DataSize,
  571. FALSE);
  572. if (!KSUCCESS(Status)) {
  573. goto GetDeviceInformationEnd;
  574. }
  575. Device->Flags |= NETCON_DEVICE_FLAG_80211;
  576. }
  577. Status = STATUS_SUCCESS;
  578. GetDeviceInformationEnd:
  579. return ClConvertKstatusToErrorNumber(Status);
  580. }
  581. VOID
  582. NetconJoinNetwork (
  583. PNETCON_CONTEXT Context
  584. )
  585. /*++
  586. Routine Description:
  587. This routine attempts to join the network specified by the SSID in the
  588. given netcon context.
  589. Arguments:
  590. Context - Supplies a pointer to the network connection context.
  591. Return Value:
  592. None.
  593. --*/
  594. {
  595. USHORT FamilyId;
  596. PNL_MESSAGE_BUFFER Message;
  597. ULONG MessageLength;
  598. NL_RECEIVE_PARAMETERS Parameters;
  599. PSTR Password;
  600. UINTN PasswordLength;
  601. ULONG PayloadLength;
  602. PNL_SOCKET Socket;
  603. UINTN SsidLength;
  604. INT Status;
  605. Password = NULL;
  606. Socket = NULL;
  607. //
  608. // Validate the SSID.
  609. //
  610. SsidLength = strlen(Context->Ssid) + 1;
  611. if (SsidLength > (NET80211_MAX_SSID_LENGTH + 1)) {
  612. printf("netcon: SSID \"%s\" is too long. Max SSID length is %d.\n",
  613. Context->Ssid,
  614. NET80211_MAX_SSID_LENGTH);
  615. errno = EINVAL;
  616. Status = -1;
  617. goto JoinNetworkEnd;
  618. }
  619. //
  620. // If a password is required, get it now.
  621. //
  622. if ((Context->Flags & NETCON_FLAG_PASSWORD) != 0) {
  623. Password = getpass("Password: ");
  624. if (Password == NULL) {
  625. Status = -1;
  626. goto JoinNetworkEnd;
  627. }
  628. PasswordLength = strlen(Password) + 1;
  629. }
  630. Status = NlCreateSocket(NETLINK_GENERIC, NL_ANY_PORT_ID, 0, &Socket);
  631. if (Status != 0) {
  632. goto JoinNetworkEnd;
  633. }
  634. Status = NlGenericGetFamilyId(Socket,
  635. NETLINK_GENERIC_80211_NAME,
  636. &FamilyId);
  637. if (Status != 0) {
  638. goto JoinNetworkEnd;
  639. }
  640. //
  641. // Build out a message to join a network. This requires specifying the
  642. // device ID of the wireless networking device that is to join the network,
  643. // the SSID of the network and an optional passphrase.
  644. //
  645. PayloadLength = NETLINK_ATTRIBUTE_SIZE(sizeof(DEVICE_ID)) +
  646. NETLINK_ATTRIBUTE_SIZE(SsidLength);
  647. if (Password != NULL) {
  648. PayloadLength += NETLINK_ATTRIBUTE_SIZE(PasswordLength);
  649. }
  650. MessageLength = NETLINK_GENERIC_HEADER_LENGTH + PayloadLength;
  651. Status = NlAllocateBuffer(MessageLength, &Message);
  652. if (Status != 0) {
  653. goto JoinNetworkEnd;
  654. }
  655. Status = NlGenericAppendHeaders(Socket,
  656. Message,
  657. PayloadLength,
  658. 0,
  659. FamilyId,
  660. 0,
  661. NETLINK_80211_COMMAND_JOIN,
  662. 0);
  663. if (Status != 0) {
  664. goto JoinNetworkEnd;
  665. }
  666. Status = NlAppendAttribute(Message,
  667. NETLINK_80211_ATTRIBUTE_DEVICE_ID,
  668. &(Context->DeviceId),
  669. sizeof(DEVICE_ID));
  670. if (Status != 0) {
  671. goto JoinNetworkEnd;
  672. }
  673. Status = NlAppendAttribute(Message,
  674. NETLINK_80211_ATTRIBUTE_SSID,
  675. Context->Ssid,
  676. SsidLength);
  677. if (Status != 0) {
  678. goto JoinNetworkEnd;
  679. }
  680. if (Password != NULL) {
  681. Status = NlAppendAttribute(Message,
  682. NETLINK_80211_ATTRIBUTE_PASSPHRASE,
  683. Password,
  684. PasswordLength);
  685. if (Status != 0) {
  686. goto JoinNetworkEnd;
  687. }
  688. }
  689. //
  690. // Send off the request to join the given network.
  691. //
  692. Status = NlSendMessage(Socket, Message, NETLINK_KERNEL_PORT_ID, 0, NULL);
  693. if (Status != 0) {
  694. goto JoinNetworkEnd;
  695. }
  696. //
  697. // Wait for an acknowledgement message.
  698. //
  699. memset(&Parameters, 0, sizeof(NL_RECEIVE_PARAMETERS));
  700. Parameters.Flags |= NL_RECEIVE_FLAG_PORT_ID;
  701. Parameters.PortId = NETLINK_KERNEL_PORT_ID;
  702. Status = NlReceiveMessage(Socket, &Parameters);
  703. if (Status != 0) {
  704. goto JoinNetworkEnd;
  705. }
  706. JoinNetworkEnd:
  707. if (Password != NULL) {
  708. memset(Password, 0, strlen(Password));
  709. }
  710. if (Socket != NULL) {
  711. NlDestroySocket(Socket);
  712. }
  713. if (Status != 0) {
  714. perror("netcon: failed to join network");
  715. }
  716. return;
  717. }
  718. VOID
  719. NetconLeaveNetwork (
  720. PNETCON_CONTEXT Context
  721. )
  722. /*++
  723. Routine Description:
  724. This routine attempts to leave the network to which the specified device
  725. is connected. The device is stored in the context structure.
  726. Arguments:
  727. Context - Supplies a pointer to the network connection context.
  728. Return Value:
  729. None.
  730. --*/
  731. {
  732. USHORT FamilyId;
  733. PNL_MESSAGE_BUFFER Message;
  734. ULONG MessageLength;
  735. NL_RECEIVE_PARAMETERS Parameters;
  736. ULONG PayloadLength;
  737. PNL_SOCKET Socket;
  738. INT Status;
  739. Status = NlCreateSocket(NETLINK_GENERIC, NL_ANY_PORT_ID, 0, &Socket);
  740. if (Status != 0) {
  741. goto LeaveNetworkEnd;
  742. }
  743. Status = NlGenericGetFamilyId(Socket,
  744. NETLINK_GENERIC_80211_NAME,
  745. &FamilyId);
  746. if (Status != 0) {
  747. goto LeaveNetworkEnd;
  748. }
  749. //
  750. // Build out a request to leave the current network on the given device.
  751. // This only requires supplying the device ID as an attribute.
  752. //
  753. PayloadLength = NETLINK_ATTRIBUTE_SIZE(sizeof(DEVICE_ID));
  754. MessageLength = NETLINK_GENERIC_HEADER_LENGTH + PayloadLength;
  755. Status = NlAllocateBuffer(MessageLength, &Message);
  756. if (Status != 0) {
  757. goto LeaveNetworkEnd;
  758. }
  759. Status = NlGenericAppendHeaders(Socket,
  760. Message,
  761. PayloadLength,
  762. 0,
  763. FamilyId,
  764. 0,
  765. NETLINK_80211_COMMAND_LEAVE,
  766. 0);
  767. if (Status != 0) {
  768. goto LeaveNetworkEnd;
  769. }
  770. Status = NlAppendAttribute(Message,
  771. NETLINK_80211_ATTRIBUTE_DEVICE_ID,
  772. &(Context->DeviceId),
  773. sizeof(DEVICE_ID));
  774. if (Status != 0) {
  775. goto LeaveNetworkEnd;
  776. }
  777. //
  778. // Send off the request to leave the current network.
  779. //
  780. Status = NlSendMessage(Socket, Message, NETLINK_KERNEL_PORT_ID, 0, NULL);
  781. if (Status != 0) {
  782. goto LeaveNetworkEnd;
  783. }
  784. //
  785. // Wait for an acknowledgement message.
  786. //
  787. memset(&Parameters, 0, sizeof(NL_RECEIVE_PARAMETERS));
  788. Parameters.Flags |= NL_RECEIVE_FLAG_PORT_ID;
  789. Parameters.PortId = NETLINK_KERNEL_PORT_ID;
  790. Status = NlReceiveMessage(Socket, &Parameters);
  791. if (Status != 0) {
  792. goto LeaveNetworkEnd;
  793. }
  794. LeaveNetworkEnd:
  795. if (Socket != NULL) {
  796. NlDestroySocket(Socket);
  797. }
  798. if (Status != 0) {
  799. perror("netcon: failed to leave network");
  800. }
  801. return;
  802. }
  803. VOID
  804. NetconScanForNetworks (
  805. PNETCON_CONTEXT Context
  806. )
  807. /*++
  808. Routine Description:
  809. This routine scans for all the wireless networks that are within range of
  810. the device stored in the given context. It then prints them to standard out.
  811. Arguments:
  812. Context - Supplies a pointer to the network connection context.
  813. Return Value:
  814. None.
  815. --*/
  816. {
  817. BOOL AckReceived;
  818. USHORT FamilyId;
  819. ULONG Flags;
  820. PNL_MESSAGE_BUFFER Message;
  821. ULONG MessageLength;
  822. NL_RECEIVE_PARAMETERS Parameters;
  823. ULONG PayloadLength;
  824. NETCON_SCAN_RESULTS ScanResults;
  825. BOOL ScanResultsReady;
  826. PNL_SOCKET Socket;
  827. INT Status;
  828. Message = NULL;
  829. Status = NlCreateSocket(NETLINK_GENERIC, NL_ANY_PORT_ID, 0, &Socket);
  830. if (Status != 0) {
  831. goto ScanForNetworksEnd;
  832. }
  833. Status = NlGenericGetFamilyId(Socket,
  834. NETLINK_GENERIC_80211_NAME,
  835. &FamilyId);
  836. if (Status != 0) {
  837. goto ScanForNetworksEnd;
  838. }
  839. //
  840. // Join the 802.11 scan multicast group in order to get progress updates
  841. // from the scan.
  842. //
  843. Status = NlGenericJoinMulticastGroup(Socket,
  844. FamilyId,
  845. NETLINK_80211_MULTICAST_SCAN_NAME);
  846. if (Status != 0) {
  847. goto ScanForNetworksEnd;
  848. }
  849. //
  850. // Build and send a request to scan for all networks on the given device.
  851. // This only requires supplying the device ID as an attribute.
  852. //
  853. PayloadLength = NETLINK_ATTRIBUTE_SIZE(sizeof(DEVICE_ID));
  854. MessageLength = NETLINK_GENERIC_HEADER_LENGTH + PayloadLength;
  855. Status = NlAllocateBuffer(MessageLength, &Message);
  856. if (Status != 0) {
  857. goto ScanForNetworksEnd;
  858. }
  859. Status = NlGenericAppendHeaders(Socket,
  860. Message,
  861. PayloadLength,
  862. 0,
  863. FamilyId,
  864. 0,
  865. NETLINK_80211_COMMAND_SCAN_START,
  866. 0);
  867. if (Status != 0) {
  868. goto ScanForNetworksEnd;
  869. }
  870. Status = NlAppendAttribute(Message,
  871. NETLINK_80211_ATTRIBUTE_DEVICE_ID,
  872. &(Context->DeviceId),
  873. sizeof(DEVICE_ID));
  874. if (Status != 0) {
  875. goto ScanForNetworksEnd;
  876. }
  877. Status = NlSendMessage(Socket, Message, NETLINK_KERNEL_PORT_ID, 0, NULL);
  878. if (Status != 0) {
  879. goto ScanForNetworksEnd;
  880. }
  881. NlFreeBuffer(Message);
  882. Message = NULL;
  883. //
  884. // Loop waiting for a few possible messages. The scan start request should
  885. // be acknowledged by the kernel. If the scan is acknowledged, then either
  886. // a scan aborted or scan results message should arrive. That is not to
  887. // say that the acknowledge will always come before a scan aborted or
  888. // results message.
  889. //
  890. memset(&Parameters, 0, sizeof(NL_RECEIVE_PARAMETERS));
  891. Parameters.ReceiveRoutine = NetconParseScanNotification;
  892. Parameters.ReceiveContext.Type = FamilyId;
  893. Parameters.ReceiveContext.PrivateContext = &ScanResultsReady;
  894. Parameters.PortId = NETLINK_KERNEL_PORT_ID;
  895. Flags = NL_RECEIVE_FLAG_PORT_ID;
  896. ScanResultsReady = FALSE;
  897. AckReceived = FALSE;
  898. while ((AckReceived == FALSE) || (ScanResultsReady == FALSE)) {
  899. Parameters.Flags = Flags;
  900. Status = NlReceiveMessage(Socket, &Parameters);
  901. if (Status != 0) {
  902. goto ScanForNetworksEnd;
  903. }
  904. if (Parameters.ReceiveContext.Status != 0) {
  905. Status = Parameters.ReceiveContext.Status;
  906. goto ScanForNetworksEnd;
  907. }
  908. //
  909. // If an ACK was received, make sure to stop waiting for one.
  910. //
  911. if ((Parameters.Flags & NL_RECEIVE_FLAG_ACK_RECEIVED) != 0) {
  912. AckReceived = TRUE;
  913. Flags |= NL_RECEIVE_FLAG_NO_ACK_WAIT;
  914. }
  915. }
  916. //
  917. // The scan has completed. Get the scan results and print them out for
  918. // the user. Start by building a scan results get request and sending that
  919. // off to the kernel.
  920. //
  921. Message = NULL;
  922. PayloadLength = NETLINK_ATTRIBUTE_SIZE(sizeof(DEVICE_ID));
  923. MessageLength = NETLINK_GENERIC_HEADER_LENGTH + PayloadLength;
  924. Status = NlAllocateBuffer(MessageLength, &Message);
  925. if (Status != 0) {
  926. goto ScanForNetworksEnd;
  927. }
  928. Status = NlGenericAppendHeaders(Socket,
  929. Message,
  930. PayloadLength,
  931. 0,
  932. FamilyId,
  933. NETLINK_HEADER_FLAG_DUMP,
  934. NETLINK_80211_COMMAND_SCAN_GET_RESULTS,
  935. 0);
  936. if (Status != 0) {
  937. goto ScanForNetworksEnd;
  938. }
  939. Status = NlAppendAttribute(Message,
  940. NETLINK_80211_ATTRIBUTE_DEVICE_ID,
  941. &(Context->DeviceId),
  942. sizeof(DEVICE_ID));
  943. if (Status != 0) {
  944. goto ScanForNetworksEnd;
  945. }
  946. Status = NlSendMessage(Socket, Message, NETLINK_KERNEL_PORT_ID, 0, NULL);
  947. if (Status != 0) {
  948. goto ScanForNetworksEnd;
  949. }
  950. //
  951. // Now wait for the ACK and the results messages to come in.
  952. //
  953. memset(&Parameters, 0, sizeof(NL_RECEIVE_PARAMETERS));
  954. memset(&ScanResults, 0, sizeof(NETCON_SCAN_RESULTS));
  955. Parameters.ReceiveRoutine = NetconParseScanResult;
  956. Parameters.ReceiveContext.Type = FamilyId;
  957. Parameters.ReceiveContext.PrivateContext = &ScanResults;
  958. Parameters.PortId = NETLINK_KERNEL_PORT_ID;
  959. Flags = NL_RECEIVE_FLAG_PORT_ID;
  960. ScanResultsReady = FALSE;
  961. AckReceived = FALSE;
  962. while ((AckReceived == FALSE) || (ScanResults.Valid == FALSE)) {
  963. Parameters.Flags = Flags;
  964. Status = NlReceiveMessage(Socket, &Parameters);
  965. if (Status != 0) {
  966. goto ScanForNetworksEnd;
  967. }
  968. if (Parameters.ReceiveContext.Status != 0) {
  969. Status = Parameters.ReceiveContext.Status;
  970. goto ScanForNetworksEnd;
  971. }
  972. //
  973. // If an ACK was received, make sure to stop waiting for one.
  974. //
  975. if ((Parameters.Flags & NL_RECEIVE_FLAG_ACK_RECEIVED) != 0) {
  976. AckReceived = TRUE;
  977. Flags |= NL_RECEIVE_FLAG_NO_ACK_WAIT;
  978. }
  979. }
  980. //
  981. // Print out those scan results!
  982. //
  983. NetconPrintScanResults(Context, &ScanResults);
  984. ScanForNetworksEnd:
  985. if (Message != NULL) {
  986. NlFreeBuffer(Message);
  987. }
  988. if (Socket != NULL) {
  989. NlDestroySocket(Socket);
  990. }
  991. if (Status != 0) {
  992. perror("netcon: failed to scan for networks");
  993. }
  994. return;
  995. }
  996. VOID
  997. NetconParseScanNotification (
  998. PNL_SOCKET Socket,
  999. PNL_RECEIVE_CONTEXT Context,
  1000. PVOID Message
  1001. )
  1002. /*++
  1003. Routine Description:
  1004. This routine parses a netlink message looking for a scan notification.
  1005. Arguments:
  1006. Socket - Supplies a pointer to the netlink socket that received the message.
  1007. Context - Supplies a pointer to the receive context given to the receive
  1008. message handler.
  1009. Message - Supplies a pointer to the beginning of the netlink message. The
  1010. length of which can be obtained from the header; it was already
  1011. validated.
  1012. Return Value:
  1013. None.
  1014. --*/
  1015. {
  1016. PNETLINK_GENERIC_HEADER GenericHeader;
  1017. PNETLINK_HEADER Header;
  1018. ULONG MessageLength;
  1019. PBOOL ScanResultsReady;
  1020. Header = (PNETLINK_HEADER)Message;
  1021. //
  1022. // Skip any messages that are not of the 802.11 family type.
  1023. //
  1024. if (Header->Type != Context->Type) {
  1025. return;
  1026. }
  1027. //
  1028. // Parse the generic header to determine the 802.11 command.
  1029. //
  1030. MessageLength = Header->Length;
  1031. MessageLength -= NETLINK_HEADER_LENGTH;
  1032. if (MessageLength < sizeof(NETLINK_GENERIC_HEADER)) {
  1033. return;
  1034. }
  1035. //
  1036. // Fail the scan request if the system aborted the scan.
  1037. //
  1038. GenericHeader = NETLINK_DATA(Header);
  1039. if (GenericHeader->Command == NETLINK_80211_COMMAND_SCAN_ABORTED) {
  1040. errno = ECANCELED;
  1041. Context->Status = -1;
  1042. //
  1043. // If it is a scan result notification, mark that it has been seen.
  1044. //
  1045. } else if (GenericHeader->Command == NETLINK_80211_COMMAND_SCAN_RESULT) {
  1046. ScanResultsReady = (PBOOL)Context->PrivateContext;
  1047. *ScanResultsReady = TRUE;
  1048. Context->Status = 0;
  1049. }
  1050. return;
  1051. }
  1052. VOID
  1053. NetconParseScanResult (
  1054. PNL_SOCKET Socket,
  1055. PNL_RECEIVE_CONTEXT Context,
  1056. PVOID Message
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. This routine parses a netlink message looking for a scan result.
  1061. Arguments:
  1062. Socket - Supplies a pointer to the netlink socket that received the message.
  1063. Context - Supplies a pointer to the receive context given to the receive
  1064. message handler.
  1065. Message - Supplies a pointer to the beginning of the netlink message. The
  1066. length of which can be obtained from the header; it was already
  1067. validated.
  1068. Return Value:
  1069. None.
  1070. --*/
  1071. {
  1072. USHORT AttributeLength;
  1073. PVOID Attributes;
  1074. PUSHORT BeaconInterval;
  1075. PNETCON_BSS Bss;
  1076. PNETCON_BSS *BssArray;
  1077. PVOID BssAttribute;
  1078. USHORT BssAttributeLength;
  1079. ULONG BssCount;
  1080. PVOID Bssid;
  1081. PULONG BssStatus;
  1082. PUSHORT Capabilities;
  1083. PVOID Elements;
  1084. USHORT ElementsSize;
  1085. PNETLINK_GENERIC_HEADER GenericHeader;
  1086. PNETLINK_HEADER Header;
  1087. ULONG MessageLength;
  1088. PNETCON_SCAN_RESULTS ScanResults;
  1089. PLONG SignalMbm;
  1090. KSTATUS Status;
  1091. Bss = NULL;
  1092. Header = (PNETLINK_HEADER)Message;
  1093. Status = 0;
  1094. //
  1095. // Skip any messages that are not of the 802.11 family type.
  1096. //
  1097. if (Header->Type != Context->Type) {
  1098. goto ParseScanResultEnd;
  1099. }
  1100. //
  1101. // Parse the generic header to determine the 802.11 command and toss
  1102. // anything that isn't a scan result.
  1103. //
  1104. MessageLength = Header->Length;
  1105. MessageLength -= NETLINK_HEADER_LENGTH;
  1106. if (MessageLength < sizeof(NETLINK_GENERIC_HEADER)) {
  1107. goto ParseScanResultEnd;
  1108. }
  1109. GenericHeader = NETLINK_DATA(Header);
  1110. if (GenericHeader->Command != NETLINK_80211_COMMAND_SCAN_RESULT) {
  1111. goto ParseScanResultEnd;
  1112. }
  1113. //
  1114. // Get the BSS region of the attributes.
  1115. //
  1116. MessageLength -= NETLINK_GENERIC_HEADER_LENGTH;
  1117. Attributes = NETLINK_GENERIC_DATA(GenericHeader);
  1118. Status = NlGetAttribute(Attributes,
  1119. MessageLength,
  1120. NETLINK_80211_ATTRIBUTE_BSS,
  1121. &BssAttribute,
  1122. &BssAttributeLength);
  1123. if (Status != 0) {
  1124. goto ParseScanResultEnd;
  1125. }
  1126. Status = NlGetAttribute(BssAttribute,
  1127. BssAttributeLength,
  1128. NETLINK_80211_BSS_ATTRIBUTE_BSSID,
  1129. &Bssid,
  1130. &AttributeLength);
  1131. if (Status != 0) {
  1132. goto ParseScanResultEnd;
  1133. }
  1134. if (AttributeLength != NET80211_ADDRESS_SIZE) {
  1135. errno = ERANGE;
  1136. Status = -1;
  1137. goto ParseScanResultEnd;
  1138. }
  1139. Status = NlGetAttribute(BssAttribute,
  1140. BssAttributeLength,
  1141. NETLINK_80211_BSS_ATTRIBUTE_CAPABILITY,
  1142. (PVOID *)&Capabilities,
  1143. &AttributeLength);
  1144. if (Status != 0) {
  1145. goto ParseScanResultEnd;
  1146. }
  1147. if (AttributeLength != sizeof(USHORT)) {
  1148. errno = ERANGE;
  1149. Status = -1;
  1150. goto ParseScanResultEnd;
  1151. }
  1152. Status = NlGetAttribute(BssAttribute,
  1153. BssAttributeLength,
  1154. NETLINK_80211_BSS_ATTRIBUTE_BEACON_INTERVAL,
  1155. (PVOID *)&BeaconInterval,
  1156. &AttributeLength);
  1157. if (Status != 0) {
  1158. goto ParseScanResultEnd;
  1159. }
  1160. if (AttributeLength != sizeof(USHORT)) {
  1161. errno = ERANGE;
  1162. Status = -1;
  1163. goto ParseScanResultEnd;
  1164. }
  1165. Status = NlGetAttribute(BssAttribute,
  1166. BssAttributeLength,
  1167. NETLINK_80211_BSS_ATTRIBUTE_SIGNAL_MBM,
  1168. (PVOID *)&SignalMbm,
  1169. &AttributeLength);
  1170. if (Status != 0) {
  1171. goto ParseScanResultEnd;
  1172. }
  1173. if (AttributeLength != sizeof(LONG)) {
  1174. errno = ERANGE;
  1175. Status = -1;
  1176. goto ParseScanResultEnd;
  1177. }
  1178. Status = NlGetAttribute(BssAttribute,
  1179. BssAttributeLength,
  1180. NETLINK_80211_BSS_ATTRIBUTE_SIGNAL_MBM,
  1181. (PVOID *)&BssStatus,
  1182. &AttributeLength);
  1183. if (Status != 0) {
  1184. goto ParseScanResultEnd;
  1185. }
  1186. if (AttributeLength != sizeof(ULONG)) {
  1187. errno = ERANGE;
  1188. Status = -1;
  1189. goto ParseScanResultEnd;
  1190. }
  1191. Status = NlGetAttribute(BssAttribute,
  1192. BssAttributeLength,
  1193. NETLINK_80211_BSS_ATTRIBUTE_INFORMATION_ELEMENTS,
  1194. &Elements,
  1195. &ElementsSize);
  1196. if (Status != 0) {
  1197. goto ParseScanResultEnd;
  1198. }
  1199. //
  1200. // Allocate a new BSS element and fill it out with the information
  1201. // collected above.
  1202. //
  1203. Bss = malloc(sizeof(NETCON_BSS) + ElementsSize);
  1204. if (Bss == NULL) {
  1205. goto ParseScanResultEnd;
  1206. }
  1207. memset(Bss, 0, sizeof(NETCON_BSS));
  1208. Bss->Bssid.Domain = NetDomain80211;
  1209. memcpy(Bss->Bssid.Address, Bssid, NET80211_ADDRESS_SIZE);
  1210. Bss->SignalStrength = *SignalMbm;
  1211. Bss->Status = *BssStatus;
  1212. Bss->BeaconInterval = *BeaconInterval;
  1213. Bss->Capabilities = *Capabilities;
  1214. Bss->Elements = Bss + 1;
  1215. Bss->ElementsSize = ElementsSize;
  1216. memcpy(Bss->Elements, Elements, ElementsSize);
  1217. //
  1218. // Expand the scan results array to incorporate this BSS element.
  1219. //
  1220. ScanResults = (PNETCON_SCAN_RESULTS)Context->PrivateContext;
  1221. BssCount = ScanResults->BssCount + 1;
  1222. BssArray = realloc(ScanResults->BssArray,
  1223. BssCount * sizeof(PNETCON_BSS));
  1224. if (BssArray == NULL) {
  1225. ScanResults->BssCount = 0;
  1226. Status = -1;
  1227. goto ParseScanResultEnd;
  1228. }
  1229. ScanResults->BssArray = BssArray;
  1230. ScanResults->BssCount = BssCount;
  1231. ScanResults->BssArray[BssCount - 1] = Bss;
  1232. ScanResults->Valid = TRUE;
  1233. ParseScanResultEnd:
  1234. if (Status != 0) {
  1235. if (Bss != NULL) {
  1236. free(Bss);
  1237. }
  1238. }
  1239. return;
  1240. }
  1241. VOID
  1242. NetconPrintScanResults (
  1243. PNETCON_CONTEXT Context,
  1244. PNETCON_SCAN_RESULTS Results
  1245. )
  1246. /*++
  1247. Routine Description:
  1248. This routine prints the given scan results list to standard out.
  1249. Arguments:
  1250. Context - Supplies a pointer to the network connection context.
  1251. Results - Supplies a pointer to the network scan results.
  1252. Return Value:
  1253. None.
  1254. --*/
  1255. {
  1256. PNETCON_BSS Bss;
  1257. PVOID Channel;
  1258. ULONG Index;
  1259. PVOID RatesElement;
  1260. PVOID Rsn;
  1261. UCHAR Ssid[NET80211_MAX_SSID_LENGTH + 1];
  1262. PVOID SsidElement;
  1263. ULONG SsidLength;
  1264. printf("Device 0x%I64x:\n", Context->DeviceId);
  1265. printf("Networks Visisble: %d\n\n", Results->BssCount);
  1266. for (Index = 0; Index < Results->BssCount; Index += 1) {
  1267. Bss = Results->BssArray[Index];
  1268. SsidElement = NetconGet80211InformationElement(Bss->Elements,
  1269. Bss->ElementsSize,
  1270. NET80211_ELEMENT_SSID);
  1271. SsidLength = 0;
  1272. if (SsidElement != NULL) {
  1273. SsidLength = NET80211_GET_ELEMENT_LENGTH(SsidElement);
  1274. memcpy(Ssid, NET80211_GET_ELEMENT_DATA(SsidElement), SsidLength);
  1275. }
  1276. Ssid[SsidLength] = STRING_TERMINATOR;
  1277. printf("SSID %d: %s\n", Index, Ssid);
  1278. if (Bss->Status == NETLINK_80211_BSS_STATUS_ASSOCIATED) {
  1279. printf("\tStatus: Connected\n");
  1280. }
  1281. Rsn = NetconGet80211InformationElement(Bss->Elements,
  1282. Bss->ElementsSize,
  1283. NET80211_ELEMENT_RSN);
  1284. if (Rsn != NULL) {
  1285. NetconPrintRsnInformation(Rsn);
  1286. } else {
  1287. printf("\tAuthentication: Open\n");
  1288. printf("\tEncryption: None\n");
  1289. }
  1290. if ((Context->Flags & NETCON_FLAG_VERBOSE) == 0) {
  1291. printf("\n");
  1292. continue;
  1293. }
  1294. printf("\tBSSID: ");
  1295. NetconPrintAddress(&(Bss->Bssid));
  1296. NetconPrintRssi(Bss->SignalStrength / 100);
  1297. Channel = NetconGet80211InformationElement(Bss->Elements,
  1298. Bss->ElementsSize,
  1299. NET80211_ELEMENT_DSSS);
  1300. if (Channel != NULL) {
  1301. printf("\tChannel: %d\n", *NET80211_GET_ELEMENT_DATA(Channel));
  1302. }
  1303. printf("\tBeacon Interval: %d ms\n", Bss->BeaconInterval);
  1304. printf("\tCapabilities: 0x%04x\n", Bss->Capabilities);
  1305. RatesElement = NetconGet80211InformationElement(
  1306. Bss->Elements,
  1307. Bss->ElementsSize,
  1308. NET80211_ELEMENT_SUPPORTED_RATES);
  1309. if (RatesElement != NULL) {
  1310. printf("\tSupported Rates (Mbps):");
  1311. NetconPrintRates(RatesElement);
  1312. }
  1313. RatesElement = NetconGet80211InformationElement(
  1314. Bss->Elements,
  1315. Bss->ElementsSize,
  1316. NET80211_ELEMENT_EXTENDED_SUPPORTED_RATES);
  1317. if (RatesElement != NULL) {
  1318. printf("\tExtended Rates (Mbps):");
  1319. NetconPrintRates(RatesElement);
  1320. }
  1321. printf("\n");
  1322. }
  1323. return;
  1324. }
  1325. PVOID
  1326. NetconGet80211InformationElement (
  1327. PVOID Elements,
  1328. ULONG ElementsSize,
  1329. UCHAR ElementId
  1330. )
  1331. /*++
  1332. Routine Description:
  1333. This routine searches the given information element buffer for the element
  1334. with the given ID, returning a pointer to the element's header.
  1335. Arguments:
  1336. Elements - Supplies a pointer to the set of information elements to search.
  1337. ElementsSize - Supplies the size of the informatin elements, in bytes.
  1338. ElementId - Supplies the ID of the element to lookup.
  1339. Return Value:
  1340. Returns a pointer to the information element on success or NULL on failure.
  1341. --*/
  1342. {
  1343. PVOID Element;
  1344. ULONG ElementLength;
  1345. PVOID FoundElement;
  1346. ULONG RemainingSize;
  1347. FoundElement = NULL;
  1348. //
  1349. // A valid element must have at least two bytes - the ID and the length.
  1350. //
  1351. Element = Elements;
  1352. RemainingSize = ElementsSize;
  1353. while (RemainingSize >= NET80211_ELEMENT_HEADER_SIZE) {
  1354. ElementLength = NET80211_GET_ELEMENT_LENGTH(Element) +
  1355. NET80211_ELEMENT_HEADER_SIZE;
  1356. if (ElementLength > RemainingSize) {
  1357. break;
  1358. }
  1359. if (NET80211_GET_ELEMENT_ID(Element) == ElementId) {
  1360. FoundElement = Element;
  1361. break;
  1362. }
  1363. RemainingSize -= ElementLength;
  1364. Element += ElementLength;
  1365. }
  1366. return FoundElement;
  1367. }
  1368. VOID
  1369. NetconPrintRsnInformation (
  1370. PUCHAR Rsn
  1371. )
  1372. /*++
  1373. Routine Description:
  1374. This routine prints the encryption information encapsulated by the RSN
  1375. information element.
  1376. Arguments:
  1377. Rsn - Supplies a pointer to the RSN element, the first byte of which is the
  1378. element ID.
  1379. Return Value:
  1380. None.
  1381. --*/
  1382. {
  1383. ULONG AkmSuite;
  1384. ULONG AkmSuiteCount;
  1385. PULONG AkmSuites;
  1386. NETWORK_ENCRYPTION_TYPE Authentication;
  1387. ULONG GroupSuite;
  1388. ULONG Index;
  1389. ULONG Offset;
  1390. ULONG PairwiseSuite;
  1391. ULONG PairwiseSuiteCount;
  1392. PULONG PairwiseSuites;
  1393. ULONG RsnLength;
  1394. INT Status;
  1395. ULONG Suite;
  1396. USHORT Version;
  1397. ASSERT(NET80211_GET_ELEMENT_ID(Rsn) == NET80211_ELEMENT_RSN);
  1398. Status = 0;
  1399. Offset = NET80211_ELEMENT_HEADER_SIZE;
  1400. RsnLength = NET80211_GET_ELEMENT_LENGTH(Rsn);
  1401. AkmSuite = 0;
  1402. GroupSuite = 0;
  1403. PairwiseSuite = 0;
  1404. PairwiseSuites = NULL;
  1405. //
  1406. // The version field is the only non-optional field.
  1407. //
  1408. if ((Offset + sizeof(USHORT)) > RsnLength) {
  1409. Status = -1;
  1410. goto PrintRsnInformationEnd;
  1411. }
  1412. Version = *((PUSHORT)&(Rsn[Offset]));
  1413. Offset += sizeof(USHORT);
  1414. if (Version != NET80211_RSN_VERSION) {
  1415. Status = -1;
  1416. goto PrintRsnInformationEnd;
  1417. }
  1418. //
  1419. // Save the group suite if it is present.
  1420. //
  1421. if ((Offset + sizeof(ULONG)) > RsnLength) {
  1422. goto PrintRsnInformationEnd;
  1423. }
  1424. GroupSuite = NETWORK_TO_CPU32(*((PULONG)&(Rsn[Offset])));
  1425. Offset += sizeof(ULONG);
  1426. //
  1427. // Save a pointer to the pairwise suites, if present.
  1428. //
  1429. if ((Offset + sizeof(USHORT)) > RsnLength) {
  1430. goto PrintRsnInformationEnd;
  1431. }
  1432. PairwiseSuiteCount = *((PUSHORT)&(Rsn[Offset]));
  1433. Offset += sizeof(USHORT);
  1434. if ((Offset + (sizeof(ULONG) * PairwiseSuiteCount)) > RsnLength) {
  1435. goto PrintRsnInformationEnd;
  1436. }
  1437. PairwiseSuites = (PULONG)&(Rsn[Offset]);
  1438. Offset += sizeof(ULONG) * PairwiseSuiteCount;
  1439. //
  1440. // Run through the pairwise suites to determine the most secure option.
  1441. //
  1442. for (Index = 0; Index < PairwiseSuiteCount; Index += 1) {
  1443. Suite = NETWORK_TO_CPU32(PairwiseSuites[Index]);
  1444. //
  1445. // CCMP is always the highest.
  1446. //
  1447. if (Suite == NET80211_CIPHER_SUITE_CCMP) {
  1448. PairwiseSuite = Suite;
  1449. break;
  1450. }
  1451. //
  1452. // TKIP beats nothing and WEP.
  1453. //
  1454. if ((Suite == NET80211_CIPHER_SUITE_TKIP) &&
  1455. ((PairwiseSuite == 0) ||
  1456. (PairwiseSuite == NET80211_CIPHER_SUITE_WEP_40) ||
  1457. (PairwiseSuite == NET80211_CIPHER_SUITE_WEP_104))) {
  1458. PairwiseSuite = Suite;
  1459. }
  1460. //
  1461. // WEP only beats nothing.
  1462. //
  1463. if ((PairwiseSuite == 0) &&
  1464. ((Suite == NET80211_CIPHER_SUITE_WEP_40) ||
  1465. (Suite == NET80211_CIPHER_SUITE_WEP_104))) {
  1466. PairwiseSuite = Suite;
  1467. }
  1468. }
  1469. //
  1470. // The PSK authentication and key management (AKM) must be one of the
  1471. // optional AKM suites.
  1472. //
  1473. if ((Offset + sizeof(USHORT)) > RsnLength) {
  1474. goto PrintRsnInformationEnd;
  1475. }
  1476. AkmSuiteCount = *((PUSHORT)&(Rsn[Offset]));
  1477. Offset += sizeof(USHORT);
  1478. if ((Offset + (AkmSuiteCount * sizeof(ULONG))) > RsnLength) {
  1479. goto PrintRsnInformationEnd;
  1480. }
  1481. AkmSuites = (PULONG)&(Rsn[Offset]);
  1482. for (Index = 0; Index < AkmSuiteCount; Index += 1) {
  1483. Suite = NETWORK_TO_CPU32(AkmSuites[Index]);
  1484. if ((Suite == NET80211_AKM_SUITE_PSK) ||
  1485. (Suite == NET80211_AKM_SUITE_PSK_SHA256)) {
  1486. AkmSuite = Suite;
  1487. break;
  1488. }
  1489. if ((Suite == NET80211_AKM_SUITE_8021X) ||
  1490. (Suite == NET80211_AKM_SUITE_8021X_SHA256)) {
  1491. AkmSuite = Suite;
  1492. break;
  1493. }
  1494. }
  1495. Offset += sizeof(ULONG) * AkmSuiteCount;
  1496. PrintRsnInformationEnd:
  1497. if (Status != 0) {
  1498. printf("\tAuthentication: unknown\n");
  1499. } else {
  1500. Authentication = NetworkEncryptionInvalid;
  1501. switch (PairwiseSuite) {
  1502. case NET80211_CIPHER_SUITE_WEP_40:
  1503. case NET80211_CIPHER_SUITE_WEP_104:
  1504. Authentication = NetworkEncryptionWep;
  1505. break;
  1506. case NET80211_CIPHER_SUITE_TKIP:
  1507. switch (AkmSuite) {
  1508. case NET80211_AKM_SUITE_PSK:
  1509. case NET80211_AKM_SUITE_PSK_SHA256:
  1510. Authentication = NetworkEncryptionWpaPsk;
  1511. break;
  1512. case NET80211_AKM_SUITE_8021X:
  1513. case NET80211_AKM_SUITE_8021X_SHA256:
  1514. Authentication = NetworkEncryptionWpaEap;
  1515. break;
  1516. default:
  1517. break;
  1518. }
  1519. break;
  1520. case NET80211_CIPHER_SUITE_CCMP:
  1521. switch (AkmSuite) {
  1522. case NET80211_AKM_SUITE_PSK:
  1523. case NET80211_AKM_SUITE_PSK_SHA256:
  1524. Authentication = NetworkEncryptionWpa2Psk;
  1525. break;
  1526. case NET80211_AKM_SUITE_8021X:
  1527. case NET80211_AKM_SUITE_8021X_SHA256:
  1528. Authentication = NetworkEncryptionWpa2Eap;
  1529. break;
  1530. default:
  1531. break;
  1532. }
  1533. break;
  1534. default:
  1535. break;
  1536. }
  1537. printf("\tAuthentication: ");
  1538. NetconPrintEncryption(Authentication);
  1539. if (PairwiseSuites != NULL) {
  1540. printf("\tPairwise Encryption:");
  1541. for (Index = 0; Index < PairwiseSuiteCount; Index += 1) {
  1542. Suite = NETWORK_TO_CPU32(PairwiseSuites[Index]);
  1543. printf(" ");
  1544. NetconPrintCipherSuite(Suite);
  1545. }
  1546. printf("\n");
  1547. }
  1548. if ((GroupSuite != 0) &&
  1549. (GroupSuite != NET80211_CIPHER_SUITE_GROUP_NOT_ALLOWED)) {
  1550. printf("\tGroup Encryption: ");
  1551. NetconPrintCipherSuite(GroupSuite);
  1552. printf("\n");
  1553. }
  1554. }
  1555. return;
  1556. }
  1557. VOID
  1558. NetconPrintDeviceInformation (
  1559. PNETCON_DEVICE_DESCRIPTION Device
  1560. )
  1561. /*++
  1562. Routine Description:
  1563. This routine prints out the network information for the given device.
  1564. Arguments:
  1565. Device - Supplies a pointer to the network device whose information is to
  1566. be printed.
  1567. Return Value:
  1568. None.
  1569. --*/
  1570. {
  1571. NETWORK_ADDRESS_CONFIGURATION_METHOD Configuration;
  1572. PNETWORK_80211_DEVICE_INFORMATION Net80211;
  1573. PNETWORK_DEVICE_INFORMATION Network;
  1574. PNETWORK_ADDRESS PhysicalAddress;
  1575. printf("Network Device 0x%I64x:\n", Device->DeviceId);
  1576. PhysicalAddress = NULL;
  1577. if ((Device->Flags & NETCON_DEVICE_FLAG_IP4) != 0) {
  1578. PhysicalAddress = &(Device->NetworkIp4.PhysicalAddress);
  1579. } else if ((Device->Flags & NETCON_DEVICE_FLAG_IP6) == 0) {
  1580. PhysicalAddress = &(Device->NetworkIp6.PhysicalAddress);
  1581. }
  1582. if (PhysicalAddress == NULL) {
  1583. return;
  1584. }
  1585. //
  1586. // The physical address should always be present.
  1587. //
  1588. printf("\tPhysical Address: ");
  1589. NetconPrintAddress(PhysicalAddress);
  1590. //
  1591. // Print the IPv4 address line to show that the device is IPv4 capable, but
  1592. // only print the actual address if it is configured.
  1593. //
  1594. if ((Device->Flags & NETCON_DEVICE_FLAG_IP4) != 0) {
  1595. printf("\tIPv4 Address: ");
  1596. Network = &(Device->NetworkIp4);
  1597. Configuration = Network->ConfigurationMethod;
  1598. if ((Configuration != NetworkAddressConfigurationInvalid) &&
  1599. (Configuration != NetworkAddressConfigurationNone)) {
  1600. NetconPrintAddress(&(Network->Address));
  1601. printf("\tSubnet Mask: ");
  1602. NetconPrintAddress(&(Network->Subnet));
  1603. printf("\tGateway: ");
  1604. NetconPrintAddress(&(Network->Gateway));
  1605. } else {
  1606. printf("(not configured)\n");
  1607. }
  1608. }
  1609. //
  1610. // Print the IPv6 address line to show that the device is IPv4 capable, but
  1611. // only print the actual address if it is configured.
  1612. //
  1613. if ((Device->Flags & NETCON_DEVICE_FLAG_IP6) != 0) {
  1614. printf("\tIPv6 Address: ");
  1615. Network = &(Device->NetworkIp6);
  1616. Configuration = Network->ConfigurationMethod;
  1617. if ((Configuration != NetworkAddressConfigurationInvalid) &&
  1618. (Configuration != NetworkAddressConfigurationNone)) {
  1619. NetconPrintAddress(&(Network->Address));
  1620. printf("\tSubnet Mask: ");
  1621. NetconPrintAddress(&(Network->Subnet));
  1622. printf("\tGateway: ");
  1623. NetconPrintAddress(&(Network->Gateway));
  1624. } else {
  1625. printf("(not configured)\n");
  1626. }
  1627. }
  1628. //
  1629. // If the device supports 802.11, at least print the SSID or
  1630. // "Not Associated".
  1631. //
  1632. if ((Device->Flags & NETCON_DEVICE_FLAG_80211) != 0) {
  1633. Net80211 = &(Device->Net80211);
  1634. printf("\tSSID: ");
  1635. if ((Net80211->Flags & NETWORK_80211_DEVICE_FLAG_ASSOCIATED) != 0) {
  1636. printf("\"%s\"\n", Net80211->Ssid);
  1637. printf("\tBSSID: ");
  1638. NetconPrintAddress(&(Net80211->Bssid));
  1639. printf("\tChannel: %d\n", Net80211->Channel);
  1640. printf("\tMax Rate: %.1f Mbps\n",
  1641. (double)Net80211->MaxRate / 1000000ULL);
  1642. NetconPrintRssi(Net80211->Rssi);
  1643. printf("\tPairwise Encryption: ");
  1644. NetconPrintEncryption(Net80211->PairwiseEncryption);
  1645. printf("\tGroup Encryption: ");
  1646. NetconPrintEncryption(Net80211->GroupEncryption);
  1647. } else {
  1648. printf("(not associated)\n");
  1649. }
  1650. }
  1651. printf("\n");
  1652. return;
  1653. }
  1654. VOID
  1655. NetconPrintAddress (
  1656. PNETWORK_ADDRESS Address
  1657. )
  1658. /*++
  1659. Routine Description:
  1660. This routine prints the given network address to standard out.
  1661. Arguments:
  1662. Address - Supplies a pointer to the network address to print.
  1663. Return Value:
  1664. None.
  1665. --*/
  1666. {
  1667. socklen_t AddressLength;
  1668. PUCHAR BytePointer;
  1669. struct sockaddr_in Ip4Address;
  1670. struct sockaddr_in6 Ip6Address;
  1671. CHAR PrintBuffer[60];
  1672. KSTATUS Status;
  1673. switch (Address->Domain) {
  1674. case NetDomainIp4:
  1675. AddressLength = sizeof(struct sockaddr_in);
  1676. Status = ClConvertFromNetworkAddress(Address,
  1677. (struct sockaddr *)&Ip4Address,
  1678. &AddressLength,
  1679. NULL,
  1680. 0);
  1681. if (!KSUCCESS(Status)) {
  1682. break;
  1683. }
  1684. inet_ntop(Ip4Address.sin_family,
  1685. &(Ip4Address.sin_addr.s_addr),
  1686. PrintBuffer,
  1687. sizeof(PrintBuffer));
  1688. printf("%s", PrintBuffer);
  1689. break;
  1690. case NetDomainIp6:
  1691. AddressLength = sizeof(struct sockaddr_in6);
  1692. Status = ClConvertFromNetworkAddress(Address,
  1693. (struct sockaddr *)&Ip6Address,
  1694. &AddressLength,
  1695. NULL,
  1696. 0);
  1697. if (!KSUCCESS(Status)) {
  1698. break;
  1699. }
  1700. inet_ntop(Ip6Address.sin6_family,
  1701. &(Ip6Address.sin6_addr.s6_addr),
  1702. PrintBuffer,
  1703. sizeof(PrintBuffer));
  1704. printf("%s", PrintBuffer);
  1705. break;
  1706. case NetDomain80211:
  1707. case NetDomainEthernet:
  1708. BytePointer = (PUCHAR)(Address->Address);
  1709. printf("%02X:%02X:%02X:%02X:%02X:%02X",
  1710. BytePointer[0],
  1711. BytePointer[1],
  1712. BytePointer[2],
  1713. BytePointer[3],
  1714. BytePointer[4],
  1715. BytePointer[5]);
  1716. break;
  1717. default:
  1718. break;
  1719. }
  1720. printf("\n");
  1721. return;
  1722. }
  1723. VOID
  1724. NetconPrintEncryption (
  1725. NETWORK_ENCRYPTION_TYPE EncryptionType
  1726. )
  1727. /*++
  1728. Routine Description:
  1729. This routine prints the name of the given encryption type.
  1730. Arguments:
  1731. EncryptionType - Supplies the encryption type to print.
  1732. Return Value:
  1733. None.
  1734. --*/
  1735. {
  1736. switch (EncryptionType) {
  1737. case NetworkEncryptionNone:
  1738. printf("none");
  1739. break;
  1740. case NetworkEncryptionWep:
  1741. printf("WEP");
  1742. break;
  1743. case NetworkEncryptionWpaPsk:
  1744. printf("WPA-PSK");
  1745. break;
  1746. case NetworkEncryptionWpaEap:
  1747. printf("WPA-EAP");
  1748. break;
  1749. case NetworkEncryptionWpa2Psk:
  1750. printf("WPA2-PSK");
  1751. break;
  1752. case NetworkEncryptionWpa2Eap:
  1753. printf("WPA2-EAP");
  1754. break;
  1755. default:
  1756. printf("unknown");
  1757. break;
  1758. }
  1759. printf("\n");
  1760. return;
  1761. }
  1762. VOID
  1763. NetconPrintCipherSuite (
  1764. ULONG Suite
  1765. )
  1766. /*++
  1767. Routine Description:
  1768. This routine prints the name of the given cipher suite.
  1769. Arguments:
  1770. Suite - Supplies the cipher suite to print.
  1771. Return Value:
  1772. None.
  1773. --*/
  1774. {
  1775. switch (Suite) {
  1776. case NET80211_CIPHER_SUITE_USE_GROUP_CIPHER:
  1777. printf("Group Only");
  1778. break;
  1779. case NET80211_CIPHER_SUITE_WEP_40:
  1780. printf("WEP-40");
  1781. break;
  1782. case NET80211_CIPHER_SUITE_TKIP:
  1783. printf("TKIP");
  1784. break;
  1785. case NET80211_CIPHER_SUITE_CCMP:
  1786. printf("CCMP");
  1787. break;
  1788. case NET80211_CIPHER_SUITE_WEP_104:
  1789. printf("WEP-104");
  1790. break;
  1791. case NET80211_CIPHER_SUITE_BIP:
  1792. printf("BIP");
  1793. break;
  1794. default:
  1795. printf("unknown");
  1796. break;
  1797. }
  1798. return;
  1799. }
  1800. VOID
  1801. NetconPrintRssi (
  1802. LONG Rssi
  1803. )
  1804. /*++
  1805. Routine Description:
  1806. This routine prints the signal strength out to standard out.
  1807. Arguments:
  1808. Rssi - Supplies the RSSI value for signal strength in dBm.
  1809. Return Value:
  1810. None.
  1811. --*/
  1812. {
  1813. ULONG Percentage;
  1814. if (Rssi < -100) {
  1815. Percentage = 0;
  1816. } else if (Rssi > -50) {
  1817. Percentage = 100;
  1818. } else {
  1819. Percentage = 2 * (Rssi + 100);
  1820. }
  1821. printf("\tSignal Strength: %d%% (%d dBm)\n", Percentage, Rssi);
  1822. return;
  1823. }
  1824. VOID
  1825. NetconPrintRates (
  1826. PVOID RatesElement
  1827. )
  1828. /*++
  1829. Routine Description:
  1830. This routine prints out each rate stored in the given rate information
  1831. element. That values are printed out in Mbps.
  1832. Arguments:
  1833. RatesElement - Supplies a pointer to the rates element to print.
  1834. Return Value:
  1835. None.
  1836. --*/
  1837. {
  1838. ULONG Index;
  1839. ULONG Rate;
  1840. PUCHAR Rates;
  1841. Rates = NET80211_GET_ELEMENT_DATA(RatesElement);
  1842. for (Index = 0;
  1843. Index < NET80211_GET_ELEMENT_LENGTH(RatesElement);
  1844. Index += 1) {
  1845. Rate = Rates[Index] & NET80211_RATE_VALUE_MASK;
  1846. Rate *= NET80211_RATE_UNIT;
  1847. if ((Rate % 1000000) == 0) {
  1848. printf(" %d", Rate / 1000000);
  1849. } else {
  1850. printf(" %.1f", (double)Rate / 1000000);
  1851. }
  1852. }
  1853. printf("\n");
  1854. return;
  1855. }
  1856. INT
  1857. NetconGet80211DeviceId (
  1858. PDEVICE_ID DeviceId
  1859. )
  1860. /*++
  1861. Routine Description:
  1862. This routine gets the device ID of the system's 802.11 device. If there
  1863. are multiple 802.11 devices then it prints an error and the available
  1864. wireless devices.
  1865. Arguments:
  1866. DeviceId - Supplies a pointer that receives the 802.11 device's ID.
  1867. Return Value:
  1868. 0 on success.
  1869. Returns an error code on failure.
  1870. --*/
  1871. {
  1872. PNETCON_DEVICE_DESCRIPTION DeviceArray;
  1873. ULONG DeviceCount;
  1874. ULONG Index;
  1875. ULONG Net80211DeviceCount;
  1876. ULONG Net80211DeviceIndex;
  1877. INT Result;
  1878. Result = NetconEnumerateDevices(&DeviceArray, &DeviceCount);
  1879. if (Result != 0) {
  1880. return Result;
  1881. }
  1882. Net80211DeviceIndex = 0;
  1883. Net80211DeviceCount = 0;
  1884. for (Index = 0; Index < DeviceCount; Index += 1) {
  1885. if ((DeviceArray[Index].Flags & NETCON_DEVICE_FLAG_80211) != 0) {
  1886. Net80211DeviceCount += 1;
  1887. Net80211DeviceIndex = Index;
  1888. }
  1889. }
  1890. if (Net80211DeviceCount == 0) {
  1891. printf("netcon: failed to find a wireless device.\n");
  1892. Result = ENODEV;
  1893. } else if (Net80211DeviceCount == 1) {
  1894. *DeviceId = DeviceArray[Net80211DeviceIndex].DeviceId;
  1895. } else {
  1896. printf("There are %d wireless devices available. Please specify "
  1897. "a device ID with the -d parameter.\n",
  1898. Net80211DeviceCount);
  1899. printf("Wireless Devices:\n\n");
  1900. for (Index = 0; Index < DeviceCount; Index += 1) {
  1901. if ((DeviceArray[Index].Flags & NETCON_DEVICE_FLAG_80211) != 0) {
  1902. NetconPrintDeviceInformation(&(DeviceArray[Index]));
  1903. printf("\n");
  1904. }
  1905. }
  1906. Result = ENODEV;
  1907. }
  1908. free(DeviceArray);
  1909. return Result;
  1910. }