Add the IPv{4,6}Configuration D-Bus interfaces on the station and P2P
objects that expose current netconfig values. Access Point and P2P-GO
are not handled yet.
---
src/dbus.h | 2 +
src/netconfig.c | 651 +++++++++++++++++++++++++++++++++++++++++++-----
src/netconfig.h | 2 +-
src/p2p.c | 4 +-
src/station.c | 8 +-
5 files changed, 604 insertions(+), 63 deletions(-)
diff --git a/src/dbus.h b/src/dbus.h
index 7703b37f..a345f7ac 100644
--- a/src/dbus.h
+++ b/src/dbus.h
@@ -43,6 +43,8 @@
#define IWD_STATION_DIAGNOSTIC_INTERFACE "net.connman.iwd.StationDiagnostic"
#define IWD_AP_DIAGNOSTIC_INTERFACE "net.connman.iwd.AccessPointDiagnostic"
#define IWD_STATION_DEBUG_INTERFACE "net.connman.iwd.StationDebug"
+#define IWD_IPV4_CONFIG_INTERFACE "net.connman.iwd.IPv4Configuration"
+#define IWD_IPV6_CONFIG_INTERFACE "net.connman.iwd.IPv6Configuration"
#define IWD_BASE_PATH "/net/connman/iwd"
#define IWD_AGENT_MANAGER_PATH IWD_BASE_PATH
diff --git a/src/netconfig.c b/src/netconfig.c
index 421270c9..a529fad4 100644
--- a/src/netconfig.c
+++ b/src/netconfig.c
@@ -49,6 +49,7 @@
#include "src/resolve.h"
#include "src/util.h"
#include "src/ie.h"
+#include "src/dbus.h"
#include "src/netconfig.h"
struct netconfig {
@@ -58,14 +59,23 @@ struct netconfig {
uint8_t rtm_protocol;
uint8_t rtm_v6_protocol;
struct l_rtnl_address *v4_address;
+ struct l_rtnl_address *v6_address;
char **dns4_overrides;
char **dns6_overrides;
+ char **dns4_list;
+ char **dns6_list;
struct ie_fils_ip_addr_response_info *fils_override;
+ char *v4_gateway_str;
+ char *v6_gateway_str;
+ char *v4_domain;
+ char **v6_domains;
const struct l_settings *active_settings;
netconfig_notify_func_t notify;
void *user_data;
+ bool v4_configured;
+ bool v6_configured;
struct resolve *resolve;
@@ -74,6 +84,13 @@ struct netconfig {
uint32_t addr4_add_cmd_id;
uint32_t addr6_add_cmd_id;
uint32_t route4_add_gateway_cmd_id;
+ uint32_t route6_add_cmd_id;
+
+ char *dbus_path;
+ struct interface_data {
+ bool is_ipv4;
+ struct netconfig *netconfig;
+ } v4_data, v6_data;
};
static struct l_netlink *rtnl;
@@ -132,6 +149,7 @@ static void netconfig_free(void *data)
l_dhcp_client_destroy(netconfig->dhcp_client);
l_dhcp6_client_destroy(netconfig->dhcp6_client);
+ l_free(netconfig->dbus_path);
l_free(netconfig);
}
@@ -257,6 +275,18 @@ static void netconfig_set_neighbor_entry_cb(int error,
strerror(-error), error);
}
+static bool netconfig_strv_eq(char *const *a, char *const *b)
+{
+ if (l_strv_length((char **) a) != l_strv_length((char **) b))
+ return false;
+
+ for (; a && *a; a++, b++)
+ if (strcmp(*a, *b))
+ return false;
+
+ return true;
+}
+
static int netconfig_set_dns(struct netconfig *netconfig)
{
const uint8_t *fils_dns4_mac = NULL;
@@ -270,23 +300,25 @@ static int netconfig_set_dns(struct netconfig *netconfig)
char **dns_list;
const struct ie_fils_ip_addr_response_info *fils =
netconfig->fils_override;
+ struct l_dbus *dbus = dbus_get_bus();
- if (!dns4_list && !dns6_list)
- return 0;
+ if (dns6_list) {
+ dns_list = l_malloc(sizeof(char *) *
+ (n_entries4 + n_entries6 + 1));
- dns_list = dns4_list;
+ if (dns4_list)
+ memcpy(dns_list, dns4_list,
+ sizeof(char *) * n_entries4);
- if (dns6_list) {
- dns_list = l_realloc(dns_list,
- sizeof(char *) * (n_entries4 + n_entries6 + 1));
memcpy(dns_list + n_entries4, dns6_list,
sizeof(char *) * (n_entries6 + 1));
- /* Contents now belong to dns_list, so no l_strfreev */
- l_free(dns6_list);
- }
+ } else
+ dns_list = dns4_list;
resolve_set_dns(netconfig->resolve, dns_list);
- l_strv_free(dns_list);
+
+ if (dns6_list)
+ l_free(dns_list);
if (fils_dns4_mac && !l_rtnl_neighbor_set_hwaddr(rtnl,
netconfig->ifindex, AF_INET,
@@ -302,6 +334,30 @@ static int netconfig_set_dns(struct netconfig *netconfig)
NULL))
l_debug("l_rtnl_neighbor_set_hwaddr failed");
+ if (netconfig_strv_eq(netconfig->dns4_list, dns4_list))
+ l_strv_free(dns4_list);
+ else {
+ l_strv_free(netconfig->dns4_list);
+ netconfig->dns4_list = dns4_list;
+
+ if (netconfig->dbus_path && netconfig->v4_configured)
+ l_dbus_property_changed(dbus, netconfig->dbus_path,
+ IWD_IPV4_CONFIG_INTERFACE,
+ "DomainNameServers");
+ }
+
+ if (netconfig_strv_eq(netconfig->dns6_list, dns6_list))
+ l_strv_free(dns6_list);
+ else {
+ l_strv_free(netconfig->dns6_list);
+ netconfig->dns6_list = dns6_list;
+
+ if (netconfig->dbus_path && netconfig->v6_configured)
+ l_dbus_property_changed(dbus, netconfig->dbus_path,
+ IWD_IPV6_CONFIG_INTERFACE,
+ "DomainNameServers");
+ }
+
return 0;
}
@@ -328,6 +384,7 @@ static int netconfig_set_domains(struct netconfig *netconfig)
char *v4_domain = NULL;
char **v6_domains = NULL;
char **p;
+ struct l_dbus *dbus = dbus_get_bus();
memset(domains, 0, sizeof(domains));
@@ -358,8 +415,30 @@ static int netconfig_set_domains(struct netconfig *netconfig)
L_ARRAY_SIZE(domains) - 1, *p);
resolve_set_domains(netconfig->resolve, domains);
- l_strv_free(v6_domains);
- l_free(v4_domain);
+
+ if (l_streq0(v4_domain, netconfig->v4_domain))
+ l_free(v4_domain);
+ else {
+ l_free(netconfig->v4_domain);
+ netconfig->v4_domain = v4_domain;
+
+ if (netconfig->dbus_path && netconfig->v4_configured)
+ l_dbus_property_changed(dbus, netconfig->dbus_path,
+ IWD_IPV4_CONFIG_INTERFACE,
+ "DomainNames");
+ }
+
+ if (netconfig_strv_eq(netconfig->v6_domains, v6_domains))
+ l_strv_free(v6_domains);
+ else {
+ l_strv_free(netconfig->v6_domains);
+ netconfig->v6_domains = v6_domains;
+
+ if (netconfig->dbus_path && netconfig->v6_configured)
+ l_dbus_property_changed(dbus, netconfig->dbus_path,
+ IWD_IPV6_CONFIG_INTERFACE,
+ "DomainNames");
+ }
return 0;
}
@@ -417,6 +496,8 @@ static char *netconfig_ipv4_get_gateway(struct netconfig *netconfig,
{
const struct l_dhcp_lease *lease;
char *gateway;
+ const struct ie_fils_ip_addr_response_info *fils =
+ netconfig->fils_override;
switch (netconfig->rtm_protocol) {
case RTPROT_STATIC:
@@ -430,15 +511,12 @@ static char *netconfig_ipv4_get_gateway(struct netconfig
*netconfig,
return gateway;
case RTPROT_DHCP:
- if (netconfig->fils_override &&
- netconfig->fils_override->ipv4_gateway) {
- gateway = netconfig_ipv4_to_string(
- netconfig->fils_override->ipv4_gateway);
+ if (fils && fils->ipv4_gateway) {
+ gateway = netconfig_ipv4_to_string(fils->ipv4_gateway);
- if (gateway && !l_memeqzero(netconfig->fils_override->
- ipv4_gateway_mac, 6))
- *out_mac = netconfig->fils_override->
- ipv4_gateway_mac;
+ if (gateway && out_mac &&
+ !l_memeqzero(fils->ipv4_gateway_mac, 6))
+ *out_mac = fils->ipv4_gateway_mac;
return gateway;
}
@@ -476,7 +554,7 @@ static struct l_rtnl_address *netconfig_get_static6_address(
prefix_len = strtoul(p, NULL, 10);
if (!unlikely(errno == EINVAL || errno == ERANGE ||
!prefix_len || prefix_len > 128)) {
- l_error("netconfig: Invalid prefix '%s' provided in network"
+ l_error("netconfig: Invalid prefix '%s' provided in network"
" configuration file", p);
return NULL;
}
@@ -492,10 +570,12 @@ no_prefix_len:
static struct l_rtnl_route *netconfig_get_static6_gateway(
struct netconfig *netconfig,
+ char **out_str,
const uint8_t **out_mac)
{
L_AUTO_FREE_VAR(char *, gateway);
struct l_rtnl_route *ret;
+ const uint8_t *mac = NULL;
gateway = l_settings_get_string(netconfig->active_settings,
"IPv6", "Gateway");
@@ -507,7 +587,7 @@ static struct l_rtnl_route *netconfig_get_static6_gateway(
netconfig->fils_override->ipv6_gateway);
if (!l_memeqzero(netconfig->fils_override->ipv6_gateway_mac, 6))
- *out_mac = netconfig->fils_override->ipv6_gateway_mac;
+ mac = netconfig->fils_override->ipv6_gateway_mac;
} else if (!gateway)
return NULL;
@@ -521,6 +601,8 @@ static struct l_rtnl_route *netconfig_get_static6_gateway(
l_rtnl_route_set_priority(ret, ROUTE_PRIORITY_OFFSET);
l_rtnl_route_set_protocol(ret, RTPROT_STATIC);
+ *out_str = l_steal_ptr(gateway);
+ *out_mac = mac;
return ret;
}
@@ -623,6 +705,99 @@ static void netconfig_ifaddr_cmd_cb(int error, uint16_t type,
netconfig_ifaddr_notify(type, data, len, user_data);
}
+static void netconfig_connected(struct netconfig *netconfig)
+{
+ if (netconfig->notify) {
+ netconfig->notify(NETCONFIG_EVENT_CONNECTED,
+ netconfig->user_data);
+ netconfig->notify = NULL;
+ }
+}
+
+static void netconfig_connected_v4(struct netconfig *netconfig)
+{
+ struct l_dbus *dbus = dbus_get_bus();
+
+ netconfig_connected(netconfig);
+
+ netconfig->v4_configured = true;
+
+ if (!netconfig->dbus_path)
+ return;
+
+ if (unlikely(!l_dbus_object_add_interface(dbus,
+ netconfig->dbus_path,
+ IWD_IPV4_CONFIG_INTERFACE,
+ &netconfig->v4_data)))
+ l_info("Unable to add %s at %s",
+ IWD_IPV4_CONFIG_INTERFACE, netconfig->dbus_path);
+
+ if (!netconfig->v6_configured &&
+ !l_dbus_object_add_interface(dbus, netconfig->dbus_path,
+ L_DBUS_INTERFACE_PROPERTIES,
+ netconfig))
+ /* Properties may already exist on the object, not an error */
+ l_debug("Unable to add %s at %s",
+ L_DBUS_INTERFACE_PROPERTIES, netconfig->dbus_path);
+}
+
+static void netconfig_disconnected_v4(struct netconfig *netconfig)
+{
+ struct l_dbus *dbus = dbus_get_bus();
+
+ netconfig->v4_configured = false;
+
+ if (!netconfig->dbus_path)
+ return;
+
+ if (unlikely(!l_dbus_object_remove_interface(dbus,
+ netconfig->dbus_path,
+ IWD_IPV4_CONFIG_INTERFACE)))
+ l_info("l_dbus_object_remove_interface failed for %s at %s",
+ IWD_IPV4_CONFIG_INTERFACE, netconfig->dbus_path);
+}
+
+static void netconfig_disconnected_v6(struct netconfig *netconfig)
+{
+ struct l_dbus *dbus = dbus_get_bus();
+
+ netconfig->v6_configured = false;
+
+ if (!netconfig->dbus_path)
+ return;
+
+ if (unlikely(!l_dbus_object_remove_interface(dbus,
+ netconfig->dbus_path,
+ IWD_IPV6_CONFIG_INTERFACE)))
+ l_info("l_dbus_object_remove_interface failed for %s at %s",
+ IWD_IPV6_CONFIG_INTERFACE, netconfig->dbus_path);
+}
+
+static void netconfig_connected_v6(struct netconfig *netconfig)
+{
+ struct l_dbus *dbus = dbus_get_bus();
+
+ netconfig->v6_configured = true;
+
+ if (!netconfig->dbus_path)
+ return;
+
+ if (unlikely(!l_dbus_object_add_interface(dbus,
+ netconfig->dbus_path,
+ IWD_IPV6_CONFIG_INTERFACE,
+ &netconfig->v6_data)))
+ l_info("Unable to add %s at %s",
+ IWD_IPV6_CONFIG_INTERFACE, netconfig->dbus_path);
+
+ if (!netconfig->v4_configured &&
+ !l_dbus_object_add_interface(dbus, netconfig->dbus_path,
+ L_DBUS_INTERFACE_PROPERTIES,
+ netconfig))
+ /* Properties may already exist on the object, not an error */
+ l_debug("Unable to add %s at %s",
+ L_DBUS_INTERFACE_PROPERTIES, netconfig->dbus_path);
+}
+
static void netconfig_ifaddr_ipv6_added(struct netconfig *netconfig,
const struct ifaddrmsg *ifa,
uint32_t len)
@@ -732,11 +907,24 @@ static void netconfig_route_add_cmd_cb(int error, uint16_t type,
return;
}
- if (!netconfig->notify)
+ netconfig_connected_v4(netconfig);
+}
+
+static void netconfig_route6_add_cb(int error, uint16_t type,
+ const void *data, uint32_t len,
+ void *user_data)
+{
+ struct netconfig *netconfig = user_data;
+
+ netconfig->route6_add_cmd_id = 0;
+
+ if (error) {
+ l_error("netconfig: Failed to add route. Error %d: %s",
+ error, strerror(-error));
return;
+ }
- netconfig->notify(NETCONFIG_EVENT_CONNECTED, netconfig->user_data);
- netconfig->notify = NULL;
+ netconfig_connected_v6(netconfig);
}
static bool netconfig_ipv4_routes_install(struct netconfig *netconfig)
@@ -775,12 +963,7 @@ static bool netconfig_ipv4_routes_install(struct netconfig
*netconfig)
netconfig->rtm_protocol == RTPROT_STATIC ?
"setting file" : "DHCPv4 lease");
- if (netconfig->notify) {
- netconfig->notify(NETCONFIG_EVENT_CONNECTED,
- netconfig->user_data);
- netconfig->notify = NULL;
- }
-
+ netconfig_connected_v4(netconfig);
return true;
}
@@ -847,7 +1030,7 @@ static void netconfig_ipv6_ifaddr_add_cmd_cb(int error, uint16_t
type,
{
struct netconfig *netconfig = user_data;
struct l_rtnl_route *gateway;
- const uint8_t *gateway_mac = NULL;
+ const uint8_t *gateway_mac;
netconfig->addr6_add_cmd_id = 0;
@@ -857,12 +1040,16 @@ static void netconfig_ipv6_ifaddr_add_cmd_cb(int error, uint16_t
type,
return;
}
- gateway = netconfig_get_static6_gateway(netconfig, &gateway_mac);
+ gateway = netconfig_get_static6_gateway(netconfig,
+ &netconfig->v6_gateway_str,
+ &gateway_mac);
if (gateway) {
- L_WARN_ON(!l_rtnl_route_add(rtnl, netconfig->ifindex,
- gateway,
- netconfig_route_generic_cb,
- netconfig, NULL));
+ netconfig->route6_add_cmd_id = l_rtnl_route_add(rtnl,
+ netconfig->ifindex,
+ gateway,
+ netconfig_route6_add_cb,
+ netconfig, NULL);
+ L_WARN_ON(unlikely(!netconfig->route6_add_cmd_id));
l_rtnl_route_free(gateway);
if (gateway_mac && !l_rtnl_neighbor_set_hwaddr(rtnl,
@@ -876,6 +1063,9 @@ static void netconfig_ipv6_ifaddr_add_cmd_cb(int error, uint16_t
type,
netconfig_set_dns(netconfig);
netconfig_set_domains(netconfig);
+
+ if (!netconfig->route6_add_cmd_id)
+ netconfig_connected_v6(netconfig);
}
static void netconfig_ifaddr_del_cmd_cb(int error, uint16_t type,
@@ -898,11 +1088,44 @@ static void netconfig_ifaddr_del_cmd_cb(int error, uint16_t type,
"Error %d: %s", error, strerror(-error));
}
+static bool netconfig_address_cmp_address(const struct l_rtnl_address *a,
+ const struct l_rtnl_address *b)
+{
+ char str_a[INET6_ADDRSTRLEN];
+ char str_b[INET6_ADDRSTRLEN];
+
+ if (a == b)
+ return true;
+
+ if (!a || !b)
+ return false;
+
+ if (!l_rtnl_address_get_address(a, str_a) ||
+ !l_rtnl_address_get_address(b, str_b))
+ return false;
+
+ return !strcmp(str_a, str_b);
+}
+
+static bool netconfig_address_cmp_prefix_len(const struct l_rtnl_address *a,
+ const struct l_rtnl_address *b)
+{
+ if (a == b)
+ return true;
+
+ if (!a || !b)
+ return false;
+
+ return l_rtnl_address_get_prefix_length(a) ==
+ l_rtnl_address_get_prefix_length(b);
+}
+
static void netconfig_ipv4_dhcp_event_handler(struct l_dhcp_client *client,
enum l_dhcp_client_event event,
void *userdata)
{
struct netconfig *netconfig = userdata;
+ struct l_dbus *dbus = dbus_get_bus();
l_debug("DHCPv4 event %d", event);
@@ -912,10 +1135,47 @@ static void netconfig_ipv4_dhcp_event_handler(struct l_dhcp_client
*client,
netconfig->v4_address,
netconfig_ifaddr_del_cmd_cb,
netconfig, NULL));
- l_rtnl_address_free(netconfig->v4_address);
/* Fall through. */
case L_DHCP_CLIENT_EVENT_LEASE_OBTAINED:
- netconfig->v4_address = netconfig_get_dhcp4_address(netconfig);
+ {
+ char *gateway_str;
+ struct l_rtnl_address *address;
+
+ gateway_str = netconfig_ipv4_get_gateway(netconfig, NULL);
+ if (l_streq0(netconfig->v4_gateway_str, gateway_str))
+ l_free(gateway_str);
+ else {
+ l_free(netconfig->v4_gateway_str);
+ netconfig->v4_gateway_str = gateway_str;
+
+ if (netconfig->dbus_path && netconfig->v4_configured)
+ l_dbus_property_changed(dbus,
+ netconfig->dbus_path,
+ IWD_IPV4_CONFIG_INTERFACE,
+ "Gateway");
+ }
+
+ address = netconfig_get_dhcp4_address(netconfig);
+
+ if (netconfig->dbus_path && netconfig->v4_configured &&
+ !netconfig_address_cmp_prefix_len(
+ netconfig->v4_address,
+ address))
+ l_dbus_property_changed(dbus, netconfig->dbus_path,
+ IWD_IPV4_CONFIG_INTERFACE,
+ "Netmask");
+
+ if (netconfig->dbus_path && netconfig->v4_configured &&
+ netconfig_address_cmp_address(
+ netconfig->v4_address,
+ address))
+ l_dbus_property_changed(dbus, netconfig->dbus_path,
+ IWD_IPV4_CONFIG_INTERFACE,
+ "Address");
+
+ l_rtnl_address_free(netconfig->v4_address);
+ netconfig->v4_address = address;
+
if (!netconfig->v4_address) {
l_error("netconfig: Failed to obtain IP addresses from "
"DHCPv4 lease.");
@@ -928,6 +1188,7 @@ static void netconfig_ipv4_dhcp_event_handler(struct l_dhcp_client
*client,
netconfig_ipv4_ifaddr_add_cmd_cb,
netconfig, NULL)));
break;
+ }
case L_DHCP_CLIENT_EVENT_LEASE_RENEWED:
break;
case L_DHCP_CLIENT_EVENT_LEASE_EXPIRED:
@@ -937,6 +1198,10 @@ static void netconfig_ipv4_dhcp_event_handler(struct l_dhcp_client
*client,
netconfig, NULL));
l_rtnl_address_free(netconfig->v4_address);
netconfig->v4_address = NULL;
+ l_free(l_steal_ptr(netconfig->v4_gateway_str));
+
+ if (netconfig->v4_configured)
+ netconfig_disconnected_v4(netconfig);
/* Fall through. */
case L_DHCP_CLIENT_EVENT_NO_LEASE:
@@ -960,18 +1225,76 @@ static void netconfig_dhcp6_event_handler(struct l_dhcp6_client
*client,
void *userdata)
{
struct netconfig *netconfig = userdata;
+ struct l_dbus *dbus = dbus_get_bus();
switch (event) {
case L_DHCP6_CLIENT_EVENT_IP_CHANGED:
case L_DHCP6_CLIENT_EVENT_LEASE_OBTAINED:
case L_DHCP6_CLIENT_EVENT_LEASE_RENEWED:
+ {
+ __auto_type lease =
+ l_dhcp6_client_get_lease(netconfig->dhcp6_client);
+ L_AUTO_FREE_VAR(char *, addr_str) =
+ l_dhcp6_lease_get_address(lease);
+ struct l_rtnl_address *address;
+ __auto_type icmp6 =
+ l_dhcp6_client_get_icmp6(netconfig->dhcp6_client);
+ __auto_type router = l_icmp6_client_get_router(icmp6);
+ char *gateway_str = l_icmp6_router_get_address(router);
+
+ if (l_streq0(netconfig->v6_gateway_str, gateway_str))
+ l_free(gateway_str);
+ else {
+ l_free(netconfig->v6_gateway_str);
+ netconfig->v6_gateway_str = gateway_str;
+
+ if (netconfig->dbus_path && netconfig->v6_configured)
+ l_dbus_property_changed(dbus,
+ netconfig->dbus_path,
+ IWD_IPV6_CONFIG_INTERFACE,
+ "Gateway");
+ }
+
+ address = l_rtnl_address_new(addr_str,
+ l_dhcp6_lease_get_prefix_length(lease));
+
+ if (netconfig->dbus_path && netconfig->v6_configured &&
+ !netconfig_address_cmp_prefix_len(
+ netconfig->v6_address,
+ address))
+ l_dbus_property_changed(dbus, netconfig->dbus_path,
+ IWD_IPV6_CONFIG_INTERFACE,
+ "Netmask");
+
+ if (netconfig->dbus_path && netconfig->v6_configured &&
+ netconfig_address_cmp_address(
+ netconfig->v6_address,
+ address))
+ l_dbus_property_changed(dbus, netconfig->dbus_path,
+ IWD_IPV6_CONFIG_INTERFACE,
+ "Address");
+
+ l_rtnl_address_free(netconfig->v6_address);
+ netconfig->v6_address = address;
+
netconfig_set_dns(netconfig);
netconfig_set_domains(netconfig);
+
+ if (!netconfig->v6_configured)
+ netconfig_connected_v6(netconfig);
+
break;
+ }
case L_DHCP6_CLIENT_EVENT_LEASE_EXPIRED:
l_debug("Lease for interface %u expired", netconfig->ifindex);
netconfig_set_dns(netconfig);
netconfig_set_domains(netconfig);
+ l_rtnl_address_free(netconfig->v6_address);
+ netconfig->v6_address = NULL;
+ l_free(l_steal_ptr(netconfig->v6_gateway_str));
+
+ if (netconfig->v6_configured)
+ netconfig_disconnected_v6(netconfig);
/* Fall through */
case L_DHCP6_CLIENT_EVENT_NO_LEASE:
@@ -993,6 +1316,9 @@ static void netconfig_remove_v4_address(struct netconfig *netconfig)
netconfig, NULL));
l_rtnl_address_free(netconfig->v4_address);
netconfig->v4_address = NULL;
+
+ if (netconfig->v4_configured)
+ netconfig_disconnected_v4(netconfig);
}
static void netconfig_reset_v4(struct netconfig *netconfig)
@@ -1000,14 +1326,19 @@ static void netconfig_reset_v4(struct netconfig *netconfig)
if (netconfig->rtm_protocol) {
netconfig_remove_v4_address(netconfig);
- l_strfreev(netconfig->dns4_overrides);
- netconfig->dns4_overrides = NULL;
+ l_strv_free(l_steal_ptr(netconfig->dns4_overrides));
+ l_strv_free(l_steal_ptr(netconfig->dns4_list));
l_dhcp_client_stop(netconfig->dhcp_client);
netconfig->rtm_protocol = 0;
l_acd_destroy(netconfig->acd);
netconfig->acd = NULL;
+
+ l_free(netconfig->v4_gateway_str);
+ netconfig->v4_gateway_str = NULL;
+
+ l_free(l_steal_ptr(netconfig->v4_domain));
}
}
@@ -1117,7 +1448,6 @@ static bool netconfig_ipv4_select_and_install(struct netconfig
*netconfig)
static bool netconfig_ipv6_select_and_install(struct netconfig *netconfig)
{
struct netdev *netdev = netdev_find(netconfig->ifindex);
- struct l_rtnl_address *address = NULL;
if (netconfig->rtm_v6_protocol == RTPROT_UNSPEC) {
l_debug("IPV6 configuration disabled");
@@ -1126,10 +1456,7 @@ static bool netconfig_ipv6_select_and_install(struct netconfig
*netconfig)
sysfs_write_ipv6_setting(netdev_get_name(netdev), "disable_ipv6",
"0");
- if (netconfig->rtm_v6_protocol == RTPROT_STATIC)
- address = netconfig_get_static6_address(
- netconfig->active_settings);
- else if (netconfig->rtm_v6_protocol == RTPROT_DHCP &&
+ if (netconfig->rtm_v6_protocol == RTPROT_DHCP &&
netconfig->fils_override &&
!l_memeqzero(netconfig->fils_override->ipv6_addr, 16)) {
uint8_t prefix_len = netconfig->fils_override->ipv6_prefix_len;
@@ -1139,11 +1466,12 @@ static bool netconfig_ipv6_select_and_install(struct netconfig
*netconfig)
if (unlikely(!addr_str))
return false;
- if (L_WARN_ON(unlikely(!(address = l_rtnl_address_new(addr_str,
- prefix_len)))))
+ netconfig->v6_address = l_rtnl_address_new(addr_str,
+ prefix_len);
+ if (L_WARN_ON(unlikely(!netconfig->v6_address)))
return false;
- l_rtnl_address_set_noprefixroute(address, true);
+ l_rtnl_address_set_noprefixroute(netconfig->v6_address, true);
/*
* TODO: If netconfig->fils_override->ipv6_lifetime is set,
@@ -1153,12 +1481,12 @@ static bool netconfig_ipv6_select_and_install(struct netconfig
*netconfig)
*/
}
- if (address) {
+ if (netconfig->v6_address) {
L_WARN_ON(!(netconfig->addr6_add_cmd_id =
- l_rtnl_ifaddr_add(rtnl, netconfig->ifindex, address,
+ l_rtnl_ifaddr_add(rtnl, netconfig->ifindex,
+ netconfig->v6_address,
netconfig_ipv6_ifaddr_add_cmd_cb,
netconfig, NULL)));
- l_rtnl_address_free(address);
return true;
}
@@ -1273,7 +1601,6 @@ bool netconfig_load_settings(struct netconfig *netconfig,
if (l_settings_has_key(active_settings, "IPv6", "Address")) {
v6_address = netconfig_get_static6_address(active_settings);
- l_rtnl_address_free(v6_address);
if (unlikely(!v6_address)) {
l_error("netconfig: Can't parse IPv6 address");
@@ -1291,11 +1618,14 @@ bool netconfig_load_settings(struct netconfig *netconfig,
if (!v6_enabled)
netconfig->rtm_v6_protocol = RTPROT_UNSPEC;
- else if (v6_address)
+ else if (v6_address) {
+ netconfig->v6_address = l_steal_ptr(v6_address);
netconfig->rtm_v6_protocol = RTPROT_STATIC;
- else
+ } else
netconfig->rtm_v6_protocol = RTPROT_DHCP;
+ l_rtnl_address_free(v6_address);
+
if (send_hostname)
l_dhcp_client_set_hostname(netconfig->dhcp_client, hostname);
@@ -1355,11 +1685,22 @@ bool netconfig_reset(struct netconfig *netconfig)
{
struct netdev *netdev = netdev_find(netconfig->ifindex);
+ if (netconfig->v4_configured)
+ netconfig_disconnected_v4(netconfig);
+
+ if (netconfig->v6_configured)
+ netconfig_disconnected_v6(netconfig);
+
if (netconfig->route4_add_gateway_cmd_id) {
l_netlink_cancel(rtnl, netconfig->route4_add_gateway_cmd_id);
netconfig->route4_add_gateway_cmd_id = 0;
}
+ if (netconfig->route6_add_cmd_id) {
+ l_netlink_cancel(rtnl, netconfig->route6_add_cmd_id);
+ netconfig->route6_add_cmd_id = 0;
+ }
+
if (netconfig->addr4_add_cmd_id) {
l_netlink_cancel(rtnl, netconfig->addr4_add_cmd_id);
netconfig->addr4_add_cmd_id = 0;
@@ -1376,14 +1717,22 @@ bool netconfig_reset(struct netconfig *netconfig)
netconfig_reset_v4(netconfig);
if (netconfig->rtm_v6_protocol) {
- l_strfreev(netconfig->dns6_overrides);
- netconfig->dns6_overrides = NULL;
+ l_rtnl_address_free(netconfig->v6_address);
+ netconfig->v6_address = NULL;
+
+ l_strv_free(l_steal_ptr(netconfig->dns6_overrides));
+ l_strv_free(l_steal_ptr(netconfig->dns6_list));
l_dhcp6_client_stop(netconfig->dhcp6_client);
netconfig->rtm_v6_protocol = 0;
sysfs_write_ipv6_setting(netdev_get_name(netdev),
"disable_ipv6", "1");
+
+ l_free(netconfig->v6_gateway_str);
+ netconfig->v6_gateway_str = NULL;
+
+ l_strv_free(l_steal_ptr(netconfig->v6_domains));
}
l_free(l_steal_ptr(netconfig->fils_override));
@@ -1434,7 +1783,7 @@ void netconfig_handle_fils_ip_resp(struct netconfig *netconfig,
netconfig->fils_override = l_memdup(info, sizeof(*info));
}
-struct netconfig *netconfig_new(uint32_t ifindex)
+struct netconfig *netconfig_new(uint32_t ifindex, const char *dbus_path)
{
struct netdev *netdev = netdev_find(ifindex);
struct netconfig *netconfig;
@@ -1451,6 +1800,7 @@ struct netconfig *netconfig_new(uint32_t ifindex)
netconfig = l_new(struct netconfig, 1);
netconfig->ifindex = ifindex;
+ netconfig->dbus_path = l_strdup(dbus_path);
netconfig->resolve = resolve_new(ifindex);
netconfig->dhcp_client = l_dhcp_client_new(ifindex);
@@ -1483,6 +1833,19 @@ struct netconfig *netconfig_new(uint32_t ifindex)
sysfs_write_ipv6_setting(netdev_get_name(netdev), "accept_ra",
"0");
sysfs_write_ipv6_setting(netdev_get_name(netdev), "disable_ipv6",
"1");
+ /*
+ * Use struct interface_data as interface user_data so that the
+ * property getters can check which interface they're being called
+ * for. For the org.freedesktop.DBus.Properties.{Get,GetAll} calls
+ * we can read the interface name from the first argument but the
+ * getters are also called when the InterfaceAdded signal messages
+ * is being built.
+ */
+ netconfig->v4_data.is_ipv4 = true;
+ netconfig->v4_data.netconfig = netconfig;
+ netconfig->v6_data.is_ipv4 = false;
+ netconfig->v6_data.netconfig = netconfig;
+
return netconfig;
}
@@ -1500,6 +1863,167 @@ void netconfig_destroy(struct netconfig *netconfig)
netconfig_free(netconfig);
}
+static bool netconfig_property_get_method(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ struct l_dbus_message_builder *builder,
+ void *user_data)
+{
+ const struct interface_data *data = user_data;
+ uint8_t protocol;
+
+ protocol = data->is_ipv4 ? data->netconfig->rtm_protocol :
+ data->netconfig->rtm_v6_protocol;
+
+ l_dbus_message_builder_append_basic(builder, 's',
+ protocol == RTPROT_DHCP ?
+ "auto" : "static");
+ return true;
+}
+
+static bool netconfig_property_get_address(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ struct l_dbus_message_builder *builder,
+ void *user_data)
+{
+ const struct interface_data *data = user_data;
+ const struct l_rtnl_address *address;
+ char ip_str[INET6_ADDRSTRLEN];
+
+ address = data->is_ipv4 ? data->netconfig->v4_address :
+ data->netconfig->v6_address;
+
+ if (!address || !l_rtnl_address_get_address(address, ip_str))
+ return false;
+
+ l_dbus_message_builder_append_basic(builder, 's', ip_str);
+ return true;
+}
+
+static bool netconfig_property_get_prefix(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ struct l_dbus_message_builder *builder,
+ void *user_data)
+{
+ const struct interface_data *data = user_data;
+ const struct l_rtnl_address *address;
+ uint8_t prefix_len;
+
+ address = data->is_ipv4 ?
+ data->netconfig->v4_address : data->netconfig->v6_address;
+
+ if (!address || !(prefix_len =
+ l_rtnl_address_get_prefix_length(address)))
+ return false;
+
+ l_dbus_message_builder_append_basic(builder, 'y', &prefix_len);
+ return true;
+}
+
+static bool netconfig_property_get_gateway(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ struct l_dbus_message_builder *builder,
+ void *user_data)
+{
+ const struct interface_data *data = user_data;
+ const char *gateway_str = data->is_ipv4 ?
+ data->netconfig->v4_gateway_str :
+ data->netconfig->v6_gateway_str;
+
+ if (!gateway_str)
+ return false;
+
+ l_dbus_message_builder_append_basic(builder, 's', gateway_str);
+ return true;
+}
+
+static bool netconfig_property_get_dnses(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ struct l_dbus_message_builder *builder,
+ void *user_data)
+{
+ const struct interface_data *data = user_data;
+ char **dns_str_list = data->is_ipv4 ?
+ data->netconfig->dns4_list : data->netconfig->dns6_list;
+ char **i;
+
+ if (!dns_str_list)
+ return false;
+
+ l_dbus_message_builder_enter_array(builder, "s");
+
+ for (i = dns_str_list; i && *i; i++)
+ l_dbus_message_builder_append_basic(builder, 's', *i);
+
+ l_dbus_message_builder_leave_array(builder);
+ return true;
+}
+
+static bool netconfig_property_get_v4_domains(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ struct l_dbus_message_builder *builder,
+ void *user_data)
+{
+ const struct interface_data *data = user_data;
+
+ if (!data->netconfig->v4_domain)
+ return false;
+
+ l_dbus_message_builder_enter_array(builder, "s");
+ l_dbus_message_builder_append_basic(builder, 's',
+ data->netconfig->v4_domain);
+ l_dbus_message_builder_leave_array(builder);
+ return true;
+}
+
+static bool netconfig_property_get_v6_domains(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ struct l_dbus_message_builder *builder,
+ void *user_data)
+{
+ const struct interface_data *data = user_data;
+ char **i;
+
+ if (!data->netconfig->v6_domains)
+ return false;
+
+ l_dbus_message_builder_enter_array(builder, "s");
+
+ for (i = data->netconfig->v6_domains; *i; i++)
+ l_dbus_message_builder_append_basic(builder, 's', *i);
+
+ l_dbus_message_builder_leave_array(builder);
+ return true;
+}
+
+static void netconfig_setup_interface(struct l_dbus_interface *interface,
+ bool is_ipv4)
+{
+ l_dbus_interface_property(interface, "Method", 0, "s",
+ netconfig_property_get_method, NULL);
+ l_dbus_interface_property(interface, "Address", 0, "s",
+ netconfig_property_get_address, NULL);
+ l_dbus_interface_property(interface, "PrefixLength", 0, "y",
+ netconfig_property_get_prefix, NULL);
+ l_dbus_interface_property(interface, "Gateway", 0, "s",
+ netconfig_property_get_gateway, NULL);
+ l_dbus_interface_property(interface, "DomainNameServers", 0, "as",
+ netconfig_property_get_dnses, NULL);
+ l_dbus_interface_property(interface, "DomainNames", 0, "as", is_ipv4
?
+ netconfig_property_get_v4_domains :
+ netconfig_property_get_v6_domains,
+ NULL);
+}
+
+static void netconfig_setup_v4_interface(struct l_dbus_interface *interface)
+{
+ netconfig_setup_interface(interface, true);
+}
+
+static void netconfig_setup_v6_interface(struct l_dbus_interface *interface)
+{
+ netconfig_setup_interface(interface, false);
+}
+
static int netconfig_init(void)
{
uint32_t r;
@@ -1551,6 +2075,14 @@ static int netconfig_init(void)
netconfig_list = l_queue_new();
+ L_WARN_ON(unlikely(!l_dbus_register_interface(dbus_get_bus(),
+ IWD_IPV4_CONFIG_INTERFACE,
+ netconfig_setup_v4_interface,
+ NULL, false)));
+ L_WARN_ON(unlikely(!l_dbus_register_interface(dbus_get_bus(),
+ IWD_IPV6_CONFIG_INTERFACE,
+ netconfig_setup_v6_interface,
+ NULL, false)));
return 0;
error:
@@ -1567,6 +2099,9 @@ static void netconfig_exit(void)
rtnl = NULL;
l_queue_destroy(netconfig_list, netconfig_free);
+
+ l_dbus_unregister_interface(dbus_get_bus(), IWD_IPV4_CONFIG_INTERFACE);
+ l_dbus_unregister_interface(dbus_get_bus(), IWD_IPV6_CONFIG_INTERFACE);
}
IWD_MODULE(netconfig, netconfig_init, netconfig_exit)
diff --git a/src/netconfig.h b/src/netconfig.h
index fa46c7c8..5d54d9cc 100644
--- a/src/netconfig.h
+++ b/src/netconfig.h
@@ -45,5 +45,5 @@ bool netconfig_get_fils_ip_req(struct netconfig *netconfig,
void netconfig_handle_fils_ip_resp(struct netconfig *netconfig,
const struct ie_fils_ip_addr_response_info *info);
-struct netconfig *netconfig_new(uint32_t ifindex);
+struct netconfig *netconfig_new(uint32_t ifindex, const char *dbus_path);
void netconfig_destroy(struct netconfig *netconfig);
diff --git a/src/p2p.c b/src/p2p.c
index 3328271b..b68e4f7c 100644
--- a/src/p2p.c
+++ b/src/p2p.c
@@ -1320,7 +1320,9 @@ static void p2p_start_client_netconfig(struct p2p_device *dev)
struct l_settings *settings;
if (!dev->conn_netconfig) {
- dev->conn_netconfig = netconfig_new(ifindex);
+ const char *peer_path = p2p_peer_get_path(dev->conn_peer);
+
+ dev->conn_netconfig = netconfig_new(ifindex, peer_path);
if (!dev->conn_netconfig) {
p2p_connect_failed(dev);
return;
diff --git a/src/station.c b/src/station.c
index 6de5fd4a..105d0ad8 100644
--- a/src/station.c
+++ b/src/station.c
@@ -3577,6 +3577,7 @@ static struct station *station_create(struct netdev *netdev)
struct station *station;
struct l_dbus *dbus = dbus_get_bus();
bool autoconnect = true;
+ const char *path;
station = l_new(struct station, 1);
watchlist_init(&station->state_watches, NULL);
@@ -3594,11 +3595,12 @@ static struct station *station_create(struct netdev *netdev)
l_queue_push_head(station_list, station);
- l_dbus_object_add_interface(dbus, netdev_get_path(netdev),
- IWD_STATION_INTERFACE, station);
+ path = netdev_get_path(netdev);
+ l_dbus_object_add_interface(dbus, path, IWD_STATION_INTERFACE, station);
if (netconfig_enabled)
- station->netconfig = netconfig_new(netdev_get_ifindex(netdev));
+ station->netconfig = netconfig_new(netdev_get_ifindex(netdev),
+ path);
station->anqp_pending = l_queue_new();
--
2.30.2