static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg, void *data) { struct vpn_provider *provider = data; DBusMessageIter iter, value; const char *name; int type; DBG("conn %p", conn); if (dbus_message_iter_init(msg, &iter) == FALSE) return __connman_error_invalid_arguments(msg); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) return __connman_error_invalid_arguments(msg); dbus_message_iter_get_basic(&iter, &name); dbus_message_iter_next(&iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) return __connman_error_invalid_arguments(msg); dbus_message_iter_recurse(&iter, &value); type = dbus_message_iter_get_arg_type(&value); if (g_str_equal(name, "UserRoutes") == TRUE) { GSList *networks; if (type != DBUS_TYPE_ARRAY) return __connman_error_invalid_arguments(msg); networks = get_user_networks(&value); if (networks != NULL) { del_routes(provider); provider->user_networks = networks; set_user_networks(provider, provider->user_networks); if (handle_routes == FALSE) provider_schedule_changed(provider, USER_ROUTES_CHANGED); } } else return __connman_error_invalid_property(msg); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); }
static int create_configuration(DBusMessage *msg, connection_ready_cb callback) { DBusMessage *new_msg = NULL; DBusPendingCall *call; DBusMessageIter iter, array, new_iter, new_dict; const char *type = NULL, *name = NULL; const char *host = NULL, *domain = NULL; char *ident, *me = NULL; int err = 0; dbus_bool_t result; struct connection_data *data; struct config_create_data *user_data = NULL; GSList *networks = NULL; /* * We copy the old message data into new message. We cannot * just use the old message as is because the user route * information is not in the same format in vpnd. */ new_msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL); dbus_message_iter_init_append(new_msg, &new_iter); connman_dbus_dict_open(&new_iter, &new_dict); dbus_message_iter_init(msg, &iter); dbus_message_iter_recurse(&iter, &array); while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) { DBusMessageIter entry, value; void *item_value; const char *key; int value_type; dbus_message_iter_recurse(&array, &entry); dbus_message_iter_get_basic(&entry, &key); dbus_message_iter_next(&entry); dbus_message_iter_recurse(&entry, &value); value_type = dbus_message_iter_get_arg_type(&value); item_value = NULL; switch (value_type) { case DBUS_TYPE_STRING: dbus_message_iter_get_basic(&value, &item_value); if (g_str_equal(key, "Type") == TRUE) { type = (const char *)item_value; } else if (g_str_equal(key, "Name") == TRUE) { name = (const char *)item_value; } else if (g_str_equal(key, "Host") == TRUE) { host = (const char *)item_value; } else if (g_str_equal(key, "VPN.Domain") == TRUE) { domain = (const char *)item_value; } DBG("%s %s", key, (char *)item_value); if (item_value != NULL) connman_dbus_dict_append_basic(&new_dict, key, value_type, &item_value); break; case DBUS_TYPE_ARRAY: if (g_str_equal(key, "Networks") == TRUE) { networks = get_user_networks(&value); connman_dbus_dict_append_array(&new_dict, "UserRoutes", DBUS_TYPE_DICT_ENTRY, append_routes, networks); } break; } dbus_message_iter_next(&array); } connman_dbus_dict_close(&new_iter, &new_dict); DBG("VPN type %s name %s host %s domain %s networks %p", type, name, host, domain, networks); if (host == NULL || domain == NULL) { err = -EINVAL; goto done; } if (type == NULL || name == NULL) { err = -EOPNOTSUPP; goto done; } ident = g_strdup_printf("%s_%s", host, domain); set_dbus_ident(ident); DBG("ident %s", ident); data = g_hash_table_lookup(vpn_connections, ident); if (data != NULL) { if (data->call != NULL || data->cb_data != NULL) { DBG("create configuration call already pending"); err = -EINPROGRESS; goto done; } } else { char *path = g_strdup_printf("%s/connection/%s", VPN_PATH, ident); data = create_connection_data(path); g_free(path); if (data == NULL) { err = -ENOMEM; goto done; } g_hash_table_insert(vpn_connections, g_strdup(ident), data); } /* * User called net.connman.Manager.ConnectProvider if we are here. * So use the data from original message in the new msg. */ me = g_strdup(dbus_message_get_destination(msg)); dbus_message_set_interface(new_msg, VPN_MANAGER_INTERFACE); dbus_message_set_path(new_msg, "/"); dbus_message_set_destination(new_msg, VPN_SERVICE); dbus_message_set_sender(new_msg, me); dbus_message_set_member(new_msg, "Create"); user_data = g_try_new0(struct config_create_data, 1); if (user_data == NULL) { err = -ENOMEM; goto done; } user_data->callback = callback; user_data->message = dbus_message_ref(msg); user_data->path = NULL; DBG("cb %p msg %p", user_data, msg); result = dbus_connection_send_with_reply(connection, new_msg, &call, DBUS_TIMEOUT); if (result == FALSE || call == NULL) { err = -EIO; goto done; } dbus_pending_call_set_notify(call, configuration_create_reply, user_data, NULL); data->call = call; done: if (new_msg != NULL) dbus_message_unref(new_msg); if (networks != NULL) g_slist_free_full(networks, destroy_route); g_free(me); return err; }