Update snapshot(2017-12-06)
[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 "caadapterutils.h"
39 #include "logger.h"
40 #include "oic_malloc.h"
41 #include "oic_string.h"
42 #include <coap/utlist.h>
43
44 #define TAG "OIC_CA_IP_MONITOR"
45 #define MAX_INTERFACE_INFO_LENGTH (1024)
46 #define NETLINK_MESSAGE_LENGTH  (4096)
47 #define IFC_LABEL_LOOP          "lo"
48 #define IFC_ADDR_LOOP_IPV4      "127.0.0.1"
49 #define IFC_ADDR_LOOP_IPV6      "::1"
50
51 /**
52  * Used to storing a connection handle for managing data connections.
53  */
54 static connection_h connection = NULL;
55
56 /**
57  * Used to storing adapter changes callback interface.
58  */
59 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
60
61 /**
62  * Create new interface item.
63  */
64 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
65                                          const char *addr, int flags);
66
67 /**
68  * Add new network interface in list.
69  */
70 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
71                                      char *name, int family, const char *addr, int flags);
72
73 /**
74  * Pass the changed network status through the stored callback.
75  */
76 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
77
78 /**
79  * Callback function to received connection state changes.
80  */
81 static void CAIPConnectionStateChangedCb(connection_type_e type, void* userData);
82
83 int CAGetPollingInterval(int interval)
84 {
85     return interval;
86 }
87
88 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
89 {
90     CAIPCBData_t *cbitem = NULL;
91     LL_FOREACH(g_adapterCallbackList, cbitem)
92     {
93         if (cbitem && cbitem->adapter)
94         {
95             cbitem->callback(cbitem->adapter, status);
96         }
97     }
98 }
99
100 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
101                                          CATransportAdapter_t adapter)
102 {
103     if (!callback)
104     {
105         OIC_LOG(ERROR, TAG, "callback is null");
106         return CA_STATUS_INVALID_PARAM;
107     }
108
109     CAIPCBData_t *cbitem = NULL;
110     LL_FOREACH(g_adapterCallbackList, cbitem)
111     {
112         if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
113         {
114             OIC_LOG(DEBUG, TAG, "this callback is already added");
115             return CA_STATUS_OK;
116         }
117     }
118
119     cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
120     if (!cbitem)
121     {
122         OIC_LOG(ERROR, TAG, "Malloc failed");
123         return CA_STATUS_FAILED;
124     }
125
126     cbitem->adapter = adapter;
127     cbitem->callback = callback;
128     LL_APPEND(g_adapterCallbackList, cbitem);
129
130     return CA_STATUS_OK;
131 }
132
133 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
134 {
135     CAIPCBData_t *cbitem = NULL;
136     CAIPCBData_t *tmpCbitem = NULL;
137     LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
138     {
139         if (cbitem && adapter == cbitem->adapter)
140         {
141             OIC_LOG(DEBUG, TAG, "remove specific callback");
142             LL_DELETE(g_adapterCallbackList, cbitem);
143             OICFree(cbitem);
144             return CA_STATUS_OK;
145         }
146     }
147     return CA_STATUS_OK;
148 }
149
150 u_arraylist_t *CAFindInterfaceChange()
151 {
152     u_arraylist_t *iflist = NULL;
153     char buf[NETLINK_MESSAGE_LENGTH] = { 0 };
154     struct sockaddr_nl sa = { 0 };
155     struct iovec iov = { .iov_base = buf,
156                          .iov_len = sizeof (buf) };
157     struct msghdr msg = { .msg_name = (void *)&sa,
158                           .msg_namelen = sizeof (sa),
159                           .msg_iov = &iov,
160                           .msg_iovlen = 1 };
161
162     ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
163
164     for (struct nlmsghdr *nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
165     {
166         if (nh != NULL && (nh->nlmsg_type != RTM_DELADDR && nh->nlmsg_type != RTM_NEWADDR))
167         {
168             continue;
169         }
170
171         struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
172         if (!ifi)
173         {
174             continue;
175         }
176
177         if (RTM_DELADDR == nh->nlmsg_type)
178         {
179             CloseMulticastSocket();
180         }
181
182         int ifiIndex = ifi->ifi_index;
183         iflist = CAIPGetInterfaceInformation(ifiIndex);
184         if (!iflist)
185         {
186             OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
187             return NULL;
188         }
189         CreateMulticastSocket();
190     }
191     return iflist;
192 }
193
194 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
195                                    CATransportAdapter_t adapter)
196 {
197     if (!g_adapterCallbackList)
198     {
199         // Initialize Connections.
200         connection_error_e ret = connection_create(&connection);
201         if (CONNECTION_ERROR_NONE != ret)
202         {
203             OIC_LOG(ERROR, TAG, "connection_create failed");
204             return CA_STATUS_FAILED;
205         }
206
207         // Set callback for receiving state changes.
208         ret = connection_set_type_changed_cb(connection, CAIPConnectionStateChangedCb, NULL);
209         if (CONNECTION_ERROR_NONE != ret)
210         {
211             OIC_LOG(ERROR, TAG, "connection_set_type_changed_cb failed");
212             return CA_STATUS_FAILED;
213         }
214     }
215
216     OIC_LOG(DEBUG, TAG, "Initialize network monitoring successfully");
217     return CAIPSetNetworkMonitorCallback(callback, adapter);
218 }
219
220 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
221 {
222     OIC_LOG(DEBUG, TAG, "IN");
223
224     CAIPUnSetNetworkMonitorCallback(adapter);
225     if (!g_adapterCallbackList)
226     {
227         // Reset callback for receiving state changes.
228         if (connection)
229         {
230             connection_error_e ret = connection_unset_type_changed_cb(connection);
231             if (CONNECTION_ERROR_NONE != ret)
232             {
233                 OIC_LOG(ERROR, TAG, "connection_unset_type_changed_cb failed");
234             }
235
236             // Deinitialize Wifi service.
237             ret = connection_destroy(connection);
238             if (CONNECTION_ERROR_NONE != ret)
239             {
240                 OIC_LOG(ERROR, TAG, "connection_destroy failed");
241             }
242             connection = NULL;
243         }
244     }
245
246     OIC_LOG(DEBUG, TAG, "Network monitoring terminated successfully");
247     return CA_STATUS_OK;
248 }
249
250 /**
251  * Used to send netlink query to kernel and recv response from kernel.
252  *
253  * @param[in]   idx       desired network interface index, 0 means all interfaces.
254  * @param[out]  iflist    linked list.
255  *
256  */
257 static bool CAIPGetAddrInfo(int idx, u_arraylist_t *iflist)
258 {
259     if ((idx < 0) || (iflist == NULL))
260     {
261         return false;
262     }
263
264     struct ifaddrs *ifp = NULL;
265     if (-1 == getifaddrs(&ifp))
266     {
267         OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs: %s", strerror(errno));
268         return false;
269     }
270
271     struct ifaddrs *ifa = NULL;
272     for (ifa = ifp; ifa; ifa = ifa->ifa_next)
273     {
274         if (!ifa->ifa_addr)
275         {
276             continue;
277         }
278
279         int family = ifa->ifa_addr->sa_family;
280         if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
281         {
282             continue;
283         }
284
285         int ifindex = if_nametoindex(ifa->ifa_name);
286         if (idx && (ifindex != idx))
287         {
288             continue;
289         }
290
291         char ipaddr[MAX_ADDR_STR_SIZE_CA] = {0};
292         if (family == AF_INET6)
293         {
294             struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
295             inet_ntop(family, (void *)&(in6->sin6_addr), ipaddr, sizeof(ipaddr));
296         }
297         else if (family == AF_INET)
298         {
299             struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
300             inet_ntop(family, (void *)&(in->sin_addr), ipaddr, sizeof(ipaddr));
301         }
302
303         if ((strcmp(ipaddr, IFC_ADDR_LOOP_IPV4) == 0) ||
304             (strcmp(ipaddr, IFC_ADDR_LOOP_IPV6) == 0) ||
305             (strcmp(ifa->ifa_name, IFC_LABEL_LOOP) == 0))
306         {
307             OIC_LOG(DEBUG, TAG, "LOOPBACK continue!!!");
308             continue;
309         }
310
311         CAResult_t result = CAAddInterfaceItem(iflist, ifindex,
312                                                ifa->ifa_name, family,
313                                                ipaddr, ifa->ifa_flags);
314         if (CA_STATUS_OK != result)
315         {
316             OIC_LOG(ERROR, TAG, "CAAddInterfaceItem fail");
317             goto exit;
318         }
319     }
320     freeifaddrs(ifp);
321     return true;
322
323 exit:
324     freeifaddrs(ifp);
325     return false;
326 }
327
328 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
329 {
330     u_arraylist_t *iflist = u_arraylist_create();
331     if (!iflist)
332     {
333         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
334         return NULL;
335     }
336
337     if (!CAIPGetAddrInfo(desiredIndex, iflist))
338     {
339         goto exit;
340     }
341
342     return iflist;
343
344 exit:
345     u_arraylist_destroy(iflist);
346     return NULL;
347 }
348
349 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
350                                      char *name, int family, const char *addr, int flags)
351 {
352     CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
353     if (!ifitem)
354     {
355         return CA_STATUS_FAILED;
356     }
357     bool result = u_arraylist_add(iflist, ifitem);
358     if (!result)
359     {
360         OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
361         OICFree(ifitem);
362         return CA_STATUS_FAILED;
363     }
364
365     return CA_STATUS_OK;
366 }
367
368 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
369                                          const char *addr, int flags)
370 {
371     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
372     if (!ifitem)
373     {
374         OIC_LOG(ERROR, TAG, "Malloc failed");
375         return NULL;
376     }
377
378     OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, name);
379     ifitem->index = index;
380     ifitem->family = family;
381     OICStrcpy(ifitem->addr, sizeof(ifitem->addr), addr);
382     ifitem->flags = flags;
383
384     return ifitem;
385 }
386
387 void CAIPConnectionStateChangedCb(connection_type_e type, void* userData)
388 {
389     (void)userData;
390
391     switch (type)
392     {
393         case CONNECTION_TYPE_DISCONNECTED:
394             OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_DISCONNECTED");
395             CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
396             break;
397         case CONNECTION_TYPE_ETHERNET:
398             OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_ETHERNET");
399             CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
400             break;
401         case CONNECTION_TYPE_WIFI:
402             OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_WIFI");
403             CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
404             break;
405         case CONNECTION_TYPE_CELLULAR:
406             OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_CELLULAR");
407             CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
408             break;
409         default:
410             break;
411     }
412 }