Fix for svace issues
[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] = { 0, };
211         char *result = NULL;
212
213         snprintf(buf, sizeof(buf), "/sys/class/net/%s/address", if_name);
214         pf = fopen(buf, "r");
215         if (NULL != pf) {
216                 fgets(buf, 31, pf);
217                 MESH_LOGD("Interface[%s] address[%s]", if_name, buf);
218
219                 if (strlen(buf) > 0)
220                         result = g_strdup(buf);
221
222                 fclose(pf);
223         }
224
225         return result;
226 }
227
228 int mesh_interface_initialize(mesh_interface_s *info)
229 {
230         if (NULL == info) {
231                 MESH_LOGE("Invalid parameter");
232                 return MESHD_ERROR_INVALID_PARAMETER;
233         }
234
235         info->bridge_interface = g_strdup(MESH_DEFAULT_BRIDGE_INTERFACE);
236         if (NULL == info->bridge_interface) {
237                 MESH_LOGE("Failed to get bridge interface !");
238                 return MESHD_ERROR_OPERATION_FAILED;
239         }
240
241         info->base_interface = g_strdup(MESH_DEFAULT_BASE_INTERFACE);
242         if (NULL == info->bridge_interface) {
243                 MESH_LOGE("Failed to get base interface !");
244                 return MESHD_ERROR_OPERATION_FAILED;
245         }
246
247         info->mesh_interface = g_strdup(MESH_DEFAULT_MESH_INTERFACE);
248         if (NULL == info->bridge_interface) {
249                 MESH_LOGE("Failed to get mesh interface !");
250                 return MESHD_ERROR_OPERATION_FAILED;
251         }
252
253         info->softap_interface = g_strdup(MESH_DEFAULT_SOFTAP_INTERFACE);
254         info->external_interface = g_strdup(MESH_DEFAULT_EXTERNAL_INTERFACE);
255
256         MESH_LOGD("Interface configuration for mesh network :");
257         MESH_LOGD("  Base    : [%s]", info->base_interface);
258         MESH_LOGD("  Mesh    : [%s]", info->mesh_interface);
259         MESH_LOGD("  Bridge  : [%s]", info->bridge_interface);
260         MESH_LOGD("  SoftAP  : [%s]", info->softap_interface);
261         MESH_LOGD("  External: [%s]", info->external_interface);
262
263         return MESHD_ERROR_NONE;
264 }
265
266 static int _check_ethernet_cable_plugin_status(const char* interface,
267                 cable_state_e *status)
268 {
269         FILE *fd = NULL;
270         int ret = -1;
271         int rv = 0;
272         char error_buf[256] = {0, };
273         char file_path[256] = {0, };
274
275         snprintf(file_path, 256, "/sys/class/net/%s/carrier", interface);
276
277         if (0 == access(file_path, F_OK)) {
278                 fd = fopen(file_path, "r");
279                 if (fd == NULL) {
280                         MESH_LOGE("Error! Could not open /sys/class/net/%s/carrier file",
281                                         interface);
282                         return MESHD_ERROR_IO_ERROR;
283                 }
284         } else {
285                 MESH_LOGE("Error! Could not access /sys/class/net/%s/carrier file",
286                                 interface);
287                 return MESHD_ERROR_IO_ERROR;
288         }
289
290         errno = 0;
291         rv = fscanf(fd, "%d", &ret);
292         if (rv < 0) {
293                 strerror_r(errno, error_buf, 256);
294                 MESH_LOGE("Error! Failed to read from file, rv:[%d], error:[%s]",
295                                 rv, error_buf);
296                 fclose(fd);
297                 return MESHD_ERROR_IO_ERROR;
298         }
299
300         if (ret == 1) {
301                 MESH_LOGD("/sys/class/net/%s/carrier : [%d]", interface, ret);
302                 *status = ETHERNET_CABLE_ATTACHED;
303         } else if (ret == 0) {
304                 MESH_LOGD("/sys/class/net/%s/carrier : [%d]", interface, ret);
305                 *status = ETHERNET_CABLE_DETACHED;
306         }
307
308         fclose(fd);
309         return MESHD_ERROR_NONE;
310 }
311
312 int mesh_interface_check_external_exists(const char* external_interface, bool *state)
313 {
314         /* TODO: Current logic checks only ethernet interface.
315                         This logic should consider wireless interface if can */
316         int ret = MESHD_ERROR_NONE;
317         cable_state_e cable_state = ETHERNET_CABLE_DETACHED;
318
319         if (NULL == external_interface || NULL == state) {
320                 return MESHD_ERROR_INVALID_PARAMETER;
321         }
322
323         bool ex = _check_interface_exists(external_interface);
324         if (FALSE == ex) {
325                 MESH_LOGE("External interface[%s] was not found.", external_interface);
326                 return MESHD_ERROR_INVALID_PARAMETER;
327         }
328
329         /* If external interface seems Ethernet, check cable state */
330         if (g_str_has_prefix(external_interface, "eth")) {
331                 ret = _check_ethernet_cable_plugin_status(external_interface, &cable_state);
332                 if (MESHD_ERROR_NONE != ret) {
333                         MESH_LOGE("Failed to get Ethernet cable state");
334                         return MESHD_ERROR_OPERATION_FAILED;
335                 }
336         }
337
338         *state = FALSE;
339         if (ETHERNET_CABLE_ATTACHED == cable_state) {
340                 *state = TRUE;
341         }
342
343         return MESHD_ERROR_NONE;
344 }