Fix interface detection error after 2nd enable method.
[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
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include <net/if.h>
28 #include <arpa/inet.h>
29 #include <sys/ioctl.h>
30 #include <sys/wait.h>
31
32 #include <errno.h>
33
34 #include "mesh.h"
35 #include "mesh-log.h"
36 #include "mesh-util.h"
37 #include "mesh-service.h"
38 #include "mesh-interface.h"
39
40 #define IPV4_MAX_LENGTH   16
41 #define BUF_LENGTH        256
42
43 #define MESH_DEFAULT_BASE_INTERFACE      "wlan0"
44 #define MESH_DEFAULT_MESH_INTERFACE      "mesh0"
45 #define MESH_DEFAULT_BRIDGE_INTERFACE    "br0"
46 #define MESH_DEFAULT_EXTERNAL_INTERFACE  "eth0"
47 #define MESH_DEFAULT_SOFTAP_INTERFACE    "wlan1"
48
49 typedef enum {
50         ETHERNET_CABLE_DETACHED = 0,
51         ETHERNET_CABLE_ATTACHED
52 } cable_state_e;
53
54 int mesh_interface_set(const char *interface, const char* ip_addr,
55                 mesh_set_interface_type_e type)
56 {
57         int sock = 0;
58         struct ifreq ifr;
59         int ret = 0;
60
61         char ip[IPV4_MAX_LENGTH] = {0,};
62         char buf[BUF_LENGTH] = {0,};
63
64         if (interface == NULL) {
65                 MESH_LOGE("Invalid interface name !");
66                 return MESHD_ERROR_INVALID_PARAMETER;
67         }
68
69         sock = socket(AF_INET, SOCK_STREAM, 0);
70         if (sock < 0) {
71                 MESH_LOGE("Cannot open network interface socket");
72                 return MESHD_ERROR_IO_ERROR;
73         }
74
75         MESH_LOGD("Initialize interface [%s]...", interface);
76         snprintf(ifr.ifr_name, IFNAMSIZ, "%s", interface);
77
78         /* Set IP Address */
79         if (NULL != ip_addr) {
80                 struct sockaddr_in sai;
81                 memset(&sai, 0, sizeof(struct sockaddr_in));
82                 sai.sin_family = AF_INET;
83                 sai.sin_port = 0;
84                 snprintf(ip, IPV4_MAX_LENGTH, "%s", ip_addr);
85
86                 MESH_LOGD("Setting IP address: [%s]\n", ip);
87                 if (!inet_aton(ip, &sai.sin_addr)) {
88                         MESH_LOGE("Failed to convert ip address");
89                         close(sock);
90                         return MESHD_ERROR_OPERATION_FAILED;
91                 }
92
93                 memcpy(&ifr.ifr_addr, &sai, sizeof(sai));
94
95                 ret = ioctl(sock, SIOCSIFADDR, &ifr);
96                 if (ret < 0) {
97                         (void) strerror_r(errno, buf, BUF_LENGTH);
98                         MESH_LOGE("Failed to set IP[%s] for interface[%s] : %s",
99                                 ip, ifr.ifr_name, buf);
100                 }
101         }
102
103         /* Get status flag */
104         if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
105                 (void) strerror_r(errno, buf, BUF_LENGTH);
106                 MESH_LOGE("Failed to get interface[%s] status : %s",
107                         ifr.ifr_name, buf);
108         }
109         snprintf(ifr.ifr_name, IFNAMSIZ, "%s", interface);
110
111         /* Set status flag */
112         if (MESH_INTERFACE_UP == type) {
113                 ifr.ifr_flags |= (IFF_UP);
114                 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
115                         (void) strerror_r(errno, buf, BUF_LENGTH);
116                         MESH_LOGE("Failed to change interface[%s] status UP : %s",
117                                 ifr.ifr_name, buf);
118                 }
119         } else if (MESH_INTERFACE_DOWN == type) {
120                 ifr.ifr_flags &= (~IFF_UP);
121                 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
122                         (void) strerror_r(errno, buf, BUF_LENGTH);
123                         MESH_LOGE("Failed to change interface[%s] status DOWN : %s",
124                                 ifr.ifr_name, buf);
125                 }
126         } else {
127                 MESH_LOGD("Do not change up/down status");
128         }
129
130         close(sock);
131         return MESHD_ERROR_NONE;
132 }
133
134 #if 0
135 /* Returns interface name in sequence order which is exists */
136 static char* _get_interface_exists_in_seq(const char* prefix)
137 {
138         char *res = NULL;
139         char buf[32];
140         int ret;
141         int i = 0;
142         const int IF_INDEX_MAX = 9;
143
144         for (i = 0; i <= IF_INDEX_MAX; i++) {
145                 snprintf(buf, sizeof(buf), "/sys/class/net/%s%d", prefix, i);
146
147                 ret = access(buf, F_OK);
148                 if (ret >= 0) {
149                         /* This name is exists. use it */
150                         snprintf(buf, sizeof(buf), "%s%d", prefix, i);
151                         res = g_strdup(buf);
152                         MESH_LOGD("  use [%s]", res);
153                         break;
154                 }
155         }
156
157         return res;
158 }
159
160 /* Returns interface name in sequence order which is exists */
161 static char* _get_interface_not_exists_in_seq(const char* prefix)
162 {
163         char *res = NULL;
164         char buf[32];
165         int ret;
166         int i = 0;
167         const int IF_INDEX_MAX = 9;
168
169         for (i = 0; i <= IF_INDEX_MAX; i++) {
170                 snprintf(buf, sizeof(buf), "/sys/class/net/%s%d", prefix, i);
171
172                 ret = access(buf, F_OK);
173                 if (ret < 0) {
174                         /* This name is not exists. use it */
175                         snprintf(buf, sizeof(buf), "%s%d", prefix, i);
176                         res = g_strdup(buf);
177                         MESH_LOGD("  use [%s]", res);
178                         break;
179                 }
180         }
181
182         return res;
183 }
184 #endif
185
186 /* Returns interface name in sequence order which is exists */
187 static bool _check_interface_exists(const char* if_name)
188 {
189         int ret;
190         char buf[32];
191         int i = 0;
192         const int IF_INDEX_MAX = 9;
193
194         for (i = 0; i <= IF_INDEX_MAX; i++) {
195                 snprintf(buf, sizeof(buf), "/sys/class/net/%s", if_name);
196
197                 ret = access(buf, F_OK);
198                 if (ret >= 0) {
199                         /* This name is exists. */
200                         return true;
201                 }
202         }
203
204         return false;
205 }
206
207 char* mesh_interface_get_address(const char* if_name)
208 {
209         FILE *pf;
210         char buf[32];
211         char *result = NULL;
212         int cnt = 0;
213
214         snprintf(buf, sizeof(buf), "/sys/class/net/%s/address", if_name);
215         pf = fopen(buf, "r");
216         if (NULL != pf) {
217                 cnt = fscanf(pf, "%s", buf);
218                 MESH_LOGD("Interface[%s] address[%s] %d", if_name, buf, cnt);
219                 result = g_strdup(buf);
220
221                 fclose(pf);
222         }
223
224         return result;
225 }
226
227 int mesh_interface_initialize(mesh_interface_s *info)
228 {
229         if (NULL == info) {
230                 MESH_LOGE("Invalid parameter");
231                 return MESHD_ERROR_INVALID_PARAMETER;
232         }
233
234         info->bridge_interface = g_strdup(MESH_DEFAULT_BRIDGE_INTERFACE);
235         if (NULL == info->bridge_interface) {
236                 MESH_LOGE("Failed to get bridge interface !");
237                 return MESHD_ERROR_OPERATION_FAILED;
238         }
239
240         info->base_interface = g_strdup(MESH_DEFAULT_BASE_INTERFACE);
241         if (NULL == info->bridge_interface) {
242                 MESH_LOGE("Failed to get base interface !");
243                 return MESHD_ERROR_OPERATION_FAILED;
244         }
245
246         info->mesh_interface = g_strdup(MESH_DEFAULT_MESH_INTERFACE);
247         if (NULL == info->bridge_interface) {
248                 MESH_LOGE("Failed to get mesh interface !");
249                 return MESHD_ERROR_OPERATION_FAILED;
250         }
251
252         info->softap_interface = g_strdup(MESH_DEFAULT_SOFTAP_INTERFACE);
253         info->external_interface = g_strdup(MESH_DEFAULT_EXTERNAL_INTERFACE);
254
255         return MESHD_ERROR_NONE;
256 }
257
258 static int _check_ethernet_cable_plugin_status(const char* interface,
259                 cable_state_e *status)
260 {
261         FILE *fd = NULL;
262         int ret = -1;
263         int rv = 0;
264         char error_buf[256] = {0, };
265         char file_path[256] = {0, };
266
267         snprintf(file_path, 256, "/sys/class/net/%s/carrier", interface);
268
269         if (0 == access(file_path, F_OK)) {
270                 fd = fopen(file_path, "r");
271                 if (fd == NULL) {
272                         MESH_LOGE("Error! Could not open /sys/class/net/%s/carrier file",
273                                         interface);
274                         return MESHD_ERROR_IO_ERROR;
275                 }
276         } else {
277                 MESH_LOGE("Error! Could not access /sys/class/net/%s/carrier file",
278                                 interface);
279                 return MESHD_ERROR_IO_ERROR;
280         }
281
282         errno = 0;
283         rv = fscanf(fd, "%d", &ret);
284         if (rv < 0) {
285                 strerror_r(errno, error_buf, 256);
286                 MESH_LOGE("Error! Failed to read from file, rv:[%d], error:[%s]",
287                                 rv, error_buf);
288                 fclose(fd);
289                 return MESHD_ERROR_IO_ERROR;
290         }
291
292         if (ret == 1) {
293                 MESH_LOGD("/sys/class/net/%s/carrier : [%d]", interface, ret);
294                 *status = ETHERNET_CABLE_ATTACHED;
295         } else if (ret == 0) {
296                 MESH_LOGD("/sys/class/net/%s/carrier : [%d]", interface, ret);
297                 *status = ETHERNET_CABLE_DETACHED;
298         }
299
300         fclose(fd);
301         return MESHD_ERROR_NONE;
302 }
303
304 int mesh_interface_check_external_exists(const char* external_interface, bool *state)
305 {
306         /* TODO: Current logic checks only ethernet interface.
307                         This logic should consider wireless interface if can */
308         int ret = MESHD_ERROR_NONE;
309         cable_state_e cable_state = ETHERNET_CABLE_DETACHED;
310
311         if (NULL == external_interface || NULL == state) {
312                 return MESHD_ERROR_INVALID_PARAMETER;
313         }
314
315         bool ex = _check_interface_exists(external_interface);
316         if (FALSE == ex) {
317                 MESH_LOGE("External interface[%s] was not found.", external_interface);
318                 return MESHD_ERROR_INVALID_PARAMETER;
319         }
320
321         /* If external interface seems Ethernet, check cable state */
322         if (g_str_has_prefix(external_interface, "eth")) {
323                 ret = _check_ethernet_cable_plugin_status(external_interface, &cable_state);
324                 if (MESHD_ERROR_NONE != ret) {
325                         MESH_LOGE("Failed to get Ethernet cable state");
326                         return MESHD_ERROR_OPERATION_FAILED;
327                 }
328         }
329
330         *state = FALSE;
331         if (ETHERNET_CABLE_ATTACHED == cable_state) {
332                 *state = TRUE;
333         }
334
335         return MESHD_ERROR_NONE;
336 }