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];
170 resourced_iface_type ret = RESOURCED_IFACE_UNKNOWN;
172 snprintf(buffer, UNIX_PATH_MAX, UEVENT_FMT, iface);
173 uevent = fopen(buffer, "r");
178 while (!feof(uevent)) {
179 if (fgets(buffer, UNIX_PATH_MAX, uevent) == NULL)
181 key_buffer = strtok(buffer, UEVENT_DELIM);
182 value_buffer = strtok(NULL, UEVENT_DELIM);
183 if (strcmp(key_buffer, DEVTYPE_KEY) != 0)
185 ret = convert_iftype(value_buffer);
191 /* work around, in case of missing DEVTYPE field */
192 if (ret == RESOURCED_IFACE_UNKNOWN)
193 ret = get_predefined_iftype(iface);
198 static void reset_tree(GTree *new, GTree **old,
199 pthread_rwlock_t *guard)
201 GTree *release = *old;
203 pthread_rwlock_wrlock(guard);
205 pthread_rwlock_unlock(guard);
207 free_iftypes_tree(release);
210 bool is_address_exists(const char *name)
216 fd = socket(AF_INET, SOCK_DGRAM, 0);
218 memset(&ifr, 0, sizeof(struct ifreq));
219 strcpy(ifr.ifr_name, name);
220 return ioctl(fd, SIOCGIFADDR, &ifr) == 0;
221 #endif /* SIOCDIFADDR */
225 static int fill_ifaces_relation(struct parse_result *result,
226 void UNUSED *user_data)
228 struct iface_relation *relation;
229 if (strcmp(result->section, IFACES_TYPE_SECTION))
230 return RESOURCED_ERROR_NONE;
232 relation = (struct iface_relation *)malloc(sizeof(struct iface_relation));
234 ret_value_msg_if(relation == NULL, RESOURCED_ERROR_NONE,
235 "Failed to allocated memory!");
237 relation->iftype = convert_iftype(result->name);
238 STRING_SAVE_COPY(relation->ifname, result->value);
240 ifnames_relations = g_slist_prepend(ifnames_relations, relation);
241 return RESOURCED_ERROR_NONE;
244 int init_iftype(void)
247 resourced_iface_type iftype;
248 struct if_nameindex *ids = if_nameindex();
249 GTree *iftypes_next = create_iface_tree();
250 GTree *ifnames_next = create_iface_tree();
253 _E("Failed to initialize iftype table! errno: %d, %s",
254 errno, strerror(errno));
255 return RESOURCED_ERROR_FAIL;
258 if (!ifnames_relations) {
259 ret = config_parse(NET_INTERFACE_NAMES_FILE,
260 fill_ifaces_relation, NULL);
262 _D("Can't parse config file %s",
263 NET_INTERFACE_NAMES_FILE);
266 iface_stat_allowance();
268 for (i = 0; ids[i].if_index != 0; ++i) {
269 if (!is_address_exists(ids[i].if_name))
271 iftype = read_iftype(ids[i].if_name);
272 put_iftype_to_tree(iftypes_next, ids[i].if_index, iftype);
273 /* we know here iftype/ids[i].if_name, lets populate
275 put_ifname_to_tree(ifnames_next, ids[i].if_name, iftype);
276 _D("ifname %s, ifype %d", ids[i].if_name, iftype);
279 /* Do not forget to free the memory */
280 if_freenameindex(ids);
282 reset_tree(iftypes_next, &iftypes, &iftypes_guard);
283 reset_tree(ifnames_next, &ifnames, &ifnames_guard);
284 return RESOURCED_ERROR_NONE;
287 void finalize_iftypes(void)
289 reset_tree(NULL, &iftypes, &iftypes_guard);
290 reset_tree(NULL, &ifnames, &ifnames_guard);
291 g_slist_free_full(ifnames_relations, free);
294 resourced_iface_type convert_iftype(const char *buffer)
297 _E("Malloc of answer_get_stat failed\n");
298 return RESOURCED_IFACE_UNKNOWN;
301 if (strcmp(buffer, DATACALL_VALUE) == 0)
302 return RESOURCED_IFACE_DATACALL;
304 if (strcmp(buffer, WIFI_VALUE) == 0)
305 return RESOURCED_IFACE_WIFI;
307 if (strcmp(buffer, BLUETOOTH_VALUE) == 0)
308 return RESOURCED_IFACE_BLUETOOTH;
310 if (strcmp(buffer, WIRED_VALUE) == 0)
311 return RESOURCED_IFACE_WIRED;
312 if (strcmp(buffer, ALL_NET_IFACE_VALUE) == 0)
313 return RESOURCED_IFACE_ALL;
314 return RESOURCED_IFACE_UNKNOWN;
317 int is_allowed_ifindex(int ifindex)
319 return iface_stat[get_iftype(ifindex)];
322 resourced_iface_type get_iftype(int ifindex)
324 return get_iftype_from_tree(iftypes, ifindex);
327 static gboolean print_ifname(gpointer key, gpointer value, gpointer data)
329 _D("ifname %s", (char *)value);
333 static char *get_ifname_from_tree(GTree *ifnames_tree, int iftype)
337 ret_value_msg_if(!ifnames_tree, NULL, "Please provide valid argument!");
339 pthread_rwlock_rdlock(&ifnames_guard);
340 ret = (char *)g_tree_lookup(ifnames_tree, (gpointer)iftype);
341 pthread_rwlock_unlock(&ifnames_guard);
343 g_tree_foreach(ifnames_tree, print_ifname, NULL);
348 char *get_iftype_name(resourced_iface_type iftype)
350 return get_ifname_from_tree(ifnames, iftype);
353 static gboolean search_loopback(gpointer key,
357 int *res = (int *)data;
360 *res = *(int *)value == RESOURCED_IFACE_UNKNOWN ? TRUE : FALSE;
364 static bool is_only_loopback(GTree *iftypes_tree)
366 int nodes = g_tree_nnodes(iftypes_tree);
372 g_tree_foreach(iftypes_tree, search_loopback, &res);
376 void for_each_ifindex(ifindex_iterator iter, void(*empty_func)(void *),
379 pthread_rwlock_rdlock(&iftypes_guard);
380 if (!is_only_loopback(iftypes))
381 g_tree_foreach(iftypes, (GTraverseFunc)iter, data);
385 pthread_rwlock_unlock(&iftypes_guard);
388 void set_wifi_allowance(const resourced_option_state wifi_option)
390 iface_stat[RESOURCED_IFACE_WIFI] = wifi_option == RESOURCED_OPTION_ENABLE ? 1 : 0;
393 void set_datacall_allowance(const resourced_option_state datacall_option)
395 iface_stat[RESOURCED_IFACE_DATACALL] = datacall_option == RESOURCED_OPTION_ENABLE ? 1 : 0;