Merge branch 'tizen' into tizen_5.5
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ip_adapter / tizen / caipnwmonitor.c
1 /******************************************************************
2 *
3 * Copyright 2014 Samsung Electronics All Rights Reserved.
4 *
5 *
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 ******************************************************************/
20
21 #include <sys/types.h>
22 #include <ifaddrs.h>
23 #include <net/if.h>
24 #include <sys/socket.h>
25 #include <netdb.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <sys/ioctl.h>
30 #include <linux/netlink.h>
31 #include <linux/rtnetlink.h>
32 #include <arpa/inet.h>
33 #include <netinet/in.h>
34 #include <net_connection.h>
35
36 #include "caipinterface.h"
37 #include "caipnwmonitor.h"
38 #include "caipnwmonitor_common.h"
39 #include "caadapterutils.h"
40 #include "logger.h"
41 #include "oic_malloc.h"
42 #include "oic_string.h"
43 #include <coap/utlist.h>
44
45 #define TAG "OIC_CA_IP_MONITOR"
46 #define MAX_INTERFACE_INFO_LENGTH (1024)
47 #define NETLINK_MESSAGE_LENGTH  (4096)
48 #define IFC_LABEL_LOOP          "lo"
49 #define IFC_ADDR_LOOP_IPV4      "127.0.0.1"
50 #define IFC_ADDR_LOOP_IPV6      "::1"
51
52 /**
53  * Used to storing a connection handle for managing data connections.
54  */
55 static connection_h connection = NULL;
56
57 /**
58  * Used to storing adapter changes callback interface.
59  */
60 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
61
62 /**
63  * Create new interface item.
64  */
65 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
66                                          const char *addr, int flags);
67
68 /**
69  * Add new network interface in list.
70  */
71 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
72                                      char *name, int family, const char *addr, int flags);
73
74 /**
75  * Pass the changed network status through the stored callback.
76  */
77 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
78
79 /**
80  * Callback function to received connection state changes.
81  */
82 static void CAIPConnectionStateChangedCb(connection_type_e type, void* userData);
83
84 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
85 {
86     CAIPPassNetworkChangesToAdapterInternal(status, g_adapterCallbackList, CA_IP_NW_COMMON_TIZEN);
87 }
88
89 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
90                                          CATransportAdapter_t adapter)
91 {
92     return CAIPSetNetworkMonitorCallbackInternal(callback, adapter, g_adapterCallbackList);
93 }
94
95 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
96 {
97     return CAIPUnSetNetworkMonitorCallbackInternal(adapter, g_adapterCallbackList);
98 }
99
100 u_arraylist_t *CAFindInterfaceChange()
101 {
102     u_arraylist_t *iflist = NULL;
103     char buf[NETLINK_MESSAGE_LENGTH] = { 0 };
104     struct sockaddr_nl sa = { 0 };
105     struct iovec iov = { .iov_base = buf,
106                          .iov_len = sizeof (buf) };
107     struct msghdr msg = { .msg_name = (void *)&sa,
108                           .msg_namelen = sizeof (sa),
109                           .msg_iov = &iov,
110                           .msg_iovlen = 1 };
111
112     ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
113
114     for (struct nlmsghdr *nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
115     {
116         if (nh != NULL && (nh->nlmsg_type != RTM_DELADDR && nh->nlmsg_type != RTM_NEWADDR))
117         {
118             continue;
119         }
120
121         struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
122         if (!ifi)
123         {
124             continue;
125         }
126
127         if (RTM_DELADDR == nh->nlmsg_type)
128         {
129             CloseMulticastSocket();
130         }
131
132         int ifiIndex = ifi->ifi_index;
133         iflist = CAIPGetInterfaceInformation(ifiIndex);
134         if (!iflist)
135         {
136             OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
137             return NULL;
138         }
139         CreateMulticastSocket();
140     }
141     return iflist;
142 }
143
144 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
145                                    CATransportAdapter_t adapter)
146 {
147     if (!g_adapterCallbackList)
148     {
149         // Initialize Connections.
150         connection_error_e ret = connection_create(&connection);
151         if (CONNECTION_ERROR_NONE != ret)
152         {
153             OIC_LOG(ERROR, TAG, "connection_create failed");
154             return CA_STATUS_FAILED;
155         }
156
157         // Set callback for receiving state changes.
158         ret = connection_set_type_changed_cb(connection, CAIPConnectionStateChangedCb, NULL);
159         if (CONNECTION_ERROR_NONE != ret)
160         {
161             OIC_LOG(ERROR, TAG, "connection_set_type_changed_cb failed");
162             return CA_STATUS_FAILED;
163         }
164     }
165
166     OIC_LOG(DEBUG, TAG, "Initialize network monitoring successfully");
167     return CAIPSetNetworkMonitorCallback(callback, adapter);
168 }
169
170 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
171 {
172     OIC_LOG(DEBUG, TAG, "IN");
173
174     CAIPUnSetNetworkMonitorCallback(adapter);
175     if (!g_adapterCallbackList)
176     {
177         // Reset callback for receiving state changes.
178         if (connection)
179         {
180             connection_error_e ret = connection_unset_type_changed_cb(connection);
181             if (CONNECTION_ERROR_NONE != ret)
182             {
183                 OIC_LOG(ERROR, TAG, "connection_unset_type_changed_cb failed");
184             }
185
186             // Deinitialize Wifi service.
187             ret = connection_destroy(connection);
188             if (CONNECTION_ERROR_NONE != ret)
189             {
190                 OIC_LOG(ERROR, TAG, "connection_destroy failed");
191             }
192             connection = NULL;
193         }
194     }
195
196     OIC_LOG(DEBUG, TAG, "Network monitoring terminated successfully");
197     return CA_STATUS_OK;
198 }
199
200 /**
201  * Used to send netlink query to kernel and recv response from kernel.
202  *
203  * @param[in]   idx       desired network interface index, 0 means all interfaces.
204  * @param[out]  iflist    linked list.
205  *
206  */
207 static bool CAIPGetAddrInfo(int idx, u_arraylist_t *iflist)
208 {
209     if ((idx < 0) || (iflist == NULL))
210     {
211         return false;
212     }
213
214     struct ifaddrs *ifp = NULL;
215     if (-1 == getifaddrs(&ifp))
216     {
217         OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs: %s", strerror(errno));
218         return false;
219     }
220
221     struct ifaddrs *ifa = NULL;
222     for (ifa = ifp; ifa; ifa = ifa->ifa_next)
223     {
224         if (!ifa->ifa_addr)
225         {
226             continue;
227         }
228
229         int family = ifa->ifa_addr->sa_family;
230         if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
231         {
232             continue;
233         }
234
235         int ifindex = if_nametoindex(ifa->ifa_name);
236         if (idx && (ifindex != idx))
237         {
238             continue;
239         }
240
241         char ipaddr[MAX_ADDR_STR_SIZE_CA] = {0};
242         if (family == AF_INET6)
243         {
244             struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
245             inet_ntop(family, (void *)&(in6->sin6_addr), ipaddr, sizeof(ipaddr));
246         }
247         else if (family == AF_INET)
248         {
249             struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
250             inet_ntop(family, (void *)&(in->sin_addr), ipaddr, sizeof(ipaddr));
251         }
252
253         if ((strcmp(ipaddr, IFC_ADDR_LOOP_IPV4) == 0) ||
254             (strcmp(ipaddr, IFC_ADDR_LOOP_IPV6) == 0) ||
255             (strcmp(ifa->ifa_name, IFC_LABEL_LOOP) == 0))
256         {
257             OIC_LOG(DEBUG, TAG, "LOOPBACK continue!!!");
258             continue;
259         }
260
261         CAResult_t result = CAAddInterfaceItem(iflist, ifindex,
262                                                ifa->ifa_name, family,
263                                                ipaddr, ifa->ifa_flags);
264         if (CA_STATUS_OK != result)
265         {
266             OIC_LOG(ERROR, TAG, "CAAddInterfaceItem fail");
267             goto exit;
268         }
269     }
270     freeifaddrs(ifp);
271     return true;
272
273 exit:
274     freeifaddrs(ifp);
275     return false;
276 }
277
278 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
279 {
280     u_arraylist_t *iflist = u_arraylist_create();
281     if (!iflist)
282     {
283         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
284         return NULL;
285     }
286
287     if (!CAIPGetAddrInfo(desiredIndex, iflist))
288     {
289         goto exit;
290     }
291
292     return iflist;
293
294 exit:
295     u_arraylist_destroy(iflist);
296     return NULL;
297 }
298
299 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
300                                      char *name, int family, const char *addr, int flags)
301 {
302     CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
303     if (!ifitem)
304     {
305         return CA_STATUS_FAILED;
306     }
307     bool result = u_arraylist_add(iflist, ifitem);
308     if (!result)
309     {
310         OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
311         OICFree(ifitem);
312         return CA_STATUS_FAILED;
313     }
314
315     return CA_STATUS_OK;
316 }
317
318 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
319                                          const char *addr, int flags)
320 {
321     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
322     if (!ifitem)
323     {
324         OIC_LOG(ERROR, TAG, "Malloc failed");
325         return NULL;
326     }
327
328     OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, name);
329     ifitem->index = index;
330     ifitem->family = family;
331     OICStrcpy(ifitem->addr, sizeof(ifitem->addr), addr);
332     ifitem->flags = flags;
333
334     return ifitem;
335 }
336
337 void CAIPConnectionStateChangedCb(connection_type_e type, void* userData)
338 {
339     (void)userData;
340
341     switch (type)
342     {
343         case CONNECTION_TYPE_DISCONNECTED:
344             OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_DISCONNECTED");
345             CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
346             break;
347         case CONNECTION_TYPE_ETHERNET:
348             OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_ETHERNET");
349             CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
350             break;
351         case CONNECTION_TYPE_WIFI:
352             OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_WIFI");
353             CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
354             break;
355         case CONNECTION_TYPE_CELLULAR:
356             OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_CELLULAR");
357             CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
358             break;
359         default:
360             break;
361     }
362 }