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