/** * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal * @wpa_s: %wpa_supplicant network interface data * Returns: 0 on success, -1 on failure * * Notify listeners that this interface has updated scan results. */ void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) { struct ctrl_iface_dbus_priv *iface = wpa_s->global->dbus_ctrl_iface; DBusMessage *_signal; const char *path; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; path = wpa_supplicant_get_dbus_path(wpa_s); if (path == NULL) { perror("wpa_supplicant_dbus_notify_scan_results[dbus]: " "interface didn't have a dbus path"); wpa_printf(MSG_ERROR, "wpa_supplicant_dbus_notify_scan_results[dbus]: " "interface didn't have a dbus path; can't send " "scan result signal."); return; } _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE, "ScanResultsAvailable"); if (_signal == NULL) { perror("wpa_supplicant_dbus_notify_scan_results[dbus]: " "couldn't create dbus signal; likely out of memory"); wpa_printf(MSG_ERROR, "dbus control interface: not enough " "memory to send scan results signal."); return; } dbus_connection_send(iface->con, _signal, NULL); dbus_message_unref(_signal); }
/** * wpas_dbus_iface_scan_results - Get the results of a recent scan request * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: a dbus message containing a dbus array of objects paths, or returns * a dbus error message if not scan results could be found * * Handler function for "scanResults" method call of a network device. Returns * a dbus message containing the object paths of wireless networks found. */ DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; DBusMessageIter iter; DBusMessageIter sub_iter; size_t i; /* Ensure we've actually got scan results to return */ if (wpa_s->scan_res == NULL && wpa_supplicant_get_scan_results(wpa_s) < 0) { reply = dbus_message_new_error(message, WPAS_ERROR_SCAN_ERROR, "An error ocurred getting scan " "results."); goto out; } /* Create and initialize the return message */ reply = dbus_message_new_method_return(message); dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH_AS_STRING, &sub_iter); /* Loop through scan results and append each result's object path */ for (i = 0; i < wpa_s->scan_res->num; i++) { struct wpa_scan_res *res = wpa_s->scan_res->res[i]; char *path; path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); if (path == NULL) { perror("wpas_dbus_iface_scan_results[dbus]: out of " "memory."); wpa_printf(MSG_ERROR, "dbus control interface: not " "enough memory to send scan results " "signal."); break; } /* Construct the object path for this network. Note that ':' * is not a valid character in dbus object paths. */ snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_BSSIDS_PART "/" WPAS_DBUS_BSSID_FORMAT, wpa_supplicant_get_dbus_path(wpa_s), MAC2STR(res->bssid)); dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_OBJECT_PATH, &path); free(path); } dbus_message_iter_close_container(&iter, &sub_iter); out: return reply; }
/** * wpas_dbus_iface_remove_network - Remove a configured network * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A dbus message containing a UINT32 indicating success (1) or * failure (0) * * Handler function for "removeNetwork" method call of a network interface. */ DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; const char *op; char *iface = NULL, *net_id = NULL; int id; struct wpa_ssid *ssid; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, DBUS_TYPE_INVALID)) { reply = wpas_dbus_new_invalid_opts_error(message, NULL); goto out; } /* Extract the network ID */ iface = wpas_dbus_decompose_object_path(op, &net_id, NULL); if (iface == NULL) { reply = wpas_dbus_new_invalid_network_error(message); goto out; } /* Ensure the network is actually a child of this interface */ if (strcmp(iface, wpa_supplicant_get_dbus_path(wpa_s)) != 0) { reply = wpas_dbus_new_invalid_network_error(message); goto out; } id = strtoul(net_id, NULL, 10); ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { reply = wpas_dbus_new_invalid_network_error(message); goto out; } if (wpa_config_remove_network(wpa_s->conf, id) < 0) { reply = dbus_message_new_error(message, WPAS_ERROR_REMOVE_NETWORK_ERROR, "error removing the specified " "on this interface."); goto out; } if (ssid == wpa_s->current_ssid) wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); reply = wpas_dbus_new_success_reply(message); out: free(iface); free(net_id); return reply; }
/** * wpas_dbus_iface_add_network - Add a new configured network * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A dbus message containing the object path of the new network * * Handler function for "addNetwork" method call of a network interface. */ DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; struct wpa_ssid *ssid; char *path = NULL; path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); if (path == NULL) { perror("wpas_dbus_iface_scan_results[dbus]: out of " "memory."); wpa_printf(MSG_ERROR, "dbus control interface: not " "enough memory to send scan results " "signal."); goto out; } ssid = wpa_config_add_network(wpa_s->conf); if (ssid == NULL) { reply = dbus_message_new_error(message, WPAS_ERROR_ADD_NETWORK_ERROR, "wpa_supplicant could not add " "a network on this interface."); goto out; } ssid->disabled = 1; wpa_config_set_network_defaults(ssid); /* Construct the object path for this network. */ snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NETWORKS_PART "/%d", wpa_supplicant_get_dbus_path(wpa_s), ssid->id); reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); out: free(path); return reply; }
/** * wpas_dbus_unregister_iface - Unregister an interface from dbus * @wpa_s: wpa_supplicant interface structure * Returns: 0 on success, -1 on failure * * Unregisters the interface with dbus */ int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) { struct ctrl_iface_dbus_priv *ctrl_iface = wpa_s->global->dbus_ctrl_iface; DBusConnection *con; const char *path; /* Do nothing if the control interface is not turned on */ if (ctrl_iface == NULL) return 0; con = ctrl_iface->con; path = wpa_supplicant_get_dbus_path(wpa_s); if (!dbus_connection_unregister_object_path(con, path)) return -1; free(wpa_s->dbus_path); wpa_s->dbus_path = NULL; return 0; }
/** * wpas_dbus_global_get_interface - Get the object path for an interface name * @message: Pointer to incoming dbus message * @global: %wpa_supplicant global data structure * Returns: The object path of the interface object, * or a dbus error message with more information * * Handler function for "getInterface" method call. Handles requests * by dbus clients for the object path of an specific network interface. */ DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message, struct wpa_global *global) { DBusMessage *reply = NULL; const char *ifname; const char *path; struct wpa_supplicant *wpa_s; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname, DBUS_TYPE_INVALID)) { reply = wpas_dbus_new_invalid_opts_error(message, NULL); goto out; } wpa_s = wpa_supplicant_get_iface(global, ifname); if (wpa_s == NULL) { reply = wpas_dbus_new_invalid_iface_error(message); goto out; } path = wpa_supplicant_get_dbus_path(wpa_s); if (path == NULL) { reply = dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR, "an internal error occurred " "getting the interface."); goto out; } reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); out: return reply; }
/** * wpa_supplicant_dbus_notify_state_change - Send a state change signal * @wpa_s: %wpa_supplicant network interface data * @new_state: new state wpa_supplicant is entering * @old_state: old state wpa_supplicant is leaving * Returns: 0 on success, -1 on failure * * Notify listeners that wpa_supplicant has changed state */ void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, wpa_states new_state, wpa_states old_state) { struct ctrl_iface_dbus_priv *iface; DBusMessage *_signal = NULL; const char *path; const char *new_state_str, *old_state_str; /* Do nothing if the control interface is not turned on */ if (wpa_s->global == NULL) return; iface = wpa_s->global->dbus_ctrl_iface; if (iface == NULL) return; /* Only send signal if state really changed */ if (new_state == old_state) return; path = wpa_supplicant_get_dbus_path(wpa_s); if (path == NULL) { perror("wpa_supplicant_dbus_notify_state_change[dbus]: " "interface didn't have a dbus path"); wpa_printf(MSG_ERROR, "wpa_supplicant_dbus_notify_state_change[dbus]: " "interface didn't have a dbus path; can't send " "signal."); return; } _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE, "StateChange"); if (_signal == NULL) { perror("wpa_supplicant_dbus_notify_state_change[dbus]: " "couldn't create dbus signal; likely out of memory"); wpa_printf(MSG_ERROR, "wpa_supplicant_dbus_notify_state_change[dbus]: " "couldn't create dbus signal; likely out of " "memory."); return; } new_state_str = wpa_supplicant_state_txt(new_state); old_state_str = wpa_supplicant_state_txt(old_state); if (new_state_str == NULL || old_state_str == NULL) { perror("wpa_supplicant_dbus_notify_state_change[dbus]: " "couldn't convert state strings"); wpa_printf(MSG_ERROR, "wpa_supplicant_dbus_notify_state_change[dbus]: " "couldn't convert state strings."); goto out; } if (!dbus_message_append_args(_signal, DBUS_TYPE_STRING, &new_state_str, DBUS_TYPE_STRING, &old_state_str, DBUS_TYPE_INVALID)) { perror("wpa_supplicant_dbus_notify_state_change[dbus]: " "not enough memory to construct state change signal."); wpa_printf(MSG_ERROR, "wpa_supplicant_dbus_notify_state_change[dbus]: " "not enough memory to construct state change " "signal."); goto out; } dbus_connection_send(iface->con, _signal, NULL); out: dbus_message_unref(_signal); }
/** * wpas_dbus_global_add_interface - Request registration of a network interface * @message: Pointer to incoming dbus message * @global: %wpa_supplicant global data structure * Returns: The object path of the new interface object, * or a dbus error message with more information * * Handler function for "addInterface" method call. Handles requests * by dbus clients to register a network interface that wpa_supplicant * will manage. */ DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message, struct wpa_global *global) { struct wpa_interface iface; char *ifname = NULL; DBusMessage *reply = NULL; DBusMessageIter iter; memset(&iface, 0, sizeof(iface)); dbus_message_iter_init(message, &iter); /* First argument: interface name (DBUS_TYPE_STRING) * Required; must be non-zero length */ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) goto error; dbus_message_iter_get_basic(&iter, &ifname); if (!strlen(ifname)) goto error; iface.ifname = ifname; /* Second argument: dict of options */ if (dbus_message_iter_next(&iter)) { DBusMessageIter iter_dict; struct wpa_dbus_dict_entry entry; if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) goto error; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; if (!strcmp(entry.key, "driver") && (entry.type == DBUS_TYPE_STRING)) { iface.driver = strdup(entry.str_value); if (iface.driver == NULL) goto error; } else if (!strcmp(entry.key, "driver-params") && (entry.type == DBUS_TYPE_STRING)) { iface.driver_param = strdup(entry.str_value); if (iface.driver_param == NULL) goto error; } else if (!strcmp(entry.key, "config-file") && (entry.type == DBUS_TYPE_STRING)) { iface.confname = strdup(entry.str_value); if (iface.confname == NULL) goto error; } else if (!strcmp(entry.key, "bridge-ifname") && (entry.type == DBUS_TYPE_STRING)) { iface.bridge_ifname = strdup(entry.str_value); if (iface.bridge_ifname == NULL) goto error; } else { wpa_dbus_dict_entry_clear(&entry); goto error; } wpa_dbus_dict_entry_clear(&entry); } } /* * Try to get the wpa_supplicant record for this iface, return * an error if we already control it. */ if (wpa_supplicant_get_iface(global, iface.ifname) != NULL) { reply = dbus_message_new_error(message, WPAS_ERROR_EXISTS_ERROR, "wpa_supplicant already " "controls this interface."); } else { struct wpa_supplicant *wpa_s; /* Otherwise, have wpa_supplicant attach to it. */ if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) { const char *path = wpa_supplicant_get_dbus_path(wpa_s); reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); } else { reply = dbus_message_new_error(message, WPAS_ERROR_ADD_ERROR, "wpa_supplicant " "couldn't grab this " "interface."); } } wpas_dbus_free_wpa_interface(&iface); return reply; error: wpas_dbus_free_wpa_interface(&iface); return wpas_dbus_new_invalid_opts_error(message, NULL); }
/** * wpas_dbus_iface_select_network - Attempt association with a configured network * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A dbus message containing a UINT32 indicating success (1) or * failure (0) * * Handler function for "selectNetwork" method call of network interface. */ DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; const char *op; struct wpa_ssid *ssid; char *iface_obj_path = NULL; char *network = NULL; if (strlen(dbus_message_get_signature(message)) == 0) { /* Any network */ ssid = wpa_s->conf->ssid; while (ssid) { ssid->disabled = 0; ssid = ssid->next; } wpa_s->reassociate = 1; wpa_supplicant_req_scan(wpa_s, 0, 0); } else { const char *obj_path; int nid; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, DBUS_TYPE_INVALID)) { reply = wpas_dbus_new_invalid_opts_error(message, NULL); goto out; } /* Extract the network number */ iface_obj_path = wpas_dbus_decompose_object_path(op, &network, NULL); if (iface_obj_path == NULL) { reply = wpas_dbus_new_invalid_iface_error(message); goto out; } /* Ensure the object path really points to this interface */ obj_path = wpa_supplicant_get_dbus_path(wpa_s); if (strcmp(iface_obj_path, obj_path) != 0) { reply = wpas_dbus_new_invalid_network_error(message); goto out; } nid = strtoul(network, NULL, 10); if (errno == EINVAL) { reply = wpas_dbus_new_invalid_network_error(message); goto out; } ssid = wpa_config_get_network(wpa_s->conf, nid); if (ssid == NULL) { reply = wpas_dbus_new_invalid_network_error(message); goto out; } /* Finally, associate with the network */ if (ssid != wpa_s->current_ssid && wpa_s->current_ssid) wpa_supplicant_disassociate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); /* Mark all other networks disabled and trigger reassociation */ ssid = wpa_s->conf->ssid; while (ssid) { ssid->disabled = (nid != ssid->id); ssid = ssid->next; } wpa_s->disconnected = 0; wpa_s->reassociate = 1; wpa_supplicant_req_scan(wpa_s, 0, 0); } reply = wpas_dbus_new_success_reply(message); out: free(iface_obj_path); free(network); return reply; }