netlink.c 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. /*++
  2. Copyright (c) 2016 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. netlink.c
  5. Abstract:
  6. This module implements the generic netlink 802.11 family message handling.
  7. Author:
  8. Chris Stevens 29-Mar-2016
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include "net80211.h"
  16. #include <minoca/net/netlink.h>
  17. //
  18. // ---------------------------------------------------------------- Definitions
  19. //
  20. //
  21. // Define the multicast group indices. These must match the order of the
  22. // multicast group array below.
  23. //
  24. #define NETLINK_GENERIC_80211_MULTICAST_SCAN 0
  25. //
  26. // ------------------------------------------------------ Data Type Definitions
  27. //
  28. //
  29. // ----------------------------------------------- Internal Function Prototypes
  30. //
  31. KSTATUS
  32. Net80211pNetlinkJoin (
  33. PNET_SOCKET Socket,
  34. PNET_PACKET_BUFFER Packet,
  35. PNETLINK_GENERIC_COMMAND_INFORMATION Command
  36. );
  37. KSTATUS
  38. Net80211pNetlinkLeave (
  39. PNET_SOCKET Socket,
  40. PNET_PACKET_BUFFER Packet,
  41. PNETLINK_GENERIC_COMMAND_INFORMATION Command
  42. );
  43. KSTATUS
  44. Net80211pNetlinkScanStart (
  45. PNET_SOCKET Socket,
  46. PNET_PACKET_BUFFER Packet,
  47. PNETLINK_GENERIC_COMMAND_INFORMATION Command
  48. );
  49. VOID
  50. Net80211pNetlinkScanCompletionRoutine (
  51. PNET80211_LINK Link,
  52. KSTATUS ScanStatus
  53. );
  54. KSTATUS
  55. Net80211pNetlinkScanGetResults (
  56. PNET_SOCKET Socket,
  57. PNET_PACKET_BUFFER Packet,
  58. PNETLINK_GENERIC_COMMAND_INFORMATION Command
  59. );
  60. KSTATUS
  61. Net80211pNetlinkGetLink (
  62. PNET_PACKET_BUFFER Packet,
  63. PNET80211_LINK *Link
  64. );
  65. VOID
  66. Net80211pNetlinkSendScanNotification (
  67. PNET80211_LINK Link,
  68. UCHAR Command
  69. );
  70. //
  71. // -------------------------------------------------------------------- Globals
  72. //
  73. NETLINK_GENERIC_COMMAND Net80211NetlinkCommands[] = {
  74. {
  75. NETLINK_80211_COMMAND_JOIN,
  76. 0,
  77. Net80211pNetlinkJoin
  78. },
  79. {
  80. NETLINK_80211_COMMAND_LEAVE,
  81. 0,
  82. Net80211pNetlinkLeave
  83. },
  84. {
  85. NETLINK_80211_COMMAND_SCAN_START,
  86. 0,
  87. Net80211pNetlinkScanStart
  88. },
  89. {
  90. NETLINK_80211_COMMAND_SCAN_GET_RESULTS,
  91. NETLINK_HEADER_FLAG_DUMP,
  92. Net80211pNetlinkScanGetResults
  93. },
  94. };
  95. NETLINK_GENERIC_MULTICAST_GROUP Net80211NetlinkMulticastGroups[] = {
  96. {
  97. NETLINK_GENERIC_80211_MULTICAST_SCAN,
  98. sizeof(NETLINK_80211_MULTICAST_SCAN_NAME),
  99. NETLINK_80211_MULTICAST_SCAN_NAME
  100. },
  101. };
  102. NETLINK_GENERIC_FAMILY_PROPERTIES Net80211NetlinkFamilyProperties = {
  103. NETLINK_GENERIC_FAMILY_PROPERTIES_VERSION,
  104. 0,
  105. sizeof(NETLINK_GENERIC_80211_NAME),
  106. NETLINK_GENERIC_80211_NAME,
  107. Net80211NetlinkCommands,
  108. sizeof(Net80211NetlinkCommands) / sizeof(Net80211NetlinkCommands[0]),
  109. Net80211NetlinkMulticastGroups,
  110. sizeof(Net80211NetlinkMulticastGroups) /
  111. sizeof(Net80211NetlinkMulticastGroups[0]),
  112. };
  113. PNETLINK_GENERIC_FAMILY Net80211NetlinkFamily = NULL;
  114. //
  115. // ------------------------------------------------------------------ Functions
  116. //
  117. KSTATUS
  118. Net80211pNetlinkInitialize (
  119. VOID
  120. )
  121. /*++
  122. Routine Description:
  123. This routine initializes the generic netlink 802.11 family.
  124. Arguments:
  125. None.
  126. Return Value:
  127. Status code.
  128. --*/
  129. {
  130. KSTATUS Status;
  131. Status = NetlinkGenericRegisterFamily(&Net80211NetlinkFamilyProperties,
  132. &Net80211NetlinkFamily);
  133. return Status;
  134. }
  135. VOID
  136. Net80211pNetlinkDestroy (
  137. VOID
  138. )
  139. /*++
  140. Routine Description:
  141. This routine tears down support for the generic netlink 802.11 family.
  142. Arguments:
  143. None.
  144. Return Value:
  145. None.
  146. --*/
  147. {
  148. if (Net80211NetlinkFamily != NULL) {
  149. NetlinkGenericUnregisterFamily(Net80211NetlinkFamily);
  150. Net80211NetlinkFamily = NULL;
  151. }
  152. return;
  153. }
  154. //
  155. // --------------------------------------------------------- Internal Functions
  156. //
  157. KSTATUS
  158. Net80211pNetlinkJoin (
  159. PNET_SOCKET Socket,
  160. PNET_PACKET_BUFFER Packet,
  161. PNETLINK_GENERIC_COMMAND_INFORMATION Command
  162. )
  163. /*++
  164. Routine Description:
  165. This routine is called to process an 802.11 netlink network join request.
  166. It attempts to join a device to a network as specified by the netlink
  167. message.
  168. Arguments:
  169. Socket - Supplies a pointer to the socket that received the packet.
  170. Packet - Supplies a pointer to a structure describing the incoming packet.
  171. This structure may be used as a scratch space while this routine
  172. executes and the packet travels up the stack, but will not be accessed
  173. after this routine returns.
  174. Command - Supplies a pointer to the command information.
  175. Return Value:
  176. Status code.
  177. --*/
  178. {
  179. PVOID Attributes;
  180. ULONG AttributesLength;
  181. PVOID Bssid;
  182. USHORT BssidLength;
  183. PNET80211_LINK Link;
  184. PUCHAR Passphrase;
  185. USHORT PassphraseLength;
  186. NET80211_SCAN_STATE ScanParameters;
  187. PUCHAR Ssid;
  188. USHORT SsidLength;
  189. KSTATUS Status;
  190. //
  191. // Parse the packet to find the 802.11 link that is to join a network.
  192. //
  193. Status = Net80211pNetlinkGetLink(Packet, &Link);
  194. if (!KSUCCESS(Status)) {
  195. goto NetlinkJoinEnd;
  196. }
  197. //
  198. // An SSID is necessary even if a BSSID is supplied. The user shouldn't
  199. // join an BSSID that switched SSID's on it.
  200. //
  201. Attributes = Packet->Buffer + Packet->DataOffset;
  202. AttributesLength = Packet->FooterOffset - Packet->DataOffset;
  203. Status = NetlinkGetAttribute(Attributes,
  204. AttributesLength,
  205. NETLINK_80211_ATTRIBUTE_SSID,
  206. (PVOID *)&Ssid,
  207. &SsidLength);
  208. if (!KSUCCESS(Status)) {
  209. goto NetlinkJoinEnd;
  210. }
  211. //
  212. // The attribute should store a null-terminated SSID string. Fail if it is
  213. // not present and strip it if it is present. The scan parameters do not
  214. // take a null-terminator SSID.
  215. //
  216. if (Ssid[SsidLength - 1] != STRING_TERMINATOR) {
  217. Status = STATUS_INVALID_PARAMETER;
  218. goto NetlinkJoinEnd;
  219. }
  220. SsidLength -= 1;
  221. if (SsidLength > NET80211_MAX_SSID_LENGTH) {
  222. Status = STATUS_NAME_TOO_LONG;
  223. goto NetlinkJoinEnd;
  224. }
  225. //
  226. // The passphrase is optional as some network do not require them. Make
  227. // sure it is null-terminated and strip the null character if it is.
  228. //
  229. Status = NetlinkGetAttribute(Attributes,
  230. AttributesLength,
  231. NETLINK_80211_ATTRIBUTE_PASSPHRASE,
  232. (PVOID *)&Passphrase,
  233. &PassphraseLength);
  234. if (KSUCCESS(Status)) {
  235. if (Passphrase[PassphraseLength - 1] != STRING_TERMINATOR) {
  236. Status = STATUS_INVALID_PARAMETER;
  237. goto NetlinkJoinEnd;
  238. }
  239. PassphraseLength -= 1;
  240. if (PassphraseLength > NET80211_MAX_PASSPHRASE_LENGTH) {
  241. Status = STATUS_NAME_TOO_LONG;
  242. goto NetlinkJoinEnd;
  243. }
  244. }
  245. //
  246. // The BSSID is optional as the MAC address of the access point is not
  247. // always known.
  248. //
  249. Status = NetlinkGetAttribute(Attributes,
  250. AttributesLength,
  251. NETLINK_80211_ATTRIBUTE_BSSID,
  252. &Bssid,
  253. &BssidLength);
  254. if (KSUCCESS(Status)) {
  255. if (BssidLength != NET80211_ADDRESS_SIZE) {
  256. Status = STATUS_INVALID_PARAMETER;
  257. goto NetlinkJoinEnd;
  258. }
  259. }
  260. RtlZeroMemory(&ScanParameters, sizeof(NET80211_SCAN_STATE));
  261. ScanParameters.Link = Link;
  262. ScanParameters.Flags = NET80211_SCAN_FLAG_JOIN;
  263. if (BssidLength == 0) {
  264. ScanParameters.Flags |= NET80211_SCAN_FLAG_BROADCAST;
  265. } else {
  266. RtlCopyMemory(ScanParameters.Bssid, Bssid, BssidLength);
  267. }
  268. if (PassphraseLength != 0) {
  269. ScanParameters.PassphraseLength = PassphraseLength;
  270. RtlCopyMemory(ScanParameters.Passphrase, Passphrase, PassphraseLength);
  271. }
  272. RtlCopyMemory(ScanParameters.Ssid, Ssid, SsidLength);
  273. ScanParameters.SsidLength = SsidLength;
  274. Status = Net80211pStartScan(Link, &ScanParameters);
  275. if (!KSUCCESS(Status)) {
  276. goto NetlinkJoinEnd;
  277. }
  278. NetlinkJoinEnd:
  279. if (Link != NULL) {
  280. Net80211LinkReleaseReference(Link);
  281. }
  282. return Status;
  283. }
  284. KSTATUS
  285. Net80211pNetlinkLeave (
  286. PNET_SOCKET Socket,
  287. PNET_PACKET_BUFFER Packet,
  288. PNETLINK_GENERIC_COMMAND_INFORMATION Command
  289. )
  290. /*++
  291. Routine Description:
  292. This routine is called to process an 802.11 netlink request for a device to
  293. leave its current network.
  294. Arguments:
  295. Socket - Supplies a pointer to the socket that received the packet.
  296. Packet - Supplies a pointer to a structure describing the incoming packet.
  297. This structure may be used as a scratch space while this routine
  298. executes and the packet travels up the stack, but will not be accessed
  299. after this routine returns.
  300. Command - Supplies a pointer to the command information.
  301. Return Value:
  302. Status code.
  303. --*/
  304. {
  305. PNET80211_LINK Link;
  306. KSTATUS Status;
  307. //
  308. // Parse the packet to find the 802.11 link that is to leave its network.
  309. //
  310. Status = Net80211pNetlinkGetLink(Packet, &Link);
  311. if (!KSUCCESS(Status)) {
  312. goto NetlinkLeaveEnd;
  313. }
  314. //
  315. // Setting the link state to initialized will deactivate the current
  316. // connection and send the appropriate deactivation messages to the access
  317. // point.
  318. //
  319. Net80211pSetState(Link, Net80211StateInitialized);
  320. NetlinkLeaveEnd:
  321. if (Link != NULL) {
  322. Net80211LinkReleaseReference(Link);
  323. }
  324. return Status;
  325. }
  326. KSTATUS
  327. Net80211pNetlinkScanStart (
  328. PNET_SOCKET Socket,
  329. PNET_PACKET_BUFFER Packet,
  330. PNETLINK_GENERIC_COMMAND_INFORMATION Command
  331. )
  332. /*++
  333. Routine Description:
  334. This routine is called to process an 802.11 netlink request to start
  335. scanning for available wireless networks.
  336. Arguments:
  337. Socket - Supplies a pointer to the socket that received the packet.
  338. Packet - Supplies a pointer to a structure describing the incoming packet.
  339. This structure may be used as a scratch space while this routine
  340. executes and the packet travels up the stack, but will not be accessed
  341. after this routine returns.
  342. Command - Supplies a pointer to the command information.
  343. Return Value:
  344. Status code.
  345. --*/
  346. {
  347. PNET80211_LINK Link;
  348. NET80211_SCAN_STATE ScanParameters;
  349. KSTATUS Status;
  350. //
  351. // Parse the packet to find the 802.11 link that is to scan for networks.
  352. //
  353. Status = Net80211pNetlinkGetLink(Packet, &Link);
  354. if (!KSUCCESS(Status)) {
  355. goto NetlinkScanStartEnd;
  356. }
  357. //
  358. // Kick off a background scan to update the BSS cache for this link.
  359. //
  360. RtlZeroMemory(&ScanParameters, sizeof(NET80211_SCAN_STATE));
  361. ScanParameters.Link = Link;
  362. ScanParameters.Flags = NET80211_SCAN_FLAG_BROADCAST;
  363. ScanParameters.CompletionRoutine = Net80211pNetlinkScanCompletionRoutine;
  364. Status = Net80211pStartScan(Link, &ScanParameters);
  365. if (!KSUCCESS(Status)) {
  366. goto NetlinkScanStartEnd;
  367. }
  368. //
  369. // Notify the scan multicast group that this scan is starting.
  370. //
  371. Net80211pNetlinkSendScanNotification(Link,
  372. NETLINK_80211_COMMAND_SCAN_START);
  373. NetlinkScanStartEnd:
  374. if (Link != NULL) {
  375. Net80211LinkReleaseReference(Link);
  376. }
  377. return Status;
  378. }
  379. VOID
  380. Net80211pNetlinkScanCompletionRoutine (
  381. PNET80211_LINK Link,
  382. KSTATUS ScanStatus
  383. )
  384. /*++
  385. Routine Description:
  386. This routine is called when a scan for nearby BSS access points has
  387. completed.
  388. Arguments:
  389. Link - Supplies a pointer to the 802.11 link that performed the scan.
  390. ScanStatus - Supplies the status result of the scan.
  391. Return Value:
  392. None.
  393. --*/
  394. {
  395. UCHAR Command;
  396. //
  397. // Report success or failure without any further details on an error.
  398. //
  399. Command = NETLINK_80211_COMMAND_SCAN_RESULT;
  400. if (!KSUCCESS(ScanStatus)) {
  401. Command = NETLINK_80211_COMMAND_SCAN_ABORTED;
  402. }
  403. Net80211pNetlinkSendScanNotification(Link, Command);
  404. return;
  405. }
  406. KSTATUS
  407. Net80211pNetlinkScanGetResults (
  408. PNET_SOCKET Socket,
  409. PNET_PACKET_BUFFER Packet,
  410. PNETLINK_GENERIC_COMMAND_INFORMATION Command
  411. )
  412. /*++
  413. Routine Description:
  414. This routine gets the results from the latest scan, packages them up as
  415. a netlink message and sends them back to the caller.
  416. Arguments:
  417. Socket - Supplies a pointer to the socket that received the packet.
  418. Packet - Supplies a pointer to a structure describing the incoming packet.
  419. This structure may be used as a scratch space while this routine
  420. executes and the packet travels up the stack, but will not be accessed
  421. after this routine returns.
  422. Command - Supplies a pointer to the command information.
  423. Return Value:
  424. Status code.
  425. --*/
  426. {
  427. PNET80211_BSS_ENTRY Bss;
  428. ULONG BssCount;
  429. ULONG BssLength;
  430. ULONG BssStatus;
  431. PLIST_ENTRY CurrentEntry;
  432. DEVICE_ID DeviceId;
  433. PNET80211_LINK Link;
  434. ULONG ResultLength;
  435. PNET_PACKET_BUFFER Results;
  436. ULONG ResultsLength;
  437. LONG SignalMbm;
  438. KSTATUS Status;
  439. //
  440. // Parse the packet to find the 802.11 link whose scan results are to be
  441. // queried.
  442. //
  443. Status = Net80211pNetlinkGetLink(Packet, &Link);
  444. if (!KSUCCESS(Status)) {
  445. goto NetlinkScanGetResultsEnd;
  446. }
  447. //
  448. // Determine the required size of the BSS replies.
  449. //
  450. BssCount = 0;
  451. ResultsLength = 0;
  452. KeAcquireQueuedLock(Link->Lock);
  453. CurrentEntry = Link->BssList.Next;
  454. while (CurrentEntry != &(Link->BssList)) {
  455. Bss = LIST_VALUE(CurrentEntry, NET80211_BSS_ENTRY, ListEntry);
  456. CurrentEntry = CurrentEntry->Next;
  457. ResultsLength += NETLINK_HEADER_LENGTH + NETLINK_GENERIC_HEADER_LENGTH;
  458. ResultsLength += NETLINK_ATTRIBUTE_SIZE(sizeof(DEVICE_ID));
  459. BssLength = NETLINK_ATTRIBUTE_SIZE(NET80211_ADDRESS_SIZE) +
  460. NETLINK_ATTRIBUTE_SIZE(sizeof(Bss->State.Capabilities)) +
  461. NETLINK_ATTRIBUTE_SIZE(sizeof(Bss->State.BeaconInterval)) +
  462. NETLINK_ATTRIBUTE_SIZE(sizeof(BssStatus)) +
  463. NETLINK_ATTRIBUTE_SIZE(sizeof(SignalMbm)) +
  464. NETLINK_ATTRIBUTE_SIZE(Bss->ElementsSize);
  465. ResultsLength += NETLINK_ATTRIBUTE_SIZE(BssLength);
  466. BssCount += 1;
  467. }
  468. KeReleaseQueuedLock(Link->Lock);
  469. //
  470. // At least always send a done message.
  471. //
  472. ResultsLength += NETLINK_HEADER_LENGTH;
  473. //
  474. // Allocate the network packet buffer to hold all of the results.
  475. //
  476. Status = NetAllocateBuffer(0, ResultsLength, 0, NULL, 0, &Results);
  477. if (!KSUCCESS(Status)) {
  478. goto NetlinkScanGetResultsEnd;
  479. }
  480. //
  481. // Package up the BSS entry list into multiple netlink scan result messages.
  482. // If new entries arrived since the lock was held before, they came in due
  483. // to an additional scan. A future scan results request will package them
  484. // up.
  485. //
  486. DeviceId = IoGetDeviceNumericId(Link->Properties.Device);
  487. KeAcquireQueuedLock(Link->Lock);
  488. CurrentEntry = Link->BssList.Next;
  489. while ((CurrentEntry != &(Link->BssList)) && (BssCount != 0)) {
  490. Bss = LIST_VALUE(CurrentEntry, NET80211_BSS_ENTRY, ListEntry);
  491. CurrentEntry = CurrentEntry->Next;
  492. //
  493. // Determine the length of the entire message.
  494. //
  495. ResultLength = NETLINK_ATTRIBUTE_SIZE(sizeof(DEVICE_ID));
  496. BssLength = NETLINK_ATTRIBUTE_SIZE(NET80211_ADDRESS_SIZE) +
  497. NETLINK_ATTRIBUTE_SIZE(sizeof(Bss->State.Capabilities)) +
  498. NETLINK_ATTRIBUTE_SIZE(sizeof(Bss->State.BeaconInterval)) +
  499. NETLINK_ATTRIBUTE_SIZE(sizeof(BssStatus)) +
  500. NETLINK_ATTRIBUTE_SIZE(sizeof(SignalMbm)) +
  501. NETLINK_ATTRIBUTE_SIZE(Bss->ElementsSize);
  502. ResultLength += NETLINK_ATTRIBUTE_SIZE(BssLength);
  503. //
  504. // Add a generic and base header for this entry.
  505. //
  506. Status = NetlinkGenericAppendHeaders(Net80211NetlinkFamily,
  507. Results,
  508. ResultLength,
  509. Command->Message.SequenceNumber,
  510. NETLINK_HEADER_FLAG_MULTIPART,
  511. NETLINK_80211_COMMAND_SCAN_RESULT,
  512. 0);
  513. if (!KSUCCESS(Status)) {
  514. goto NetlinkScanGetResultsEnd;
  515. }
  516. //
  517. // Add the attributes.
  518. //
  519. Status = NetlinkAppendAttribute(Results,
  520. NETLINK_80211_ATTRIBUTE_DEVICE_ID,
  521. &DeviceId,
  522. sizeof(DEVICE_ID));
  523. if (!KSUCCESS(Status)) {
  524. goto NetlinkScanGetResultsEnd;
  525. }
  526. Status = NetlinkAppendAttribute(Results,
  527. NETLINK_80211_ATTRIBUTE_BSS,
  528. NULL,
  529. BssLength);
  530. if (!KSUCCESS(Status)) {
  531. goto NetlinkScanGetResultsEnd;
  532. }
  533. Status = NetlinkAppendAttribute(Results,
  534. NETLINK_80211_BSS_ATTRIBUTE_BSSID,
  535. Bss->State.Bssid,
  536. NET80211_ADDRESS_SIZE);
  537. if (!KSUCCESS(Status)) {
  538. goto NetlinkScanGetResultsEnd;
  539. }
  540. Status = NetlinkAppendAttribute(Results,
  541. NETLINK_80211_BSS_ATTRIBUTE_CAPABILITY,
  542. &(Bss->State.Capabilities),
  543. sizeof(Bss->State.Capabilities));
  544. if (!KSUCCESS(Status)) {
  545. goto NetlinkScanGetResultsEnd;
  546. }
  547. Status = NetlinkAppendAttribute(
  548. Results,
  549. NETLINK_80211_BSS_ATTRIBUTE_BEACON_INTERVAL,
  550. &(Bss->State.BeaconInterval),
  551. sizeof(Bss->State.BeaconInterval));
  552. if (!KSUCCESS(Status)) {
  553. goto NetlinkScanGetResultsEnd;
  554. }
  555. SignalMbm = Bss->State.Rssi * 100;
  556. Status = NetlinkAppendAttribute(Results,
  557. NETLINK_80211_BSS_ATTRIBUTE_SIGNAL_MBM,
  558. &SignalMbm,
  559. sizeof(SignalMbm));
  560. if (!KSUCCESS(Status)) {
  561. goto NetlinkScanGetResultsEnd;
  562. }
  563. BssStatus = NETLINK_80211_BSS_STATUS_NOT_CONNECTED;
  564. if (Bss == Link->ActiveBss) {
  565. switch (Link->State) {
  566. case Net80211StateAssociated:
  567. case Net80211StateEncrypted:
  568. Status = NETLINK_80211_BSS_STATUS_ASSOCIATED;
  569. break;
  570. case Net80211StateAssociating:
  571. Status = NETLINK_80211_BSS_STATUS_AUTHENTICATED;
  572. break;
  573. default:
  574. break;
  575. }
  576. }
  577. Status = NetlinkAppendAttribute(Results,
  578. NETLINK_80211_BSS_ATTRIBUTE_STATUS,
  579. &BssStatus,
  580. sizeof(BssStatus));
  581. if (!KSUCCESS(Status)) {
  582. goto NetlinkScanGetResultsEnd;
  583. }
  584. Status = NetlinkAppendAttribute(
  585. Results,
  586. NETLINK_80211_BSS_ATTRIBUTE_INFORMATION_ELEMENTS,
  587. Bss->Elements,
  588. Bss->ElementsSize);
  589. if (!KSUCCESS(Status)) {
  590. goto NetlinkScanGetResultsEnd;
  591. }
  592. BssCount -= 1;
  593. }
  594. KeReleaseQueuedLock(Link->Lock);
  595. //
  596. // Send this multipart message back to the source of the request. This
  597. // routine will add the terminating DONE message and then send the entire
  598. // set of messages in the results packet.
  599. //
  600. Status = NetlinkSendMultipartMessage(Socket,
  601. Results,
  602. Command->Message.SourceAddress,
  603. Command->Message.SequenceNumber);
  604. if (!KSUCCESS(Status)) {
  605. goto NetlinkScanGetResultsEnd;
  606. }
  607. NetlinkScanGetResultsEnd:
  608. if (Link != NULL) {
  609. Net80211LinkReleaseReference(Link);
  610. }
  611. return Status;
  612. }
  613. KSTATUS
  614. Net80211pNetlinkGetLink (
  615. PNET_PACKET_BUFFER Packet,
  616. PNET80211_LINK *Link
  617. )
  618. /*++
  619. Routine Description:
  620. This routine parses the given 802.11 netlink message packet for the device
  621. ID attribute and then looks for the corresponding 802.11 link. If found, a
  622. reference is taken on the the 802.11 link and it is the caller's
  623. responsibility to release the reference.
  624. Arguments:
  625. Packet - Supplies a pointer to the netlink message to parse for the device
  626. ID or order to determine the target 802.11 link.
  627. Link - Supplies a pointer that receives a pointer an 802.11 network link.
  628. Return Value:
  629. Status code.
  630. --*/
  631. {
  632. PVOID Attributes;
  633. ULONG AttributesLength;
  634. PDEVICE Device;
  635. PVOID DeviceId;
  636. USHORT DeviceIdLength;
  637. PNET80211_LINK Net80211Link;
  638. PNET_LINK NetLink;
  639. KSTATUS Status;
  640. Device = NULL;
  641. NetLink = NULL;
  642. Net80211Link = NULL;
  643. //
  644. // Get the device ID. It is necessary to find the appropriate link.
  645. //
  646. Attributes = Packet->Buffer + Packet->DataOffset;
  647. AttributesLength = Packet->FooterOffset - Packet->DataOffset;
  648. Status = NetlinkGetAttribute(Attributes,
  649. AttributesLength,
  650. NETLINK_80211_ATTRIBUTE_DEVICE_ID,
  651. &DeviceId,
  652. &DeviceIdLength);
  653. if (!KSUCCESS(Status)) {
  654. goto NetlinkGetLinkEnd;
  655. }
  656. if (DeviceIdLength != sizeof(DEVICE_ID)) {
  657. Status = STATUS_DATA_LENGTH_MISMATCH;
  658. goto NetlinkGetLinkEnd;
  659. }
  660. Device = IoGetDeviceByNumericId(*((PDEVICE_ID)DeviceId));
  661. if (Device == NULL) {
  662. Status = STATUS_NO_SUCH_DEVICE;
  663. goto NetlinkGetLinkEnd;
  664. }
  665. Status = NetLookupLinkByDevice(Device, &NetLink);
  666. if (!KSUCCESS(Status)) {
  667. goto NetlinkGetLinkEnd;
  668. }
  669. //
  670. // If the link is not an 802.11 type then nothing can be done.
  671. //
  672. if (NetLink->Properties.DataLinkType != NetDomain80211) {
  673. Status = STATUS_NOT_SUPPORTED;
  674. goto NetlinkGetLinkEnd;
  675. }
  676. //
  677. // Setting the link state to initialized will deactivate the current
  678. // connection and send the appropriate deactivation messages to the access
  679. // point.
  680. //
  681. Net80211Link = NetLink->DataLinkContext;
  682. Net80211LinkAddReference(Net80211Link);
  683. NetlinkGetLinkEnd:
  684. if (Device != NULL) {
  685. IoDeviceReleaseReference(Device);
  686. }
  687. if (NetLink != NULL) {
  688. NetLinkReleaseReference(NetLink);
  689. }
  690. *Link = Net80211Link;
  691. return Status;
  692. }
  693. VOID
  694. Net80211pNetlinkSendScanNotification (
  695. PNET80211_LINK Link,
  696. UCHAR Command
  697. )
  698. /*++
  699. Routine Description:
  700. This routine notifies the scan multicast group about a scan's progress.
  701. Arguments:
  702. Link - Supplies a pointer to the 802.11 link that performed the scan.
  703. Command - Supplies the 802.11 netlink command to send to the scan multicast
  704. group.
  705. Return Value:
  706. None.
  707. --*/
  708. {
  709. DEVICE_ID DeviceId;
  710. ULONG HeaderSize;
  711. PNET_PACKET_BUFFER Packet;
  712. ULONG PayloadSize;
  713. ULONG Size;
  714. KSTATUS Status;
  715. //
  716. // Allocate and build a network buffer to hold the scan properties.
  717. //
  718. Packet = NULL;
  719. HeaderSize = NETLINK_HEADER_LENGTH + NETLINK_GENERIC_HEADER_LENGTH;
  720. PayloadSize = NETLINK_ATTRIBUTE_SIZE(sizeof(DEVICE_ID));
  721. Size = HeaderSize + PayloadSize;
  722. Status = NetAllocateBuffer(0,
  723. Size,
  724. 0,
  725. NULL,
  726. 0,
  727. &Packet);
  728. if (!KSUCCESS(Status)) {
  729. goto NetlinkSendScanNotification;
  730. }
  731. Status = NetlinkGenericAppendHeaders(Net80211NetlinkFamily,
  732. Packet,
  733. PayloadSize,
  734. 0,
  735. 0,
  736. Command,
  737. 0);
  738. if (!KSUCCESS(Status)) {
  739. goto NetlinkSendScanNotification;
  740. }
  741. DeviceId = IoGetDeviceNumericId(Link->Properties.Device);
  742. Status = NetlinkAppendAttribute(Packet,
  743. NETLINK_80211_ATTRIBUTE_DEVICE_ID,
  744. &DeviceId,
  745. sizeof(DEVICE_ID));
  746. if (!KSUCCESS(Status)) {
  747. goto NetlinkSendScanNotification;
  748. }
  749. //
  750. // Send the packet out to the 802.11 scan multicast group.
  751. //
  752. Status = NetlinkGenericSendMulticastCommand(
  753. Net80211NetlinkFamily,
  754. Packet,
  755. NETLINK_GENERIC_80211_MULTICAST_SCAN);
  756. if (!KSUCCESS(Status)) {
  757. goto NetlinkSendScanNotification;
  758. }
  759. NetlinkSendScanNotification:
  760. if (Packet != NULL) {
  761. NetFreeBuffer(Packet);
  762. }
  763. return;
  764. }