Fix mismatched function call
[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         MESH_LOGD("Interface configuration for mesh network :");
256         MESH_LOGD("  Base    : [%s]", info->base_interface);
257         MESH_LOGD("  Mesh    : [%s]", info->mesh_interface);
258         MESH_LOGD("  Bridge  : [%s]", info->bridge_interface);
259         MESH_LOGD("  SoftAP  : [%s]", info->softap_interface);
260         MESH_LOGD("  External: [%s]", info->external_interface);
261
262         return MESHD_ERROR_NONE;
263 }
264
265 static int _check_ethernet_cable_plugin_status(const char* interface,
266                 cable_state_e *status)
267 {
268         FILE *fd = NULL;
269         int ret = -1;
270         int rv = 0;
271         char error_buf[256] = {0, };
272         char file_path[256] = {0, };
273
274         snprintf(file_path, 256, "/sys/class/net/%s/carrier", interface);
275
276         if (0 == access(file_path, F_OK)) {
277                 fd = fopen(file_path, "r");
278                 if (fd == NULL) {
279                         MESH_LOGE("Error! Could not open /sys/class/net/%s/carrier file",
280                                         interface);
281                         return MESHD_ERROR_IO_ERROR;
282                 }
283         } else {
284                 MESH_LOGE("Error! Could not access /sys/class/net/%s/carrier file",
285                                 interface);
286                 return MESHD_ERROR_IO_ERROR;
287         }
288
289         errno = 0;
290         rv = fscanf(fd, "%d", &ret);
291         if (rv < 0) {
292                 strerror_r(errno, error_buf, 256);
293                 MESH_LOGE("Error! Failed to read from file, rv:[%d], error:[%s]",
294                                 rv, error_buf);
295                 fclose(fd);
296                 return MESHD_ERROR_IO_ERROR;
297         }
298
299         if (ret == 1) {
300                 MESH_LOGD("/sys/class/net/%s/carrier : [%d]", interface, ret);
301                 *status = ETHERNET_CABLE_ATTACHED;
302         } else if (ret == 0) {
303                 MESH_LOGD("/sys/class/net/%s/carrier : [%d]", interface, ret);
304                 *status = ETHERNET_CABLE_DETACHED;
305         }
306
307         fclose(fd);
308         return MESHD_ERROR_NONE;
309 }
310
311 int mesh_interface_check_external_exists(const char* external_interface, bool *state)
312 {
313         /* TODO: Current logic checks only ethernet interface.
314                         This logic should consider wireless interface if can */
315         int ret = MESHD_ERROR_NONE;
316         cable_state_e cable_state = ETHERNET_CABLE_DETACHED;
317
318         if (NULL == external_interface || NULL == state) {
319                 return MESHD_ERROR_INVALID_PARAMETER;
320         }
321
322         bool ex = _check_interface_exists(external_interface);
323         if (FALSE == ex) {
324                 MESH_LOGE("External interface[%s] was not found.", external_interface);
325                 return MESHD_ERROR_INVALID_PARAMETER;
326         }
327
328         /* If external interface seems Ethernet, check cable state */
329         if (g_str_has_prefix(external_interface, "eth")) {
330                 ret = _check_ethernet_cable_plugin_status(external_interface, &cable_state);
331                 if (MESHD_ERROR_NONE != ret) {
332                         MESH_LOGE("Failed to get Ethernet cable state");
333                         return MESHD_ERROR_OPERATION_FAILED;
334                 }
335         }
336
337         *state = FALSE;
338         if (ETHERNET_CABLE_ATTACHED == cable_state) {
339                 *state = TRUE;
340         }
341
342         return MESHD_ERROR_NONE;
343 }