Change the package name for haltests
[platform/core/connectivity/wifi-mesh-manager.git] / src / wmesh-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 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include <net/if.h>
27 #include <arpa/inet.h>
28 #include <sys/ioctl.h>
29 #include <sys/wait.h>
30
31 #include <errno.h>
32
33 #include "wmesh.h"
34 #include "wmesh-log.h"
35 #include "wmesh-util.h"
36 #include "wmesh-service.h"
37 #include "wmesh-interface.h"
38
39 #define IPV4_MAX_LENGTH   16
40 #define BUF_LENGTH        256
41
42 #define MESH_DEFAULT_BASE_INTERFACE      "wlan0"
43 #define MESH_DEFAULT_MESH_INTERFACE      "mesh0"
44 #define MESH_DEFAULT_BRIDGE_INTERFACE    "br0"
45 #define MESH_DEFAULT_EXTERNAL_INTERFACE  "eth0"
46 #define MESH_DEFAULT_SOFTAP_INTERFACE    "wlan1"
47
48 typedef enum {
49         ETHERNET_CABLE_DETACHED = 0,
50         ETHERNET_CABLE_ATTACHED
51 } cable_state_e;
52
53 /* LCOV_EXCL_START */
54 int wmesh_interface_set(const char *interface, const char* ip_addr,
55                 wmesh_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                 WMESH_LOGE("Invalid interface name !");
66                 return WMESHD_ERROR_INVALID_PARAMETER;
67         }
68
69         sock = socket(AF_INET, SOCK_STREAM, 0);
70         if (sock < 0) {
71                 WMESH_LOGE("Cannot open network interface socket");
72                 return WMESHD_ERROR_IO_ERROR;
73         }
74
75         WMESH_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                 WMESH_LOGD("Setting IP address: [%s]\n", ip);
87                 if (!inet_aton(ip, &sai.sin_addr)) {
88                         WMESH_LOGE("Failed to convert ip address");
89                         close(sock);
90                         return WMESHD_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                         WMESH_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                 WMESH_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 (WMESH_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                         WMESH_LOGE("Failed to change interface[%s] status UP : %s",
117                                 ifr.ifr_name, buf);
118                 }
119         } else if (WMESH_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                         WMESH_LOGE("Failed to change interface[%s] status DOWN : %s",
124                                 ifr.ifr_name, buf);
125                 }
126         } else {
127                 WMESH_LOGD("Do not change up/down status");
128         }
129
130         close(sock);
131         return WMESHD_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                         WMESH_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                         WMESH_LOGD("  use [%s]", res);
178                         break;
179                 }
180         }
181
182         return res;
183 }
184 #endif
185 /* LCOV_EXCL_STOP */
186
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; //LCOV_EXCL_LINE
205 }
206
207 /* Check if interface is bridged */
208 static bool _check_bridge_interface_exists(const char* bridge, const char* if_name)
209 {
210         int ret;
211         char buf[32];
212         int i = 0;
213         const int IF_INDEX_MAX = 9;
214
215         for (i = 0; i <= IF_INDEX_MAX; i++) {
216                 snprintf(buf, sizeof(buf), "/sys/class/net/%s/brif/%s", bridge, if_name);
217
218                 ret = access(buf, F_OK);
219                 if (ret >= 0) {
220                         /* This name is exists. */
221                         return true; //LCOV_EXCL_LINE
222                 }
223         }
224
225         return false; //LCOV_EXCL_LINE
226 }
227
228 /* LCOV_EXCL_START */
229 char* wmesh_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                 if (!fgets(buf, 31, pf) || ferror(pf) || feof(pf)) {
239                         WMESH_LOGE("Error open Inerface[%s]", if_name);
240                 } else {
241                         WMESH_LOGD("Interface[%s] address[%s]", if_name, buf);
242
243                         if (strlen(buf) > 0)
244                                 result = g_strdup(buf);
245                 }
246                 fclose(pf);
247         }
248
249         return result;
250 }
251 /* LCOV_EXCL_STOP */
252
253 int wmesh_interface_initialize(wmesh_interface_s *info)
254 {
255         if (NULL == info) {
256                 /* LCOV_EXCL_START */
257                 WMESH_LOGE("Invalid parameter");
258                 return WMESHD_ERROR_INVALID_PARAMETER;
259                 /* LCOV_EXCL_STOP */
260         }
261
262         info->bridge_interface = g_strdup(MESH_DEFAULT_BRIDGE_INTERFACE);
263         if (NULL == info->bridge_interface) {
264                 /* LCOV_EXCL_START */
265                 WMESH_LOGE("Failed to get bridge interface !");
266                 return WMESHD_ERROR_OPERATION_FAILED;
267                 /* LCOV_EXCL_STOP */
268         }
269
270         info->base_interface = g_strdup(MESH_DEFAULT_BASE_INTERFACE);
271         if (NULL == info->bridge_interface) {
272                 /* LCOV_EXCL_START */
273                 WMESH_LOGE("Failed to get base interface !");
274                 return WMESHD_ERROR_OPERATION_FAILED;
275                 /* LCOV_EXCL_STOP */
276         }
277
278         info->mesh_interface = g_strdup(MESH_DEFAULT_MESH_INTERFACE);
279         if (NULL == info->bridge_interface) {
280                 /* LCOV_EXCL_START */
281                 WMESH_LOGE("Failed to get mesh interface !");
282                 return WMESHD_ERROR_OPERATION_FAILED;
283                 /* LCOV_EXCL_STOP */
284         }
285
286         info->softap_interface = g_strdup(MESH_DEFAULT_SOFTAP_INTERFACE);
287         info->external_interface = g_strdup(MESH_DEFAULT_EXTERNAL_INTERFACE);
288
289         WMESH_LOGD("Interface configuration for mesh network :");
290         WMESH_LOGD("  Base    : [%s]", info->base_interface);
291         WMESH_LOGD("  Mesh    : [%s]", info->mesh_interface);
292         WMESH_LOGD("  Bridge  : [%s]", info->bridge_interface);
293         WMESH_LOGD("  SoftAP  : [%s]", info->softap_interface);
294         WMESH_LOGD("  External: [%s]", info->external_interface);
295
296         return WMESHD_ERROR_NONE;
297 }
298
299 static int _check_ethernet_cable_plugin_status(const char* interface,
300                 cable_state_e *status)
301 {
302         FILE *fd = NULL;
303         int ret = -1;
304         int rv = 0;
305         char error_buf[256] = {0, };
306         char file_path[256] = {0, };
307
308         snprintf(file_path, 256, "/sys/class/net/%s/carrier", interface);
309
310         if (0 == access(file_path, F_OK)) {
311                 fd = fopen(file_path, "r");
312                 if (fd == NULL) {
313                         /* LCOV_EXCL_START */
314                         WMESH_LOGE("Error! Could not open /sys/class/net/%s/carrier file",
315                                         interface);
316                         return WMESHD_ERROR_IO_ERROR;
317                         /* LCOV_EXCL_STOP */
318                 }
319         } else {
320                 /* LCOV_EXCL_START */
321                 WMESH_LOGE("Error! Could not access /sys/class/net/%s/carrier file",
322                                 interface);
323                 return WMESHD_ERROR_IO_ERROR;
324                 /* LCOV_EXCL_STOP */
325         }
326
327         errno = 0;
328         rv = fscanf(fd, "%d", &ret);
329         if (rv < 0) {
330                 /* LCOV_EXCL_START */
331                 strerror_r(errno, error_buf, 256);
332                 WMESH_LOGE("Error! Failed to read from file, rv:[%d], error:[%s]",
333                                 rv, error_buf);
334                 fclose(fd);
335                 return WMESHD_ERROR_IO_ERROR;
336                 /* LCOV_EXCL_STOP */
337         }
338
339         /* LCOV_EXCL_START */
340         if (ret == 1) {
341                 WMESH_LOGD("/sys/class/net/%s/carrier : [%d]", interface, ret);
342                 *status = ETHERNET_CABLE_ATTACHED;
343         } else if (ret == 0) {
344                 WMESH_LOGD("/sys/class/net/%s/carrier : [%d]", interface, ret);
345                 *status = ETHERNET_CABLE_DETACHED;
346         }
347         /* LCOV_EXCL_STOP */
348
349         fclose(fd);
350         return WMESHD_ERROR_NONE;
351 }
352
353 int wmesh_interface_check_external_exists(const char* external_interface, bool *state)
354 {
355         /* TODO: Current logic checks only ethernet interface.
356                         This logic should consider wireless interface if can */
357         int ret = WMESHD_ERROR_NONE;
358         bool ex = false;
359         cable_state_e cable_state = ETHERNET_CABLE_DETACHED;
360
361         if (NULL == external_interface || NULL == state)
362                 return WMESHD_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
363
364         ex = _check_interface_exists(external_interface);
365         if (FALSE == ex) {
366                 /* LCOV_EXCL_START */
367                 WMESH_LOGE("External interface[%s] was not found.", external_interface);
368                 return WMESHD_ERROR_INVALID_PARAMETER;
369                 /* LCOV_EXCL_STOP */
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 (WMESHD_ERROR_NONE != ret) {
376                         /* LCOV_EXCL_START */
377                         WMESH_LOGE("Failed to get Ethernet cable state");
378                         return WMESHD_ERROR_OPERATION_FAILED;
379                         /* LCOV_EXCL_STOP */
380                 }
381         }
382
383         *state = FALSE;
384         if (ETHERNET_CABLE_ATTACHED == cable_state)
385                 *state = TRUE; /* LCOV_EXCL_LINE */
386
387         return WMESHD_ERROR_NONE;
388 }
389
390 int wmesh_interface_check(const char* interface)
391 {
392         bool ex = FALSE;
393
394         if (NULL == interface || strlen(interface) == 0)
395                 return WMESHD_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
396
397         ex = _check_interface_exists(interface);
398         if (FALSE == ex) {
399                 /* LCOV_EXCL_START */
400                 WMESH_LOGE("Interface[%s] was not found.", interface);
401                 return WMESHD_ERROR_NO_DATA;
402                 /* LCOV_EXCL_STOP */
403         }
404
405         return WMESHD_ERROR_NONE;
406 }
407
408 int wmesh_interface_check_bridge_interface_exists(const char* bridge, const char* interface)
409 {
410         bool ex = FALSE;
411
412         if (NULL == bridge || NULL == interface ||
413                 strlen(bridge) == 0 || strlen(interface) == 0)
414                 return WMESHD_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
415
416         ex = _check_bridge_interface_exists(bridge, interface);
417         if (FALSE == ex) {
418                 /* LCOV_EXCL_START */
419                 WMESH_LOGE("Interface[%s] was not found.", interface);
420                 return WMESHD_ERROR_NO_DATA;
421                 /* LCOV_EXCL_STOP */
422         }
423
424         return WMESHD_ERROR_NONE; /* LCOV_EXCL_LINE */
425 }
426