wmesh-manager: Add support to get softAP station info
[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 int wmesh_interface_set(const char *interface, const char* ip_addr,
54                 wmesh_set_interface_type_e type)
55 {
56         int sock = 0;
57         struct ifreq ifr;
58         int ret = 0;
59
60         char ip[IPV4_MAX_LENGTH] = {0,};
61         char buf[BUF_LENGTH] = {0,};
62
63         if (interface == NULL) {
64                 WMESH_LOGE("Invalid interface name !");
65                 return WMESHD_ERROR_INVALID_PARAMETER;
66         }
67
68         sock = socket(AF_INET, SOCK_STREAM, 0);
69         if (sock < 0) {
70                 WMESH_LOGE("Cannot open network interface socket");
71                 return WMESHD_ERROR_IO_ERROR;
72         }
73
74         WMESH_LOGD("Initialize interface [%s]...", interface);
75         snprintf(ifr.ifr_name, IFNAMSIZ, "%s", interface);
76
77         /* Set IP Address */
78         if (NULL != ip_addr) {
79                 struct sockaddr_in sai;
80                 memset(&sai, 0, sizeof(struct sockaddr_in));
81                 sai.sin_family = AF_INET;
82                 sai.sin_port = 0;
83                 snprintf(ip, IPV4_MAX_LENGTH, "%s", ip_addr);
84
85                 WMESH_LOGD("Setting IP address: [%s]\n", ip);
86                 if (!inet_aton(ip, &sai.sin_addr)) {
87                         WMESH_LOGE("Failed to convert ip address");
88                         close(sock);
89                         return WMESHD_ERROR_OPERATION_FAILED;
90                 }
91
92                 memcpy(&ifr.ifr_addr, &sai, sizeof(sai));
93
94                 ret = ioctl(sock, SIOCSIFADDR, &ifr);
95                 if (ret < 0) {
96                         (void) strerror_r(errno, buf, BUF_LENGTH);
97                         WMESH_LOGE("Failed to set IP[%s] for interface[%s] : %s",
98                                 ip, ifr.ifr_name, buf);
99                 }
100         }
101
102         /* Get status flag */
103         if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
104                 (void) strerror_r(errno, buf, BUF_LENGTH);
105                 WMESH_LOGE("Failed to get interface[%s] status : %s",
106                         ifr.ifr_name, buf);
107         }
108         snprintf(ifr.ifr_name, IFNAMSIZ, "%s", interface);
109
110         /* Set status flag */
111         if (WMESH_INTERFACE_UP == type) {
112                 ifr.ifr_flags |= (IFF_UP);
113                 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
114                         (void) strerror_r(errno, buf, BUF_LENGTH);
115                         WMESH_LOGE("Failed to change interface[%s] status UP : %s",
116                                 ifr.ifr_name, buf);
117                 }
118         } else if (WMESH_INTERFACE_DOWN == type) {
119                 ifr.ifr_flags &= (~IFF_UP);
120                 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
121                         (void) strerror_r(errno, buf, BUF_LENGTH);
122                         WMESH_LOGE("Failed to change interface[%s] status DOWN : %s",
123                                 ifr.ifr_name, buf);
124                 }
125         } else {
126                 WMESH_LOGD("Do not change up/down status");
127         }
128
129         close(sock);
130         return WMESHD_ERROR_NONE;
131 }
132
133 #if 0
134 /* Returns interface name in sequence order which is exists */
135 static char* _get_interface_exists_in_seq(const char* prefix)
136 {
137         char *res = NULL;
138         char buf[32];
139         int ret;
140         int i = 0;
141         const int IF_INDEX_MAX = 9;
142
143         for (i = 0; i <= IF_INDEX_MAX; i++) {
144                 snprintf(buf, sizeof(buf), "/sys/class/net/%s%d", prefix, i);
145
146                 ret = access(buf, F_OK);
147                 if (ret >= 0) {
148                         /* This name is exists. use it */
149                         snprintf(buf, sizeof(buf), "%s%d", prefix, i);
150                         res = g_strdup(buf);
151                         WMESH_LOGD("  use [%s]", res);
152                         break;
153                 }
154         }
155
156         return res;
157 }
158
159 /* Returns interface name in sequence order which is exists */
160 static char* _get_interface_not_exists_in_seq(const char* prefix)
161 {
162         char *res = NULL;
163         char buf[32];
164         int ret;
165         int i = 0;
166         const int IF_INDEX_MAX = 9;
167
168         for (i = 0; i <= IF_INDEX_MAX; i++) {
169                 snprintf(buf, sizeof(buf), "/sys/class/net/%s%d", prefix, i);
170
171                 ret = access(buf, F_OK);
172                 if (ret < 0) {
173                         /* This name is not exists. use it */
174                         snprintf(buf, sizeof(buf), "%s%d", prefix, i);
175                         res = g_strdup(buf);
176                         WMESH_LOGD("  use [%s]", res);
177                         break;
178                 }
179         }
180
181         return res;
182 }
183 #endif
184
185 static bool _check_interface_exists(const char* if_name)
186 {
187         int ret;
188         char buf[32];
189         int i = 0;
190         const int IF_INDEX_MAX = 9;
191
192         for (i = 0; i <= IF_INDEX_MAX; i++) {
193                 snprintf(buf, sizeof(buf), "/sys/class/net/%s", if_name);
194
195                 ret = access(buf, F_OK);
196                 if (ret >= 0) {
197                         /* This name is exists. */
198                         return true;
199                 }
200         }
201
202         return false;
203 }
204
205 /* Check if interface is bridged */
206 static bool _check_bridge_interface_exists(const char* bridge, const char* if_name)
207 {
208         int ret;
209         char buf[32];
210         int i = 0;
211         const int IF_INDEX_MAX = 9;
212
213         for (i = 0; i <= IF_INDEX_MAX; i++) {
214                 snprintf(buf, sizeof(buf), "/sys/class/net/%s/brif/%s", bridge, if_name);
215
216                 ret = access(buf, F_OK);
217                 if (ret >= 0) {
218                         /* This name is exists. */
219                         return true;
220                 }
221         }
222
223         return false;
224 }
225
226 char* wmesh_interface_get_address(const char* if_name)
227 {
228         FILE *pf;
229         char buf[32] = { 0, };
230         char *result = NULL;
231
232         snprintf(buf, sizeof(buf), "/sys/class/net/%s/address", if_name);
233         pf = fopen(buf, "r");
234         if (NULL != pf) {
235                 fgets(buf, 31, pf);
236                 WMESH_LOGD("Interface[%s] address[%s]", if_name, buf);
237
238                 if (strlen(buf) > 0)
239                         result = g_strdup(buf);
240
241                 fclose(pf);
242         }
243
244         return result;
245 }
246
247 int wmesh_interface_initialize(wmesh_interface_s *info)
248 {
249         if (NULL == info) {
250                 WMESH_LOGE("Invalid parameter");
251                 return WMESHD_ERROR_INVALID_PARAMETER;
252         }
253
254         info->bridge_interface = g_strdup(MESH_DEFAULT_BRIDGE_INTERFACE);
255         if (NULL == info->bridge_interface) {
256                 WMESH_LOGE("Failed to get bridge interface !");
257                 return WMESHD_ERROR_OPERATION_FAILED;
258         }
259
260         info->base_interface = g_strdup(MESH_DEFAULT_BASE_INTERFACE);
261         if (NULL == info->bridge_interface) {
262                 WMESH_LOGE("Failed to get base interface !");
263                 return WMESHD_ERROR_OPERATION_FAILED;
264         }
265
266         info->mesh_interface = g_strdup(MESH_DEFAULT_MESH_INTERFACE);
267         if (NULL == info->bridge_interface) {
268                 WMESH_LOGE("Failed to get mesh interface !");
269                 return WMESHD_ERROR_OPERATION_FAILED;
270         }
271
272         info->softap_interface = g_strdup(MESH_DEFAULT_SOFTAP_INTERFACE);
273         info->external_interface = g_strdup(MESH_DEFAULT_EXTERNAL_INTERFACE);
274
275         WMESH_LOGD("Interface configuration for mesh network :");
276         WMESH_LOGD("  Base    : [%s]", info->base_interface);
277         WMESH_LOGD("  Mesh    : [%s]", info->mesh_interface);
278         WMESH_LOGD("  Bridge  : [%s]", info->bridge_interface);
279         WMESH_LOGD("  SoftAP  : [%s]", info->softap_interface);
280         WMESH_LOGD("  External: [%s]", info->external_interface);
281
282         return WMESHD_ERROR_NONE;
283 }
284
285 static int _check_ethernet_cable_plugin_status(const char* interface,
286                 cable_state_e *status)
287 {
288         FILE *fd = NULL;
289         int ret = -1;
290         int rv = 0;
291         char error_buf[256] = {0, };
292         char file_path[256] = {0, };
293
294         snprintf(file_path, 256, "/sys/class/net/%s/carrier", interface);
295
296         if (0 == access(file_path, F_OK)) {
297                 fd = fopen(file_path, "r");
298                 if (fd == NULL) {
299                         WMESH_LOGE("Error! Could not open /sys/class/net/%s/carrier file",
300                                         interface);
301                         return WMESHD_ERROR_IO_ERROR;
302                 }
303         } else {
304                 WMESH_LOGE("Error! Could not access /sys/class/net/%s/carrier file",
305                                 interface);
306                 return WMESHD_ERROR_IO_ERROR;
307         }
308
309         errno = 0;
310         rv = fscanf(fd, "%d", &ret);
311         if (rv < 0) {
312                 strerror_r(errno, error_buf, 256);
313                 WMESH_LOGE("Error! Failed to read from file, rv:[%d], error:[%s]",
314                                 rv, error_buf);
315                 fclose(fd);
316                 return WMESHD_ERROR_IO_ERROR;
317         }
318
319         if (ret == 1) {
320                 WMESH_LOGD("/sys/class/net/%s/carrier : [%d]", interface, ret);
321                 *status = ETHERNET_CABLE_ATTACHED;
322         } else if (ret == 0) {
323                 WMESH_LOGD("/sys/class/net/%s/carrier : [%d]", interface, ret);
324                 *status = ETHERNET_CABLE_DETACHED;
325         }
326
327         fclose(fd);
328         return WMESHD_ERROR_NONE;
329 }
330
331 int wmesh_interface_check_external_exists(const char* external_interface, bool *state)
332 {
333         /* TODO: Current logic checks only ethernet interface.
334                         This logic should consider wireless interface if can */
335         int ret = WMESHD_ERROR_NONE;
336         cable_state_e cable_state = ETHERNET_CABLE_DETACHED;
337
338         if (NULL == external_interface || NULL == state)
339                 return WMESHD_ERROR_INVALID_PARAMETER;
340
341         bool ex = _check_interface_exists(external_interface);
342         if (FALSE == ex) {
343                 WMESH_LOGE("External interface[%s] was not found.", external_interface);
344                 return WMESHD_ERROR_INVALID_PARAMETER;
345         }
346
347         /* If external interface seems Ethernet, check cable state */
348         if (g_str_has_prefix(external_interface, "eth")) {
349                 ret = _check_ethernet_cable_plugin_status(external_interface, &cable_state);
350                 if (WMESHD_ERROR_NONE != ret) {
351                         WMESH_LOGE("Failed to get Ethernet cable state");
352                         return WMESHD_ERROR_OPERATION_FAILED;
353                 }
354         }
355
356         *state = FALSE;
357         if (ETHERNET_CABLE_ATTACHED == cable_state)
358                 *state = TRUE;
359
360         return WMESHD_ERROR_NONE;
361 }
362
363 int wmesh_interface_check(const char* interface)
364 {
365         bool ex = FALSE;
366
367         if (NULL == interface || strlen(interface) == 0)
368                 return WMESHD_ERROR_INVALID_PARAMETER;
369
370         ex = _check_interface_exists(interface);
371         if (FALSE == ex) {
372                 WMESH_LOGE("Interface[%s] was not found.", interface);
373                 return WMESHD_ERROR_NO_DATA;
374         }
375
376         return WMESHD_ERROR_NONE;
377 }
378
379 int wmesh_interface_check_bridge_interface_exists(const char* bridge, const char* interface)
380 {
381         bool ex = FALSE;
382
383         if (NULL == bridge || NULL == interface ||
384                 strlen(bridge) == 0 || strlen(interface) == 0)
385                 return WMESHD_ERROR_INVALID_PARAMETER;
386
387         ex = _check_bridge_interface_exists(bridge, interface);
388         if (FALSE == ex) {
389                 WMESH_LOGE("Interface[%s] was not found.", interface);
390                 return WMESHD_ERROR_NO_DATA;
391         }
392
393         return WMESHD_ERROR_NONE;
394 }
395