4 * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
24 * @desc Utility for working with network interfaces
30 #include <sys/ioctl.h>
31 #include <sys/socket.h>
41 #include "config-parser.h"
47 #define NET_INTERFACE_NAMES_FILE "/etc/resourced/network.conf"
48 #define IFACES_TYPE_SECTION "IFACES_TYPE"
50 static int iface_stat[RESOURCED_IFACE_LAST_ELEM - 1];
51 static GTree *iftypes; /* holds int key and value of type resourced_iface_type */
52 static GTree *ifnames; /* for keeping ifype - interface name association */
54 static pthread_rwlock_t iftypes_guard = PTHREAD_RWLOCK_INITIALIZER;
55 static pthread_rwlock_t ifnames_guard = PTHREAD_RWLOCK_INITIALIZER;
58 static const char *UEVENT_FMT = "/sys/class/net/%s/uevent";
59 static const char *DEVTYPE_KEY = "DEVTYPE";
60 static const char *WIRED_VALUE = "gadget";
61 static const char *WIFI_VALUE = "wlan";
62 static const char *BLUETOOTH_VALUE = "bluetooth";
63 static const char *DATACALL_VALUE = "datacall";
64 static const char *ALL_NET_IFACE_VALUE = "all";
65 static const char *UEVENT_DELIM = "=\n";
67 static GSList *ifnames_relations;
69 struct iface_relation {
70 resourced_iface_type iftype;
71 char ifname[MAX_NAME_LENGTH];
74 static gint compare_int(gconstpointer a, gconstpointer b,
75 gpointer UNUSED userdata)
84 static GTree *create_iface_tree(void)
86 return g_tree_new_full(compare_int,
90 static void put_iftype_to_tree(GTree *iftypes_tree, int ifindex, int iftype)
94 ret_msg_if(!iftypes_tree, "Please provide valid argument!");
95 new_value = (gpointer)malloc(sizeof(int));
97 _E("Malloc of put_iftype_to_tree failed\n");
100 *(int *)new_value = iftype;
101 g_tree_replace(iftypes_tree, (gpointer)ifindex, new_value);
104 static void put_ifname_to_tree(GTree *ifnames_tree, char *ifname, int iftype)
106 int name_len = strlen(ifname) + 1;
107 gpointer new_value = (gpointer)malloc(name_len);
109 _E("Malloc of put_ifname_to_tree failed\n");
112 strncpy(new_value, ifname, name_len);
116 _E("Please provide valid argument!");
119 g_tree_replace(ifnames_tree, (gpointer)iftype, new_value);
122 static resourced_iface_type get_iftype_from_tree(GTree *iftypes_tree, int ifindex)
124 resourced_iface_type ret = RESOURCED_IFACE_UNKNOWN;
125 gpointer table_value;
127 ret_value_msg_if(!iftypes_tree, ret, "Please provide valid argument!");
129 pthread_rwlock_rdlock(&iftypes_guard);
130 table_value = g_tree_lookup(iftypes_tree, (gpointer)ifindex);
131 pthread_rwlock_unlock(&iftypes_guard);
132 if (table_value != NULL)
133 ret = *(int *)table_value;
138 static void free_iftypes_tree(GTree *iftypes_tree)
140 g_tree_destroy(iftypes_tree);
143 static void iface_stat_allowance(void)
146 for (i = 0; i < ARRAY_SIZE(iface_stat); ++i)
150 static resourced_iface_type get_predefined_iftype(const char *ifname)
152 struct iface_relation *relation;
154 gslist_for_each_item(iter, ifnames_relations) {
155 relation = (struct iface_relation *)iter->data;
156 if (strstr(ifname, relation->ifname))
157 return relation->iftype;
159 _D("Even in predefined interface name list, interface types wasn't "
160 " find for %s", ifname);
161 return RESOURCED_IFACE_UNKNOWN;
164 static resourced_iface_type read_iftype(const char *iface)
166 char buffer[UNIX_PATH_MAX];
171 resourced_iface_type ret = RESOURCED_IFACE_UNKNOWN;
173 snprintf(buffer, UNIX_PATH_MAX, UEVENT_FMT, iface);
174 uevent = fopen(buffer, "r");
179 while (!feof(uevent)) {
180 if (fgets(buffer, UNIX_PATH_MAX, uevent) == NULL)
182 key_buffer = strtok_r(buffer, UEVENT_DELIM, &saveptr);
183 value_buffer = strtok_r(NULL, UEVENT_DELIM, &saveptr);
184 if (strcmp(key_buffer, DEVTYPE_KEY) != 0)
186 ret = convert_iftype(value_buffer);
192 /* work around, in case of missing DEVTYPE field */
193 if (ret == RESOURCED_IFACE_UNKNOWN)
194 ret = get_predefined_iftype(iface);
199 static void reset_tree(GTree *new, GTree **old,
200 pthread_rwlock_t *guard)
202 GTree *release = *old;
204 pthread_rwlock_wrlock(guard);
206 pthread_rwlock_unlock(guard);
208 free_iftypes_tree(release);
211 bool is_address_exists(const char *name)
217 fd = socket(AF_INET, SOCK_DGRAM, 0);
219 memset(&ifr, 0, sizeof(struct ifreq));
220 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)-1);
221 return ioctl(fd, SIOCGIFADDR, &ifr) == 0;
222 #endif /* SIOCDIFADDR */
226 static int fill_ifaces_relation(struct parse_result *result,
227 void UNUSED *user_data)
229 struct iface_relation *relation;
230 if (strcmp(result->section, IFACES_TYPE_SECTION))
231 return RESOURCED_ERROR_NONE;
233 relation = (struct iface_relation *)malloc(sizeof(struct iface_relation));
235 ret_value_msg_if(relation == NULL, RESOURCED_ERROR_NONE,
236 "Failed to allocated memory!");
238 relation->iftype = convert_iftype(result->name);
239 STRING_SAVE_COPY(relation->ifname, result->value);
241 ifnames_relations = g_slist_prepend(ifnames_relations, relation);
242 return RESOURCED_ERROR_NONE;
245 int init_iftype(void)
249 resourced_iface_type iftype;
250 struct if_nameindex *ids = if_nameindex();
251 GTree *iftypes_next = create_iface_tree();
252 GTree *ifnames_next = create_iface_tree();
255 strerror_r(errno, buf, sizeof(buf));
256 _E("Failed to initialize iftype table! errno: %d, %s",
258 return RESOURCED_ERROR_FAIL;
261 if (!ifnames_relations) {
262 ret = config_parse(NET_INTERFACE_NAMES_FILE,
263 fill_ifaces_relation, NULL);
265 _D("Can't parse config file %s",
266 NET_INTERFACE_NAMES_FILE);
269 iface_stat_allowance();
271 for (i = 0; ids[i].if_index != 0; ++i) {
272 if (!is_address_exists(ids[i].if_name))
274 iftype = read_iftype(ids[i].if_name);
275 put_iftype_to_tree(iftypes_next, ids[i].if_index, iftype);
276 /* we know here iftype/ids[i].if_name, lets populate
278 put_ifname_to_tree(ifnames_next, ids[i].if_name, iftype);
279 _D("ifname %s, ifype %d", ids[i].if_name, iftype);
282 /* Do not forget to free the memory */
283 if_freenameindex(ids);
285 reset_tree(iftypes_next, &iftypes, &iftypes_guard);
286 reset_tree(ifnames_next, &ifnames, &ifnames_guard);
287 return RESOURCED_ERROR_NONE;
290 void finalize_iftypes(void)
292 reset_tree(NULL, &iftypes, &iftypes_guard);
293 reset_tree(NULL, &ifnames, &ifnames_guard);
294 g_slist_free_full(ifnames_relations, free);
297 resourced_iface_type convert_iftype(const char *buffer)
300 _E("Malloc of answer_get_stat failed\n");
301 return RESOURCED_IFACE_UNKNOWN;
304 if (strcmp(buffer, DATACALL_VALUE) == 0)
305 return RESOURCED_IFACE_DATACALL;
307 if (strcmp(buffer, WIFI_VALUE) == 0)
308 return RESOURCED_IFACE_WIFI;
310 if (strcmp(buffer, BLUETOOTH_VALUE) == 0)
311 return RESOURCED_IFACE_BLUETOOTH;
313 if (strcmp(buffer, WIRED_VALUE) == 0)
314 return RESOURCED_IFACE_WIRED;
315 if (strcmp(buffer, ALL_NET_IFACE_VALUE) == 0)
316 return RESOURCED_IFACE_ALL;
317 return RESOURCED_IFACE_UNKNOWN;
320 int is_allowed_ifindex(int ifindex)
322 return iface_stat[get_iftype(ifindex)];
325 resourced_iface_type get_iftype(int ifindex)
327 return get_iftype_from_tree(iftypes, ifindex);
330 static gboolean print_ifname(gpointer key, gpointer value, gpointer data)
332 _D("ifname %s", (char *)value);
336 static char *get_ifname_from_tree(GTree *ifnames_tree, int iftype)
340 ret_value_msg_if(!ifnames_tree, NULL, "Please provide valid argument!");
342 pthread_rwlock_rdlock(&ifnames_guard);
343 ret = (char *)g_tree_lookup(ifnames_tree, (gpointer)iftype);
344 pthread_rwlock_unlock(&ifnames_guard);
346 g_tree_foreach(ifnames_tree, print_ifname, NULL);
351 char *get_iftype_name(resourced_iface_type iftype)
353 return get_ifname_from_tree(ifnames, iftype);
356 static gboolean search_loopback(gpointer key,
360 int *res = (int *)data;
363 *res = *(int *)value == RESOURCED_IFACE_UNKNOWN ? TRUE : FALSE;
367 static bool is_only_loopback(GTree *iftypes_tree)
369 int nodes = g_tree_nnodes(iftypes_tree);
375 g_tree_foreach(iftypes_tree, search_loopback, &res);
379 void for_each_ifindex(ifindex_iterator iter, void(*empty_func)(void *),
382 pthread_rwlock_rdlock(&iftypes_guard);
383 if (!is_only_loopback(iftypes))
384 g_tree_foreach(iftypes, (GTraverseFunc)iter, data);
388 pthread_rwlock_unlock(&iftypes_guard);
391 void set_wifi_allowance(const resourced_option_state wifi_option)
393 iface_stat[RESOURCED_IFACE_WIFI] = wifi_option == RESOURCED_OPTION_ENABLE ? 1 : 0;
396 void set_datacall_allowance(const resourced_option_state datacall_option)
398 iface_stat[RESOURCED_IFACE_DATACALL] = datacall_option == RESOURCED_OPTION_ENABLE ? 1 : 0;