nsWifiScannerDBus.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #include "nsWifiScannerDBus.h"
  5. #include "mozilla/ipc/DBusMessageRefPtr.h"
  6. #include "nsWifiAccessPoint.h"
  7. namespace mozilla {
  8. nsWifiScannerDBus::nsWifiScannerDBus(nsCOMArray<nsWifiAccessPoint> *aAccessPoints)
  9. : mAccessPoints(aAccessPoints)
  10. {
  11. MOZ_ASSERT(mAccessPoints);
  12. mConnection =
  13. already_AddRefed<DBusConnection>(dbus_bus_get(DBUS_BUS_SYSTEM, nullptr));
  14. MOZ_ASSERT(mConnection);
  15. dbus_connection_set_exit_on_disconnect(mConnection, false);
  16. MOZ_COUNT_CTOR(nsWifiScannerDBus);
  17. }
  18. nsWifiScannerDBus::~nsWifiScannerDBus()
  19. {
  20. MOZ_COUNT_DTOR(nsWifiScannerDBus);
  21. }
  22. nsresult
  23. nsWifiScannerDBus::Scan()
  24. {
  25. return SendMessage("org.freedesktop.NetworkManager",
  26. "/org/freedesktop/NetworkManager",
  27. "GetDevices");
  28. }
  29. nsresult
  30. nsWifiScannerDBus::SendMessage(const char* aInterface,
  31. const char* aPath,
  32. const char* aFuncCall)
  33. {
  34. RefPtr<DBusMessage> msg = already_AddRefed<DBusMessage>(
  35. dbus_message_new_method_call("org.freedesktop.NetworkManager",
  36. aPath, aInterface, aFuncCall));
  37. if (!msg) {
  38. return NS_ERROR_FAILURE;
  39. }
  40. DBusMessageIter argsIter;
  41. dbus_message_iter_init_append(msg, &argsIter);
  42. if (!strcmp(aFuncCall, "Get")) {
  43. const char* paramInterface = "org.freedesktop.NetworkManager.Device";
  44. if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING,
  45. &paramInterface)) {
  46. return NS_ERROR_FAILURE;
  47. }
  48. const char* paramDeviceType = "DeviceType";
  49. if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING,
  50. &paramDeviceType)) {
  51. return NS_ERROR_FAILURE;
  52. }
  53. } else if (!strcmp(aFuncCall, "GetAll")) {
  54. const char* param = "org.freedesktop.NetworkManager.AccessPoint";
  55. if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, &param)) {
  56. return NS_ERROR_FAILURE;
  57. }
  58. }
  59. DBusError err;
  60. dbus_error_init(&err);
  61. // http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html
  62. // Refer to function dbus_connection_send_with_reply_and_block.
  63. const uint32_t DBUS_DEFAULT_TIMEOUT = -1;
  64. RefPtr<DBusMessage> reply = already_AddRefed<DBusMessage>(
  65. dbus_connection_send_with_reply_and_block(mConnection, msg,
  66. DBUS_DEFAULT_TIMEOUT, &err));
  67. if (dbus_error_is_set(&err)) {
  68. dbus_error_free(&err);
  69. // In the GetAccessPoints case, if there are no access points, error is set.
  70. // We don't want to error out here.
  71. if (!strcmp(aFuncCall, "GetAccessPoints")) {
  72. return NS_OK;
  73. }
  74. return NS_ERROR_FAILURE;
  75. }
  76. nsresult rv;
  77. if (!strcmp(aFuncCall, "GetDevices")) {
  78. rv = IdentifyDevices(reply);
  79. } else if (!strcmp(aFuncCall, "Get")) {
  80. rv = IdentifyDeviceType(reply, aPath);
  81. } else if (!strcmp(aFuncCall, "GetAccessPoints")) {
  82. rv = IdentifyAccessPoints(reply);
  83. } else if (!strcmp(aFuncCall, "GetAll")) {
  84. rv = IdentifyAPProperties(reply);
  85. } else {
  86. rv = NS_ERROR_FAILURE;
  87. }
  88. return rv;
  89. }
  90. nsresult
  91. nsWifiScannerDBus::IdentifyDevices(DBusMessage* aMsg)
  92. {
  93. DBusMessageIter iter;
  94. nsresult rv = GetDBusIterator(aMsg, &iter);
  95. NS_ENSURE_SUCCESS(rv, rv);
  96. const char* devicePath;
  97. do {
  98. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) {
  99. return NS_ERROR_FAILURE;
  100. }
  101. dbus_message_iter_get_basic(&iter, &devicePath);
  102. if (!devicePath) {
  103. return NS_ERROR_FAILURE;
  104. }
  105. rv = SendMessage("org.freedesktop.DBus.Properties", devicePath, "Get");
  106. NS_ENSURE_SUCCESS(rv, rv);
  107. } while (dbus_message_iter_next(&iter));
  108. return NS_OK;
  109. }
  110. nsresult
  111. nsWifiScannerDBus::IdentifyDeviceType(DBusMessage* aMsg, const char* aDevicePath)
  112. {
  113. DBusMessageIter args;
  114. if (!dbus_message_iter_init(aMsg, &args)) {
  115. return NS_ERROR_FAILURE;
  116. }
  117. if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_VARIANT) {
  118. return NS_ERROR_FAILURE;
  119. }
  120. DBusMessageIter variantIter;
  121. dbus_message_iter_recurse(&args, &variantIter);
  122. if (dbus_message_iter_get_arg_type(&variantIter) != DBUS_TYPE_UINT32) {
  123. return NS_ERROR_FAILURE;
  124. }
  125. uint32_t deviceType;
  126. dbus_message_iter_get_basic(&variantIter, &deviceType);
  127. // http://projects.gnome.org/NetworkManager/developers/api/07/spec-07.html
  128. // Refer to NM_DEVICE_TYPE_WIFI under NM_DEVICE_TYPE.
  129. const uint32_t NM_DEVICE_TYPE_WIFI = 2;
  130. nsresult rv = NS_OK;
  131. if (deviceType == NM_DEVICE_TYPE_WIFI) {
  132. rv = SendMessage("org.freedesktop.NetworkManager.Device.Wireless",
  133. aDevicePath, "GetAccessPoints");
  134. }
  135. return rv;
  136. }
  137. nsresult
  138. nsWifiScannerDBus::IdentifyAccessPoints(DBusMessage* aMsg)
  139. {
  140. DBusMessageIter iter;
  141. nsresult rv = GetDBusIterator(aMsg, &iter);
  142. NS_ENSURE_SUCCESS(rv, rv);
  143. const char* path;
  144. do {
  145. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) {
  146. return NS_ERROR_FAILURE;
  147. }
  148. dbus_message_iter_get_basic(&iter, &path);
  149. if (!path) {
  150. return NS_ERROR_FAILURE;
  151. }
  152. rv = SendMessage("org.freedesktop.DBus.Properties", path, "GetAll");
  153. NS_ENSURE_SUCCESS(rv, rv);
  154. } while (dbus_message_iter_next(&iter));
  155. return NS_OK;
  156. }
  157. nsresult
  158. nsWifiScannerDBus::IdentifyAPProperties(DBusMessage* aMsg)
  159. {
  160. DBusMessageIter arr;
  161. nsresult rv = GetDBusIterator(aMsg, &arr);
  162. NS_ENSURE_SUCCESS(rv, rv);
  163. RefPtr<nsWifiAccessPoint> ap = new nsWifiAccessPoint();
  164. do {
  165. DBusMessageIter dict;
  166. dbus_message_iter_recurse(&arr, &dict);
  167. do {
  168. const char* key;
  169. dbus_message_iter_get_basic(&dict, &key);
  170. if (!key) {
  171. return NS_ERROR_FAILURE;
  172. }
  173. dbus_message_iter_next(&dict);
  174. DBusMessageIter variant;
  175. dbus_message_iter_recurse(&dict, &variant);
  176. if (!strncmp(key, "Ssid", strlen("Ssid"))) {
  177. nsresult rv = StoreSsid(&variant, ap);
  178. NS_ENSURE_SUCCESS(rv, rv);
  179. break;
  180. }
  181. if (!strncmp(key, "HwAddress", strlen("HwAddress"))) {
  182. nsresult rv = SetMac(&variant, ap);
  183. NS_ENSURE_SUCCESS(rv, rv);
  184. break;
  185. }
  186. if (!strncmp(key, "Strength", strlen("Strength"))) {
  187. if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_BYTE) {
  188. return NS_ERROR_FAILURE;
  189. }
  190. uint8_t strength;
  191. dbus_message_iter_get_basic(&variant, &strength);
  192. ap->setSignal(strength);
  193. }
  194. } while (dbus_message_iter_next(&dict));
  195. } while (dbus_message_iter_next(&arr));
  196. mAccessPoints->AppendObject(ap);
  197. return NS_OK;
  198. }
  199. nsresult
  200. nsWifiScannerDBus::StoreSsid(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp)
  201. {
  202. if (dbus_message_iter_get_arg_type(aVariant) != DBUS_TYPE_ARRAY) {
  203. return NS_ERROR_FAILURE;
  204. }
  205. DBusMessageIter variantMember;
  206. dbus_message_iter_recurse(aVariant, &variantMember);
  207. const uint32_t MAX_SSID_LEN = 32;
  208. char ssid[MAX_SSID_LEN];
  209. memset(ssid, '\0', ArrayLength(ssid));
  210. uint32_t i = 0;
  211. do {
  212. if (dbus_message_iter_get_arg_type(&variantMember) != DBUS_TYPE_BYTE) {
  213. return NS_ERROR_FAILURE;
  214. }
  215. dbus_message_iter_get_basic(&variantMember, &ssid[i]);
  216. i++;
  217. } while (dbus_message_iter_next(&variantMember) && i < MAX_SSID_LEN);
  218. aAp->setSSID(ssid, i);
  219. return NS_OK;
  220. }
  221. nsresult
  222. nsWifiScannerDBus::SetMac(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp)
  223. {
  224. if (dbus_message_iter_get_arg_type(aVariant) != DBUS_TYPE_STRING) {
  225. return NS_ERROR_FAILURE;
  226. }
  227. // hwAddress format is XX:XX:XX:XX:XX:XX. Need to convert to XXXXXX format.
  228. char* hwAddress;
  229. dbus_message_iter_get_basic(aVariant, &hwAddress);
  230. if (!hwAddress) {
  231. return NS_ERROR_FAILURE;
  232. }
  233. const uint32_t MAC_LEN = 6;
  234. uint8_t macAddress[MAC_LEN];
  235. char* token = strtok(hwAddress, ":");
  236. for (uint32_t i = 0; i < ArrayLength(macAddress); i++) {
  237. if (!token) {
  238. return NS_ERROR_FAILURE;
  239. }
  240. macAddress[i] = strtoul(token, nullptr, 16);
  241. token = strtok(nullptr, ":");
  242. }
  243. aAp->setMac(macAddress);
  244. return NS_OK;
  245. }
  246. nsresult
  247. nsWifiScannerDBus::GetDBusIterator(DBusMessage* aMsg,
  248. DBusMessageIter* aIterArray)
  249. {
  250. DBusMessageIter iter;
  251. if (!dbus_message_iter_init(aMsg, &iter)) {
  252. return NS_ERROR_FAILURE;
  253. }
  254. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
  255. return NS_ERROR_FAILURE;
  256. }
  257. dbus_message_iter_recurse(&iter, aIterArray);
  258. return NS_OK;
  259. }
  260. } // mozilla
  261. nsresult
  262. nsWifiMonitor::DoScan()
  263. {
  264. nsCOMArray<nsWifiAccessPoint> accessPoints;
  265. mozilla::nsWifiScannerDBus wifiScanner(&accessPoints);
  266. nsCOMArray<nsWifiAccessPoint> lastAccessPoints;
  267. while (mKeepGoing) {
  268. accessPoints.Clear();
  269. nsresult rv = wifiScanner.Scan();
  270. NS_ENSURE_SUCCESS(rv, rv);
  271. bool accessPointsChanged = !AccessPointsEqual(accessPoints,
  272. lastAccessPoints);
  273. ReplaceArray(lastAccessPoints, accessPoints);
  274. rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
  275. NS_ENSURE_SUCCESS(rv, rv);
  276. LOG(("waiting on monitor\n"));
  277. mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
  278. mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval));
  279. }
  280. return NS_OK;
  281. }