Implement sending 'enable ethernet' to the ConnMan
[platform/core/connectivity/wifi-mesh-manager.git] / src / mesh-interface.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  */
19 #include <glib.h>
20 #include <gio/gio.h>
21 #ifdef USE_UDEV_MONITOR
22 #include <gudev/gudev.h>
23 #endif /* USE_UDEV_MONITOR */
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 #include <net/if.h>
30 #include <arpa/inet.h>
31 #include <sys/ioctl.h>
32 #include <sys/wait.h>
33
34 #include <errno.h>
35
36 #include "mesh.h"
37 #include "mesh-log.h"
38 #include "mesh-util.h"
39 #include "mesh-service.h"
40 #include "mesh-interface.h"
41
42 #define IPV4_MAX_LENGTH   16
43 #define BUF_LENGTH        256
44
45 #define MESH_DEFAULT_BASE_INTERFACE      "wlan0"
46 #define MESH_DEFAULT_MESH_INTERFACE      "mesh0"
47 #define MESH_DEFAULT_BRIDGE_INTERFACE    "br0"
48 #define MESH_DEFAULT_EXTERNAL_INTERFACE  "eth0"
49 #define MESH_DEFAULT_SOFTAP_INTERFACE    "wlan1"
50
51 typedef enum {
52         ETHERNET_CABLE_DETACHED = 0,
53         ETHERNET_CABLE_ATTACHED
54 } cable_state_e;
55
56 int mesh_interface_set(const char *interface, const char* ip_addr,
57                 mesh_set_interface_type_e type)
58 {
59         int sock = 0;
60         struct ifreq ifr;
61         int ret = 0;
62
63         char ip[IPV4_MAX_LENGTH] = {0,};
64         char buf[BUF_LENGTH] = {0,};
65
66         if (interface == NULL) {
67                 MESH_LOGE("Invalid interface name !");
68                 return MESHD_ERROR_INVALID_PARAMETER;
69         }
70
71         sock = socket(AF_INET, SOCK_STREAM, 0);
72         if (sock < 0) {
73                 MESH_LOGE("Cannot open network interface socket");
74                 return MESHD_ERROR_IO_ERROR;
75         }
76
77         MESH_LOGD("Initialize interface [%s]...", interface);
78         snprintf(ifr.ifr_name, IFNAMSIZ, "%s", interface);
79
80         /* Set IP Address */
81         if (NULL != ip_addr) {
82                 struct sockaddr_in sai;
83                 memset(&sai, 0, sizeof(struct sockaddr_in));
84                 sai.sin_family = AF_INET;
85                 sai.sin_port = 0;
86                 snprintf(ip, IPV4_MAX_LENGTH, "%s", ip_addr);
87
88                 MESH_LOGD("Setting IP address: [%s]\n", ip);
89                 if (!inet_aton(ip, &sai.sin_addr)) {
90                         MESH_LOGE("Failed to convert ip address");
91                         close(sock);
92                         return MESHD_ERROR_OPERATION_FAILED;
93                 }
94
95                 memcpy(&ifr.ifr_addr, &sai, sizeof(sai));
96
97                 ret = ioctl(sock, SIOCSIFADDR, &ifr);
98                 if (ret < 0) {
99                         (void) strerror_r(errno, buf, BUF_LENGTH);
100                         MESH_LOGE("Failed to set IP[%s] for interface[%s] : %s",
101                                 ip, ifr.ifr_name, buf);
102                 }
103         }
104
105         /* Get status flag */
106         if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
107                 (void) strerror_r(errno, buf, BUF_LENGTH);
108                 MESH_LOGE("Failed to get interface[%s] status : %s",
109                         ifr.ifr_name, buf);
110         }
111         snprintf(ifr.ifr_name, IFNAMSIZ, "%s", interface);
112
113         /* Set status flag */
114         if (MESH_INTERFACE_UP == type) {
115                 ifr.ifr_flags |= (IFF_UP);
116                 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
117                         (void) strerror_r(errno, buf, BUF_LENGTH);
118                         MESH_LOGE("Failed to change interface[%s] status UP : %s",
119                                 ifr.ifr_name, buf);
120                 }
121         } else if (MESH_INTERFACE_DOWN == type) {
122                 ifr.ifr_flags &= (~IFF_UP);
123                 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
124                         (void) strerror_r(errno, buf, BUF_LENGTH);
125                         MESH_LOGE("Failed to change interface[%s] status DOWN : %s",
126                                 ifr.ifr_name, buf);
127                 }
128         } else {
129                 MESH_LOGD("Do not change up/down status");
130         }
131
132         close(sock);
133         return MESHD_ERROR_NONE;
134 }
135
136 #if 0
137 /* Returns interface name in sequence order which is exists */
138 static char* _get_interface_exists_in_seq(const char* prefix)
139 {
140         char *res = NULL;
141         char buf[32];
142         int ret;
143         int i = 0;
144         const int IF_INDEX_MAX = 9;
145
146         for (i = 0; i <= IF_INDEX_MAX; i++) {
147                 snprintf(buf, sizeof(buf), "/sys/class/net/%s%d", prefix, i);
148
149                 ret = access(buf, F_OK);
150                 if (ret >= 0) {
151                         /* This name is exists. use it */
152                         snprintf(buf, sizeof(buf), "%s%d", prefix, i);
153                         res = g_strdup(buf);
154                         MESH_LOGD("  use [%s]", res);
155                         break;
156                 }
157         }
158
159         return res;
160 }
161
162 /* Returns interface name in sequence order which is exists */
163 static char* _get_interface_not_exists_in_seq(const char* prefix)
164 {
165         char *res = NULL;
166         char buf[32];
167         int ret;
168         int i = 0;
169         const int IF_INDEX_MAX = 9;
170
171         for (i = 0; i <= IF_INDEX_MAX; i++) {
172                 snprintf(buf, sizeof(buf), "/sys/class/net/%s%d", prefix, i);
173
174                 ret = access(buf, F_OK);
175                 if (ret < 0) {
176                         /* This name is not exists. use it */
177                         snprintf(buf, sizeof(buf), "%s%d", prefix, i);
178                         res = g_strdup(buf);
179                         MESH_LOGD("  use [%s]", res);
180                         break;
181                 }
182         }
183
184         return res;
185 }
186 #endif
187
188 static bool _check_interface_exists(const char* if_name)
189 {
190         int ret;
191         char buf[32];
192         int i = 0;
193         const int IF_INDEX_MAX = 9;
194
195         for (i = 0; i <= IF_INDEX_MAX; i++) {
196                 snprintf(buf, sizeof(buf), "/sys/class/net/%s", if_name);
197
198                 ret = access(buf, F_OK);
199                 if (ret >= 0) {
200                         /* This name is exists. */
201                         return true;
202                 }
203         }
204
205         return false;
206 }
207
208 /* Check if interface is bridged */
209 static bool _check_bridge_interface_exists(const char* bridge, const char* if_name)
210 {
211         int ret;
212         char buf[32];
213         int i = 0;
214         const int IF_INDEX_MAX = 9;
215
216         for (i = 0; i <= IF_INDEX_MAX; i++) {
217                 snprintf(buf, sizeof(buf), "/sys/class/net/%s/brif/%s", bridge, if_name);
218
219                 ret = access(buf, F_OK);
220                 if (ret >= 0) {
221                         /* This name is exists. */
222                         return true;
223                 }
224         }
225
226         return false;
227 }
228
229 char* mesh_interface_get_address(const char* if_name)
230 {
231         FILE *pf;
232         char buf[32] = { 0, };
233         char *result = NULL;
234
235         snprintf(buf, sizeof(buf), "/sys/class/net/%s/address", if_name);
236         pf = fopen(buf, "r");
237         if (NULL != pf) {
238                 fgets(buf, 31, pf);
239                 MESH_LOGD("Interface[%s] address[%s]", if_name, buf);
240
241                 if (strlen(buf) > 0)
242                         result = g_strdup(buf);
243
244                 fclose(pf);
245         }
246
247         return result;
248 }
249
250 #ifdef USE_UDEV_MONITOR
251 static void __on_uevent(GUdevClient *client, gchar *action, GUdevDevice *device, gpointer user_data)
252 {
253         NOTUSED(client);
254         NOTUSED(device);
255         NOTUSED(user_data);
256
257         MESH_LOGD("KSR : action:[%s]", action);
258 }
259
260 static void _interface_status_monitor_init(mesh_interface_s *info)
261 {
262         const gchar *subsystem[] = {"net", NULL};
263
264         info->udev_client = g_udev_client_new(subsystem);
265         g_signal_connect(info->udev_client, "uevent", G_CALLBACK(__on_uevent), info);
266 }
267 #endif /* USE_UDEV_MONITOR */
268
269 int mesh_interface_initialize(mesh_interface_s *info)
270 {
271         if (NULL == info) {
272                 MESH_LOGE("Invalid parameter");
273                 return MESHD_ERROR_INVALID_PARAMETER;
274         }
275
276         info->bridge_interface = g_strdup(MESH_DEFAULT_BRIDGE_INTERFACE);
277         if (NULL == info->bridge_interface) {
278                 MESH_LOGE("Failed to get bridge interface !");
279                 return MESHD_ERROR_OPERATION_FAILED;
280         }
281
282         info->base_interface = g_strdup(MESH_DEFAULT_BASE_INTERFACE);
283         if (NULL == info->bridge_interface) {
284                 MESH_LOGE("Failed to get base interface !");
285                 return MESHD_ERROR_OPERATION_FAILED;
286         }
287
288         info->mesh_interface = g_strdup(MESH_DEFAULT_MESH_INTERFACE);
289         if (NULL == info->bridge_interface) {
290                 MESH_LOGE("Failed to get mesh interface !");
291                 return MESHD_ERROR_OPERATION_FAILED;
292         }
293
294         info->softap_interface = g_strdup(MESH_DEFAULT_SOFTAP_INTERFACE);
295         info->external_interface = g_strdup(MESH_DEFAULT_EXTERNAL_INTERFACE);
296
297         MESH_LOGD("Interface configuration for mesh network :");
298         MESH_LOGD("  Base    : [%s]", info->base_interface);
299         MESH_LOGD("  Mesh    : [%s]", info->mesh_interface);
300         MESH_LOGD("  Bridge  : [%s]", info->bridge_interface);
301         MESH_LOGD("  SoftAP  : [%s]", info->softap_interface);
302         MESH_LOGD("  External: [%s]", info->external_interface);
303
304 #ifdef USE_UDEV_MONITOR
305         _interface_status_monitor_init(info);
306 #endif /* USE_UDEV_MONITOR */
307         return MESHD_ERROR_NONE;
308 }
309
310 static int _check_ethernet_cable_plugin_status(const char* interface,
311                 cable_state_e *status)
312 {
313         FILE *fd = NULL;
314         int ret = -1;
315         int rv = 0;
316         char error_buf[256] = {0, };
317         char file_path[256] = {0, };
318
319         snprintf(file_path, 256, "/sys/class/net/%s/carrier", interface);
320
321         if (0 == access(file_path, F_OK)) {
322                 fd = fopen(file_path, "r");
323                 if (fd == NULL) {
324                         MESH_LOGE("Error! Could not open /sys/class/net/%s/carrier file",
325                                         interface);
326                         return MESHD_ERROR_IO_ERROR;
327                 }
328         } else {
329                 MESH_LOGE("Error! Could not access /sys/class/net/%s/carrier file",
330                                 interface);
331                 return MESHD_ERROR_IO_ERROR;
332         }
333
334         errno = 0;
335         rv = fscanf(fd, "%d", &ret);
336         if (rv < 0) {
337                 strerror_r(errno, error_buf, 256);
338                 MESH_LOGE("Error! Failed to read from file, rv:[%d], error:[%s]",
339                                 rv, error_buf);
340                 fclose(fd);
341                 return MESHD_ERROR_IO_ERROR;
342         }
343
344         if (ret == 1) {
345                 MESH_LOGD("/sys/class/net/%s/carrier : [%d]", interface, ret);
346                 *status = ETHERNET_CABLE_ATTACHED;
347         } else if (ret == 0) {
348                 MESH_LOGD("/sys/class/net/%s/carrier : [%d]", interface, ret);
349                 *status = ETHERNET_CABLE_DETACHED;
350         }
351
352         fclose(fd);
353         return MESHD_ERROR_NONE;
354 }
355
356 int mesh_interface_check_external_exists(const char* external_interface, bool *state)
357 {
358         /* TODO: Current logic checks only ethernet interface.
359                         This logic should consider wireless interface if can */
360         int ret = MESHD_ERROR_NONE;
361         cable_state_e cable_state = ETHERNET_CABLE_DETACHED;
362
363         if (NULL == external_interface || NULL == state)
364                 return MESHD_ERROR_INVALID_PARAMETER;
365
366         bool ex = _check_interface_exists(external_interface);
367         if (FALSE == ex) {
368                 MESH_LOGE("External interface[%s] was not found.", external_interface);
369                 return MESHD_ERROR_INVALID_PARAMETER;
370         }
371
372         /* If external interface seems Ethernet, check cable state */
373         if (g_str_has_prefix(external_interface, "eth")) {
374                 ret = _check_ethernet_cable_plugin_status(external_interface, &cable_state);
375                 if (MESHD_ERROR_NONE != ret) {
376                         MESH_LOGE("Failed to get Ethernet cable state");
377                         return MESHD_ERROR_OPERATION_FAILED;
378                 }
379         }
380
381         *state = FALSE;
382         if (ETHERNET_CABLE_ATTACHED == cable_state)
383                 *state = TRUE;
384
385         return MESHD_ERROR_NONE;
386 }
387
388 int mesh_interface_check(const char* interface)
389 {
390         bool ex = FALSE;
391
392         if (NULL == interface || strlen(interface) == 0)
393                 return MESHD_ERROR_INVALID_PARAMETER;
394
395         ex = _check_interface_exists(interface);
396         if (FALSE == ex) {
397                 MESH_LOGE("Interface[%s] was not found.", interface);
398                 return MESHD_ERROR_NO_DATA;
399         }
400
401         return MESHD_ERROR_NONE;
402 }
403
404 int mesh_interface_check_bridge_interface_exists(const char* bridge, const char* interface)
405 {
406         bool ex = FALSE;
407
408         if (NULL == bridge || NULL == interface ||
409                 strlen(bridge) == 0 || strlen(interface) == 0)
410                 return MESHD_ERROR_INVALID_PARAMETER;
411
412         ex = _check_bridge_interface_exists(bridge, interface);
413         if (FALSE == ex) {
414                 MESH_LOGE("Interface[%s] was not found.", interface);
415                 return MESHD_ERROR_NO_DATA;
416         }
417
418         return MESHD_ERROR_NONE;
419 }
420