Implement sending 'enable ethernet' to the ConnMan
[platform/core/connectivity/wifi-mesh-manager.git] / src / mesh-device-monitor.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 <errno.h>
20 #include <stdio.h>
21 #include <string.h>
22
23 #include <net/if.h>
24 #include <net/ethernet.h>
25 #ifdef USE_IOCTL_MONITOR
26 #include <sys/ioctl.h>
27 #endif
28 #ifdef USE_NETLINK_MONITOR
29 #include <asm/types.h>
30 #include <asm/types.h>
31 #include <sys/socket.h>
32 #include <linux/netlink.h>
33 #include <linux/rtnetlink.h>
34 #include <net/if_arp.h>
35 #endif /* USE_NETLINK_MONITOR */
36
37 #include "mesh.h"
38 #include "mesh-log.h"
39 #include "mesh-util.h"
40 #include "mesh-device-monitor.h"
41
42 #ifdef USE_NETLINK_MONITOR
43 static void mesh_read_netlink_msg(void *pdata)
44 {
45         int len;
46         int buf[1024];
47
48         struct sockaddr_nl sa;
49         struct nlmsghdr *nh;
50         struct ifinfomsg *ifimsg;
51         struct rtattr *attribute;
52         struct iovec iov = { buf, sizeof(buf) };
53         struct msghdr msg = { (void *)&sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
54
55         mesh_interface_s *info = NULL;
56         mesh_service *service = (mesh_service *)pdata;
57         meshd_check_null_ret("service", service);
58         info = service->interface_info;
59         meshd_check_null_ret("info", info);
60
61         len = recvmsg(service->netlink_fd, &msg, 0);
62         if(-1 == len) {
63                 MESH_LOGE("recvmsg error");
64                 return;
65         }
66
67         for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
68                 if (nh->nlmsg_type == NLMSG_ERROR) {
69                         MESH_LOGE("Read Netlink Message Error!!");
70                         continue;
71                 }
72                 if (nh->nlmsg_type == NLMSG_DONE) {
73                         MESH_LOGD("Read Netlink Message Done");
74                         return;
75                 }
76
77                 ifimsg = NLMSG_DATA(nh);
78                 MESH_LOGD("Message : [%u %u %u 0x%X 0x%X]",
79                         ifimsg->ifi_family,
80                         ifimsg->ifi_type,
81                         ifimsg->ifi_index,
82                         ifimsg->ifi_flags,
83                         ifimsg->ifi_change);
84                 /* Monitor external interface state change */
85                 if (ARPHRD_ETHER != ifimsg->ifi_type)
86                         return;
87
88                 attribute = IFLA_RTA(ifimsg);
89                 if (IFLA_IFNAME == attribute->rta_type) {
90                         if (!g_strcmp0(info->external_interface, RTA_DATA(attribute))) {
91                                 MESH_LOGD("Event from external interface : [%s]", RTA_DATA(attribute));
92                                 if (RTM_NEWLINK == nh->nlmsg_type && false == info->can_be_gate &&
93                                         IFF_LOWER_UP == (ifimsg->ifi_flags & IFF_LOWER_UP)) {
94                                         MESH_LOGD("RTM_NEWLINK : [%s]", RTA_DATA(attribute));
95                                         info->can_be_gate = true;
96                                 } else if (RTM_DELLINK == nh->nlmsg_type) {
97                                         MESH_LOGD("RTM_DELLINK : [%s]", RTA_DATA(attribute));
98                                         info->can_be_gate = false;
99                                 }
100                         }
101                 }
102         }
103 }
104
105 static gboolean _on_socket_msg_received(GIOChannel *source,
106                 GIOCondition condition, gpointer data)
107 {
108         NOTUSED(source);
109         NOTUSED(condition);
110
111         mesh_read_netlink_msg(data);
112
113         /* Do not remove I/O source */
114         return TRUE;
115 }
116
117 int mesh_device_monitor(void *pdata)
118 {
119         struct sockaddr_nl sa;
120         guint event_source;
121         GIOChannel *recv_channel = NULL;
122
123         mesh_service *service = (mesh_service *)pdata;
124         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
125
126         memset(&sa, 0, sizeof(sa));
127         sa.nl_family = AF_NETLINK;
128         sa.nl_groups = RTMGRP_LINK;
129
130         service->netlink_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
131         if(-1 == service->netlink_fd) {
132                 MESH_LOGE("Netlink socket creation error");
133                 return MESHD_ERROR_OPERATION_FAILED;
134         }
135
136         if(bind(service->netlink_fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
137                 MESH_LOGE("bind error");
138                 return MESHD_ERROR_OPERATION_FAILED;
139         }
140
141         recv_channel = g_io_channel_unix_new(service->netlink_fd);
142         event_source = g_io_add_watch(recv_channel,     (G_IO_IN | G_IO_ERR),
143                                         _on_socket_msg_received, (gpointer)service);
144         g_io_channel_unref(recv_channel);
145
146     return 0;
147 }
148 #endif /* USE_NETLINK_MONITOR */
149
150 #ifdef USE_IOCTL_MONITOR
151 /* Check send notification status */
152 static gboolean g_chk_eth_send_notification = FALSE;
153 #define MAX_SIZE_ERROR_BUFFER 128
154
155 static int _ethernet_cable_plugin_status_check()
156 {
157         struct ifreq ifr;
158         int soketfd = -1;
159         int error = 0;
160         int ret = 0;
161         struct _stMData *mdata;
162         struct timeval tv;
163         char error_buf[MAX_SIZE_ERROR_BUFFER] = {};
164
165         soketfd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
166         if (soketfd < 0) {
167                 MESH_LOGE("Failed to create socket");
168                 return -errno;
169         }
170
171         /* Set Timeout for IOCTL Call */
172         tv.tv_sec = 1;
173         tv.tv_usec = 0;
174
175         if (setsockopt(soketfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
176                 sizeof(struct timeval)) < 0) {
177
178                 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
179                 MESH_LOGE("Failed to set socket option : [%d] [%s]", -errno, error_buf);
180                 goto done;
181         }
182
183         memset(&ifr, 0, sizeof(ifr));
184         g_strlcpy(ifr.ifr_name, "eth0", IFNAMSIZ);
185         if (ioctl(soketfd, SIOCGMIIPHY, &ifr) < 0){
186                 error = -errno;
187                 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
188                 MESH_LOGE("SIOCGMIIPHY on eth0 failed : [%d] [%s]", errno, error_buf);
189                 goto done;
190         }
191
192         mdata = (struct _stMData *)&ifr.ifr_data;
193         mdata->reg_num = ETH_REG_BMSR;
194
195         if (ioctl(soketfd, SIOCGMIIREG, &ifr) < 0){
196                 error = -errno;
197                 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
198                 MESH_LOGE("SIOCGMIIREG on %s failed , [%d] [%s] ", ifr.ifr_name,errno,error_buf);
199                 goto done;
200         }
201         ret = mdata->val_out;
202         ret = ret & BMSR_LINK_VALID;
203
204         MESH_LOGD("value of ret : %d",ret);
205
206         if (ret == 4) {
207                 if (!g_chk_eth_send_notification) {
208                         MESH_LOGE("Return Value : [%d]", ret);
209                 }
210                 g_chk_eth_send_notification = TRUE;
211                 } else if (ret == 0) {
212                         if (g_chk_eth_send_notification) {
213                         MESH_LOGE("Return Value : [%d]", ret);
214                 }
215                 g_chk_eth_send_notification = FALSE;
216         }
217
218
219         error = 0;
220 done:
221         close(soketfd);
222         return error;
223 }
224
225 int mesh_get_ethernet_cable_state(int *status)
226 {
227         int error = 0;
228         meshd_check_null_ret_error("status", status, MESHD_ERROR_INVALID_PARAMETER);
229
230         if ((error = _ethernet_cable_plugin_status_check()) != 0) {
231                 MESH_LOGE("Error !!! Failed to check ethernet cable status [%d]\n", error);
232                 return error;
233         }
234
235         if (g_chk_eth_send_notification == TRUE)
236                 *status = 1;            /* Ethernet cable Attached */
237         else
238                 *status = 0;            /* Ethernet cable Deattached */
239         return MESHD_ERROR_NONE;
240 }
241 #endif