From patchwork Fri Dec 22 15:46:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jussi Laakkonen X-Patchwork-Id: 13503468 Received: from fgw20-7.mail.saunalahti.fi (fgw20-7.mail.saunalahti.fi [62.142.5.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1BD0523753 for ; Fri, 22 Dec 2023 15:47:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=jolla.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=jolla.com Received: from localhost.localdomain (88-113-60-79.elisa-laajakaista.fi [88.113.60.79]) by fgw20.mail.saunalahti.fi (Halon) with ESMTP id 50b914ca-a0e1-11ee-b3cf-005056bd6ce9; Fri, 22 Dec 2023 17:46:47 +0200 (EET) From: Jussi Laakkonen To: connman@lists.linux.dev Subject: [PATCH 1/3] technology: Add global regdom and regdom getter Date: Fri, 22 Dec 2023 17:46:43 +0200 Message-Id: <20231222154645.278128-2-jussi.laakkonen@jolla.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20231222154645.278128-1-jussi.laakkonen@jolla.com> References: <20231222154645.278128-1-jussi.laakkonen@jolla.com> Precedence: bulk X-Mailing-List: connman@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add a global regdom to be saved when setting technology regdom because the technologies are not loaded yet at bootup. Loading of plugins initializes technologies which then sets up the regdom if it has been set up earlier by timezone.c. The getter prioritizes the technology regdom and then the global regdom and is to be used by devices when powering up. --- src/connman.h | 1 + src/technology.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/connman.h b/src/connman.h index 622a7785..34e1463e 100644 --- a/src/connman.h +++ b/src/connman.h @@ -595,6 +595,7 @@ void __connman_technology_remove_interface(enum connman_service_type type, int index, const char *ident); void __connman_technology_notify_regdom_by_device(struct connman_device *device, int result, const char *alpha2); +const char *__connman_technology_get_regdom(enum connman_service_type type); #include diff --git a/src/technology.c b/src/technology.c index 5c469111..65fb9854 100644 --- a/src/technology.c +++ b/src/technology.c @@ -43,6 +43,8 @@ static GHashTable *rfkill_list; static bool global_offlinemode; +static char *global_regdom = NULL; + struct connman_rfkill { unsigned int index; enum connman_service_type type; @@ -333,8 +335,14 @@ int connman_technology_set_regdom(const char *alpha2) driver->set_regdom(technology, alpha2); } } + + /* Save regdom for this technology */ + connman_technology_regdom_notify(technology, alpha2); } + g_free(global_regdom); + global_regdom = g_strdup(alpha2); + return 0; } @@ -354,6 +362,22 @@ static struct connman_technology *technology_find(enum connman_service_type type return NULL; } +const char *__connman_technology_get_regdom(enum connman_service_type type) +{ + struct connman_technology *technology; + + DBG("type %d/%s", type, get_name(type)); + + technology = technology_find(type); + if (!technology) + return NULL; + + if (technology->regdom) + return technology->regdom; + + return global_regdom; +} + enum connman_service_type connman_technology_get_type (struct connman_technology *technology) { @@ -1283,6 +1307,7 @@ static struct connman_technology *technology_get(enum connman_service_type type) technology_load(technology); technology_list = g_slist_prepend(technology_list, technology); technology->driver_list = tech_drivers; + technology->regdom = g_strdup(global_regdom); for (list = tech_drivers; list; list = list->next) { driver = list->data; @@ -1905,4 +1930,6 @@ void __connman_technology_cleanup(void) g_hash_table_destroy(rfkill_list); dbus_connection_unref(connection); + + g_free(global_regdom); } From patchwork Fri Dec 22 15:46:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jussi Laakkonen X-Patchwork-Id: 13503470 Received: from fgw20-7.mail.saunalahti.fi (fgw20-7.mail.saunalahti.fi [62.142.5.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9284C23775 for ; Fri, 22 Dec 2023 15:47:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=jolla.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=jolla.com Received: from localhost.localdomain (88-113-60-79.elisa-laajakaista.fi [88.113.60.79]) by fgw20.mail.saunalahti.fi (Halon) with ESMTP id 511ba8b9-a0e1-11ee-b3cf-005056bd6ce9; Fri, 22 Dec 2023 17:46:48 +0200 (EET) From: Jussi Laakkonen To: connman@lists.linux.dev Subject: [PATCH 2/3] device: Setup regdom when powering up to maintain consistency Date: Fri, 22 Dec 2023 17:46:44 +0200 Message-Id: <20231222154645.278128-3-jussi.laakkonen@jolla.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20231222154645.278128-1-jussi.laakkonen@jolla.com> References: <20231222154645.278128-1-jussi.laakkonen@jolla.com> Precedence: bulk X-Mailing-List: connman@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 If the regdom has been set for the technology or for all the technologies as a global setting apply it when powering up a device that supports changing regdom. Otherwise the changes made to regdom may not have been propagated to the device if the change has been made when the device was powered off, for instance. --- src/device.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/device.c b/src/device.c index 264c5e2d..55670099 100644 --- a/src/device.c +++ b/src/device.c @@ -589,6 +589,7 @@ int connman_device_set_powered(struct connman_device *device, { struct connman_device_scan_params params; enum connman_service_type type; + const char *alpha2; int i; DBG("device %p powered %d", device, powered); @@ -607,6 +608,16 @@ int connman_device_set_powered(struct connman_device *device, if (!device->powered) { __connman_technology_disabled(type); return 0; + } else { + /* + * Check if the technology has regdom set and apply it for the + * device. Regdom may have been changed when the device was + * powered off and, thus, the new regdom has not been applied + * here. + */ + alpha2 = __connman_technology_get_regdom(type); + if (alpha2) + connman_device_set_regdom(device, alpha2); } __connman_technology_enabled(type); From patchwork Fri Dec 22 15:46:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jussi Laakkonen X-Patchwork-Id: 13503471 Received: from fgw20-7.mail.saunalahti.fi (fgw20-7.mail.saunalahti.fi [62.142.5.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4DE3123779 for ; Fri, 22 Dec 2023 15:47:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=jolla.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=jolla.com Received: from localhost.localdomain (88-113-60-79.elisa-laajakaista.fi [88.113.60.79]) by fgw20.mail.saunalahti.fi (Halon) with ESMTP id 5175d85e-a0e1-11ee-b3cf-005056bd6ce9; Fri, 22 Dec 2023 17:46:49 +0200 (EET) From: Jussi Laakkonen To: connman@lists.linux.dev Subject: [PATCH 3/3] timezone: Fix resolving of proper ISO3166 code from tz data Date: Fri, 22 Dec 2023 17:46:45 +0200 Message-Id: <20231222154645.278128-4-jussi.laakkonen@jolla.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20231222154645.278128-1-jussi.laakkonen@jolla.com> References: <20231222154645.278128-1-jussi.laakkonen@jolla.com> Precedence: bulk X-Mailing-List: connman@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 It is possible that the region set as localtime region may have matches in either of the zone map files. And in some cases there may be ISO3166 codes in the deprecated files that are not supported by the backends such as gsupplicant to set the regulatory domain. Ålands/Mariehamn is an example of this since as a region it only exists in zone.tab and provides ISO3166 code AX which cannot be supported as regulatory domain. But zone1970.tab contains the ISO3166 as a sub-region code for Finland (FI) that should be set. Furthermore, the timezone files for sub-regions, like with Ålands in Finland and Pacific/Midway as UM -> AS, are identical copies and cannot be compared solely by checking the mmap()'d entries. The path needs to be taken into account or wrong region might be generated as a search parameter for getting the ISO3166 code. Otherwise the results in some cases might be ambiguous and the localtime set would yield another region as a search parameter for the ISO3661 code. Therefore, these changes add the real path utilized from the Localtime path set in ConnMan settings to be used along the comparison of timezone files. And the resolving of the ISO3661 code supports now more laborous search if the code is not found using the region as a search parameter. In such case the ISO3661 code is attempted to be searched from the deprecated tz map and when found this code is used to search the zone1970.tab again for a match in any of the defined ISO3166 string lists. As a result the ISO3166 code of the main region is set that should be supported by the varying backends to set the WiFi regulatory domain. --- src/timezone.c | 178 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 152 insertions(+), 26 deletions(-) diff --git a/src/timezone.c b/src/timezone.c index f8d192df..89c44895 100644 --- a/src/timezone.c +++ b/src/timezone.c @@ -38,9 +38,10 @@ #include "connman.h" -#define ETC_SYSCONFIG_CLOCK "/etc/sysconfig/clock" -#define USR_SHARE_ZONEINFO "/usr/share/zoneinfo" -#define USR_SHARE_ZONEINFO_MAP USR_SHARE_ZONEINFO "/zone1970.tab" +#define ETC_SYSCONFIG_CLOCK "/etc/sysconfig/clock" +#define USR_SHARE_ZONEINFO "/usr/share/zoneinfo" +#define USR_SHARE_ZONEINFO_MAP USR_SHARE_ZONEINFO "/zone1970.tab" +#define USR_SHARE_ZONEINFO_MAP_OLD USR_SHARE_ZONEINFO "/zone.tab" static char *read_key_file(const char *pathname, const char *key) { @@ -115,12 +116,17 @@ static char *read_key_file(const char *pathname, const char *key) } static int compare_file(void *src_map, struct stat *src_st, - const char *pathname) + const char *real_path, const char *pathname) { struct stat dst_st; void *dst_map; int fd, result; + DBG("real path %s path name %s", real_path, pathname); + + if (real_path && g_strcmp0(real_path, pathname)) + return -1; + fd = open(pathname, O_RDONLY | O_CLOEXEC); if (fd < 0) return -1; @@ -151,7 +157,8 @@ static int compare_file(void *src_map, struct stat *src_st, } static char *find_origin(void *src_map, struct stat *src_st, - const char *basepath, const char *subpath) + const char* real_path, const char *basepath, + const char *subpath) { DIR *dir; struct dirent *d; @@ -186,7 +193,8 @@ static char *find_origin(void *src_map, struct stat *src_st, "%s/%s/%s", basepath, subpath, d->d_name); - if (compare_file(src_map, src_st, pathname) == 0) { + if (compare_file(src_map, src_st, real_path, pathname) + == 0) { if (!subpath) str = g_strdup(d->d_name); else @@ -214,7 +222,8 @@ static char *find_origin(void *src_map, struct stat *src_st, snprintf(pathname, sizeof(pathname), "%s/%s", subpath, d->d_name); - str = find_origin(src_map, src_st, basepath, pathname); + str = find_origin(src_map, src_st, real_path, basepath, + pathname); if (str) { closedir(dir); return str; @@ -228,7 +237,52 @@ static char *find_origin(void *src_map, struct stat *src_st, return NULL; } -static char *get_timezone_alpha2(const char *zone) +/* TZ map file format: Countrycodes Coordinates TZ Comments */ +enum tz_map_item { + TZ_MAP_ITEM_ISO3166 = 0, + TZ_MAP_ITEM_COORDINATE = 1, + TZ_MAP_ITEM_TIMEZONE = 2, + TZ_MAP_ITEM_COMMENT = 3, +}; + +static bool iso3166_matches(const char *codes, const char *iso3166) +{ + gchar **tokens; + guint len; + guint i; + bool ret = false; + + if (!codes || !iso3166) + return false; + + tokens = g_strsplit(codes, ",", -1); + if (!tokens) + return false; + + len = g_strv_length(tokens); + if (len < 2) { + g_strfreev(tokens); + return false; + } + + DBG("search %s from %s", iso3166, codes); + + for (i = 0; i < len; i++) { + DBG("#%d %s", i, tokens[i]); + + if (!g_strcmp0(tokens[i], iso3166)) { + ret = true; + break; + } + } + + g_strfreev(tokens); + + return ret; +} + +static char *get_timezone_alpha2(const char *zone, const char *mapfile, + enum tz_map_item map_item) { GIOChannel *channel; struct stat st; @@ -236,15 +290,15 @@ static char *get_timezone_alpha2(const char *zone) char *line; char *alpha2 = NULL; gsize len; + bool found = false; int fd; if (!zone) return NULL; - fd = open(USR_SHARE_ZONEINFO_MAP, O_RDONLY | O_CLOEXEC); + fd = open(mapfile, O_RDONLY | O_CLOEXEC); if (fd < 0) { - connman_warn("failed to open zoneinfo map %s", - USR_SHARE_ZONEINFO_MAP); + connman_warn("failed to open zoneinfo map %s", mapfile); return NULL; } @@ -256,23 +310,23 @@ static char *get_timezone_alpha2(const char *zone) channel = g_io_channel_unix_new(fd); if (!channel) { - connman_warn("failed to create io channel for %s", - USR_SHARE_ZONEINFO_MAP); + connman_warn("failed to create io channel for %s", mapfile); close(fd); return NULL; } - DBG("read %s for %s", USR_SHARE_ZONEINFO_MAP, zone); + DBG("read %s for %s", mapfile, zone); g_io_channel_set_encoding(channel, "UTF-8", NULL); while (g_io_channel_read_line(channel, &line, &len, NULL, NULL) == G_IO_STATUS_NORMAL) { + found = false; + if (!line || !*line || *line == '#' || *line == '\n') { g_free(line); continue; } - /* File format: Countrycodes Coordinates TZ Comments */ tokens = g_strsplit_set(line, " \t", 4); if (!tokens) { connman_warn("line %s failed to parse", line); @@ -280,13 +334,35 @@ static char *get_timezone_alpha2(const char *zone) continue; } - if (g_strv_length(tokens) >= 3 && !g_strcmp0( - g_strstrip(tokens[2]), zone)) { + if (g_strv_length(tokens) >= 3) { + switch (map_item) { + case TZ_MAP_ITEM_ISO3166: + + if (!g_strcmp0(tokens[0], zone)) { + found = true; + break; + } + + if (iso3166_matches(tokens[0], zone)) + found = true; + break; + case TZ_MAP_ITEM_COORDINATE: + break; + case TZ_MAP_ITEM_TIMEZONE: + if (!g_strcmp0(g_strstrip(tokens[2]), zone)) + found = true; + break; + case TZ_MAP_ITEM_COMMENT: + break; + } + /* * Multiple country codes can be listed, use the first - * 2 chars. + * 2 chars as backends such as gsupplicant support only + * the main country code. */ - alpha2 = g_strndup(g_strstrip(tokens[0]), 2); + if (found) + alpha2 = g_strndup(g_strstrip(tokens[0]), 2); } g_strfreev(tokens); @@ -300,9 +376,8 @@ static char *get_timezone_alpha2(const char *zone) } else { DBG("Zone %s ISO3166 country code %s", zone, alpha2); + break; } - - break; } } @@ -312,6 +387,44 @@ static char *get_timezone_alpha2(const char *zone) return alpha2; } +static char *try_get_timezone_alpha2(const char *zone) +{ + char *alpha2; + char *alpha2_old; + + /* First try the official map */ + alpha2 = get_timezone_alpha2(zone, USR_SHARE_ZONEINFO_MAP, + TZ_MAP_ITEM_TIMEZONE); + if (alpha2) + return alpha2; + + DBG("%s not found in %s", zone, USR_SHARE_ZONEINFO_MAP); + + /* The zone was not found in official map, try with deprecated */ + alpha2_old = get_timezone_alpha2(zone, USR_SHARE_ZONEINFO_MAP_OLD, + TZ_MAP_ITEM_TIMEZONE); + if (!alpha2_old) { + DBG("%s not found in %s", zone, USR_SHARE_ZONEINFO_MAP_OLD); + return NULL; + } + + /* + * Found from deprecated, try to get main region code from official new + * map using the iso3166 search. This is because some of the codes + * defined in the deprecated are not supported by the backends, e.g., + * gsupplicant and the main code should be used. + */ + alpha2 = get_timezone_alpha2(alpha2_old, USR_SHARE_ZONEINFO_MAP, + TZ_MAP_ITEM_ISO3166); + + DBG("%s -> ISO3166 %s found in %s as %s", zone, alpha2_old, + USR_SHARE_ZONEINFO_MAP, alpha2); + + g_free(alpha2_old); + + return alpha2; +} + char *__connman_timezone_lookup(void) { struct stat st; @@ -319,13 +432,16 @@ char *__connman_timezone_lookup(void) int fd; char *zone; char *alpha2; + const char *local_time; + char real_path[PATH_MAX]; zone = read_key_file(ETC_SYSCONFIG_CLOCK, "ZONE"); DBG("sysconfig zone %s", zone); - fd = open(connman_setting_get_string("Localtime"), - O_RDONLY | O_CLOEXEC); + local_time = connman_setting_get_string("Localtime"); + + fd = open(local_time, O_RDONLY | O_CLOEXEC); if (fd < 0) { g_free(zone); return NULL; @@ -334,6 +450,15 @@ char *__connman_timezone_lookup(void) if (fstat(fd, &st) < 0) goto done; + if (!realpath(local_time, real_path)) { + connman_error("Failed to get real path of %s: %d/%s", + local_time, errno, strerror(errno)); + g_free(zone); + close(fd); + + return NULL; + } + if (S_ISREG(st.st_mode)) { map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); if (!map || map == MAP_FAILED) { @@ -349,14 +474,15 @@ char *__connman_timezone_lookup(void) snprintf(pathname, PATH_MAX, "%s/%s", USR_SHARE_ZONEINFO, zone); - if (compare_file(map, &st, pathname) != 0) { + if (compare_file(map, &st, NULL, pathname) != 0) { g_free(zone); zone = NULL; } } if (!zone) - zone = find_origin(map, &st, USR_SHARE_ZONEINFO, NULL); + zone = find_origin(map, &st, real_path, + USR_SHARE_ZONEINFO, NULL); munmap(map, st.st_size); } else { @@ -370,7 +496,7 @@ done: DBG("localtime zone %s", zone); if (connman_setting_get_bool("RegdomFollowsTimezone")) { - alpha2 = get_timezone_alpha2(zone); + alpha2 = try_get_timezone_alpha2(zone); if (alpha2) { DBG("change regdom to %s", alpha2); connman_technology_set_regdom(alpha2);