3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-10-04 02:18:49 +02:00
iwd/src/main.c
James Prestwood bbcfde8743 plugins: remove dependency on ELL plugins
There has been a desire to remove the ELL plugin dependency from
IWD which is the only consumer of the plugin API. This removes
the dependency and prepares the tree for converting the existing
ofono plugin into a regular module.

sim_hardcoded was removed completely. This was originall implemented
before full ofono support purely to test the IWD side of EAP-SIM/AKA.
Since the ofono plugin (module-to-be) is now fully implemented there
really isn't a need for sim_hardcoded.
2020-09-16 14:30:14 -05:00

512 lines
12 KiB
C

/*
*
* Wireless daemon for Linux
*
* Copyright (C) 2013-2019 Intel Corporation. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <ell/ell.h>
#include "linux/nl80211.h"
#include "src/iwd.h"
#include "src/module.h"
#include "src/wiphy.h"
#include "src/dbus.h"
#include "src/eap.h"
#include "src/eapol.h"
#include "src/rfkill.h"
#include "src/storage.h"
#include "src/anqp.h"
#include "src/backtrace.h"
static struct l_genl *genl;
static struct l_netlink *rtnl;
static struct l_settings *iwd_config;
static struct l_timeout *timeout;
static const char *interfaces;
static const char *nointerfaces;
static const char *phys;
static const char *nophys;
static const char *debugopt;
static bool terminating;
static bool nl80211_complete;
static void main_loop_quit(struct l_timeout *timeout, void *user_data)
{
l_main_quit();
}
static void iwd_shutdown(void)
{
if (terminating)
return;
terminating = true;
if (!nl80211_complete) {
l_main_quit();
return;
}
dbus_shutdown();
netdev_shutdown();
timeout = l_timeout_create(1, main_loop_quit, NULL, NULL);
}
static void signal_handler(uint32_t signo, void *user_data)
{
switch (signo) {
case SIGINT:
case SIGTERM:
l_info("Terminate");
iwd_shutdown();
break;
}
}
const struct l_settings *iwd_get_config(void)
{
return iwd_config;
}
struct l_genl *iwd_get_genl(void)
{
return genl;
}
struct l_netlink *iwd_get_rtnl(void)
{
return rtnl;
}
const char *iwd_get_iface_whitelist(void)
{
return interfaces;
}
const char *iwd_get_iface_blacklist(void)
{
return nointerfaces;
}
const char *iwd_get_phy_whitelist(void)
{
return phys;
}
const char *iwd_get_phy_blacklist(void)
{
return nophys;
}
static void usage(void)
{
printf("iwd - Wireless daemon\n"
"Usage:\n");
printf("\tiwd [options]\n");
printf("Options:\n"
"\t-B, --dbus-debug Enable D-Bus debugging\n"
"\t-i, --interfaces Interfaces to manage\n"
"\t-I, --nointerfaces Interfaces to ignore\n"
"\t-p, --phys Phys to manage\n"
"\t-P, --nophys Phys to ignore\n"
"\t-d, --debug Enable debug output\n"
"\t-v, --version Show version\n"
"\t-h, --help Show help options\n");
}
static const struct option main_options[] = {
{ "dbus-debug", no_argument, NULL, 'B' },
{ "version", no_argument, NULL, 'v' },
{ "interfaces", required_argument, NULL, 'i' },
{ "nointerfaces", required_argument, NULL, 'I' },
{ "phys", required_argument, NULL, 'p' },
{ "nophys", required_argument, NULL, 'P' },
{ "debug", optional_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ }
};
static void do_debug(const char *str, void *user_data)
{
const char *prefix = user_data;
l_info("%s%s", prefix, str);
}
static void nl80211_appeared(const struct l_genl_family_info *info,
void *user_data)
{
l_debug("Found nl80211 interface");
nl80211_complete = true;
if (iwd_modules_init() < 0) {
l_main_quit();
return;
}
}
static void request_name_callback(struct l_dbus *dbus, bool success,
bool queued, void *user_data)
{
if (!success) {
l_error("Name request failed");
goto fail_exit;
}
if (!l_dbus_object_manager_enable(dbus, "/"))
l_warn("Unable to register the ObjectManager");
/* TODO: Always request nl80211 for now, ignoring auto-loading */
l_genl_request_family(genl, NL80211_GENL_NAME, nl80211_appeared,
NULL, NULL);
return;
fail_exit:
l_main_quit();
}
static void dbus_ready(void *user_data)
{
struct l_dbus *dbus = user_data;
l_dbus_name_acquire(dbus, "net.connman.iwd", false, false, false,
request_name_callback, NULL);
}
static void dbus_disconnected(void *user_data)
{
l_info("D-Bus disconnected, quitting...");
iwd_shutdown();
}
static void print_koption(const void *key, void *value, void *user_data)
{
l_info("\t%s", (const char *) key);
}
#define ADD_MISSING(opt) \
l_hashmap_replace(options, opt, &r, NULL)
#define ADD_OPTIONAL(opt) \
l_hashmap_replace(optional, opt, &r, NULL)
static int check_crypto()
{
int r = 0;
struct l_hashmap *options = l_hashmap_string_new();
struct l_hashmap *optional = l_hashmap_string_new();
if (!l_checksum_is_supported(L_CHECKSUM_SHA1, true)) {
r = -ENOTSUP;
l_error("No HMAC(SHA1) support found");
ADD_MISSING("CONFIG_CRYPTO_USER_API_HASH");
ADD_MISSING("CONFIG_CRYPTO_SHA1");
ADD_MISSING("CONFIG_CRYPTO_HMAC");
ADD_OPTIONAL("CONFIG_CRYPTO_SHA1_SSSE3");
}
if (!l_checksum_is_supported(L_CHECKSUM_MD5, true)) {
r = -ENOTSUP;
l_error("No HMAC(MD5) support found");
ADD_MISSING("CONFIG_CRYPTO_USER_API_HASH");
ADD_MISSING("CONFIG_CRYPTO_MD5");
ADD_MISSING("CONFIG_CRYPTO_HMAC");
}
if (!l_checksum_cmac_aes_supported()) {
r = -ENOTSUP;
l_error("No CMAC(AES) support found");
ADD_MISSING("CONFIG_CRYPTO_USER_API_HASH");
ADD_MISSING("CONFIG_CRYPTO_AES");
ADD_MISSING("CONFIG_CRYPTO_CMAC");
ADD_OPTIONAL("CONFIG_CRYPTO_AES_X86_64");
ADD_OPTIONAL("CONFIG_CRYPTO_AES_NI_INTEL");
}
if (!l_checksum_is_supported(L_CHECKSUM_SHA256, true)) {
r = -ENOTSUP;
l_error("No HMAC(SHA256) support not found");
ADD_MISSING("CONFIG_CRYPTO_USER_API_HASH");
ADD_MISSING("CONFIG_CRYPTO_HMAC");
ADD_MISSING("CONFIG_CRYPTO_SHA256");
ADD_OPTIONAL("CONFIG_CRYPTO_SHA256_SSSE3");
}
if (!l_checksum_is_supported(L_CHECKSUM_SHA512, true)) {
l_warn("No HMAC(SHA512) support found, "
"certain TLS connections might fail");
ADD_MISSING("CONFIG_CRYPTO_SHA512");
ADD_OPTIONAL("CONFIG_CRYPTO_SHA512_SSSE3");
}
if (!l_cipher_is_supported(L_CIPHER_DES) ||
!l_cipher_is_supported(L_CIPHER_DES3_EDE_CBC)) {
r = -ENOTSUP;
l_error("DES support not found");
ADD_MISSING("CONFIG_CRYPTO_USER_API_SKCIPHER");
ADD_MISSING("CONFIG_CRYPTO_DES");
ADD_MISSING("CONFIG_CRYPTO_ECB");
ADD_OPTIONAL("CONFIG_CRYPTO_DES3_EDE_X86_64");
}
if (!l_cipher_is_supported(L_CIPHER_AES)) {
r = -ENOTSUP;
l_error("AES support not found");
ADD_MISSING("CONFIG_CRYPTO_USER_API_SKCIPHER");
ADD_MISSING("CONFIG_CRYPTO_AES");
ADD_MISSING("CONFIG_CRYPTO_ECB");
ADD_OPTIONAL("CONFIG_CRYPTO_AES_X86_64");
ADD_OPTIONAL("CONFIG_CRYPTO_AES_NI_INTEL");
}
if (!l_cipher_is_supported(L_CIPHER_DES3_EDE_CBC)) {
l_warn("No CBC(DES3_EDE) support found, "
"certain TLS connections might fail");
ADD_MISSING("CONFIG_CRYPTO_DES");
ADD_MISSING("CONFIG_CRYPTO_CBC");
ADD_OPTIONAL("CONFIG_CRYPTO_DES3_EDE_X86_64");
}
if (!l_cipher_is_supported(L_CIPHER_AES_CBC)) {
l_warn("No CBC(AES) support found, "
"WPS will not be available");
ADD_MISSING("CONFIG_CRYPTO_CBC");
}
if (!l_key_is_supported(L_KEY_FEATURE_DH)) {
l_warn("No Diffie-Hellman support found, "
"WPS will not be available");
ADD_MISSING("CONFIG_KEY_DH_OPERATIONS");
}
if (!l_key_is_supported(L_KEY_FEATURE_RESTRICT)) {
l_warn("No keyring restrictions support found.");
ADD_MISSING("CONFIG_KEYS");
}
if (!l_key_is_supported(L_KEY_FEATURE_CRYPTO)) {
l_warn("No asymmetric key support found.");
l_warn("TLS based WPA-Enterprise authentication methods will"
" not function.");
l_warn("Kernel 4.20+ is required for this feature.");
ADD_MISSING("CONFIG_ASYMMETRIC_KEY_TYPE");
ADD_MISSING("CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE");
ADD_MISSING("CONFIG_X509_CERTIFICATE_PARSER");
ADD_MISSING("CONFIG_PKCS7_MESSAGE_PARSER");
ADD_MISSING("CONFIG_PKCS8_PRIVATE_KEY_PARSER");
}
if (l_hashmap_isempty(options))
goto done;
l_info("The following options are missing in the kernel:");
if (l_hashmap_remove(options, "CONFIG_CRYPTO_USER_API_HASH"))
l_info("\tCONFIG_CRYPTO_USER_API_HASH");
if (l_hashmap_remove(options, "CONFIG_CRYPTO_USER_API_SKCIPHER"))
l_info("\tCONFIG_CRYPTO_USER_API_SKCIPHER");
l_hashmap_foreach(options, print_koption, NULL);
if (!l_hashmap_isempty(optional)) {
l_info("The following optimized implementations might be "
"available:");
l_hashmap_foreach(optional, print_koption, NULL);
}
done:
l_hashmap_destroy(options, NULL);
l_hashmap_destroy(optional, NULL);
return r;
}
int main(int argc, char *argv[])
{
bool enable_dbus_debug = false;
int exit_status;
struct l_dbus *dbus;
const char *config_dir;
char **config_dirs;
int i;
for (;;) {
int opt;
opt = getopt_long(argc, argv, "Bi:I:p:P:d::vh",
main_options, NULL);
if (opt < 0)
break;
switch (opt) {
case 'B':
enable_dbus_debug = true;
break;
case 'i':
interfaces = optarg;
break;
case 'I':
nointerfaces = optarg;
break;
case 'p':
phys = optarg;
break;
case 'P':
nophys = optarg;
break;
case 'd':
if (optarg)
debugopt = optarg;
else if (argv[optind] && argv[optind][0] != '-')
debugopt = argv[optind++];
else
debugopt = "*";
break;
case 'v':
printf("%s\n", VERSION);
return EXIT_SUCCESS;
case 'h':
usage();
return EXIT_SUCCESS;
default:
return EXIT_FAILURE;
}
}
if (argc - optind > 0) {
fprintf(stderr, "Invalid command line parameters\n");
return EXIT_FAILURE;
}
l_log_set_stderr();
if (check_crypto() < 0)
return EXIT_FAILURE;
if (!l_main_init())
return EXIT_FAILURE;
if (debugopt)
l_debug_enable(debugopt);
#ifdef HAVE_BACKTRACE
__iwd_backtrace_init();
#endif
l_info("Wireless daemon version %s", VERSION);
config_dir = getenv("CONFIGURATION_DIRECTORY");
if (!config_dir)
config_dir = DAEMON_CONFIGDIR;
l_debug("Using configuration directory %s", config_dir);
iwd_config = l_settings_new();
config_dirs = l_strsplit(config_dir, ':');
for (i = 0; config_dirs[i]; i++) {
L_AUTO_FREE_VAR(char *, path) =
l_strdup_printf("%s/%s", config_dirs[i], "main.conf");
if (!l_settings_load_from_file(iwd_config, path))
continue;
l_info("Loaded configuration from %s", path);
break;
}
l_strv_free(config_dirs);
__eapol_set_config(iwd_config);
__eap_set_config(iwd_config);
exit_status = EXIT_FAILURE;
if (!storage_create_dirs())
goto failed_dirs;
genl = l_genl_new();
if (!genl) {
l_error("Failed to open generic netlink socket");
goto failed_genl;
}
if (getenv("IWD_GENL_DEBUG"))
l_genl_set_debug(genl, do_debug, "[GENL] ", NULL);
rtnl = l_netlink_new(NETLINK_ROUTE);
if (!rtnl) {
l_error("Failed to open route netlink socket");
goto failed_rtnl;
}
if (getenv("IWD_RTNL_DEBUG"))
l_netlink_set_debug(rtnl, do_debug, "[RTNL] ", NULL);
dbus = l_dbus_new_default(L_DBUS_SYSTEM_BUS);
if (!dbus) {
l_error("Failed to initialize D-Bus");
goto failed_dbus;
}
if (enable_dbus_debug)
l_dbus_set_debug(dbus, do_debug, "[DBUS] ", NULL);
l_dbus_set_ready_handler(dbus, dbus_ready, dbus, NULL);
l_dbus_set_disconnect_handler(dbus, dbus_disconnected, NULL, NULL);
dbus_init(dbus);
exit_status = l_main_run_with_signal(signal_handler, NULL);
iwd_modules_exit();
dbus_exit();
l_dbus_destroy(dbus);
failed_dbus:
l_netlink_destroy(rtnl);
failed_rtnl:
l_genl_unref(genl);
failed_genl:
storage_cleanup_dirs();
failed_dirs:
l_settings_free(iwd_config);
l_timeout_remove(timeout);
l_main_exit();
return exit_status;
}