[IOT-1528]update file path and remove static analysis warring
[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 "caipinterface.h"
22
23 #include <sys/types.h>
24 #include <ifaddrs.h>
25 #include <net/if.h>
26 #include <sys/socket.h>
27 #include <netdb.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <sys/ioctl.h>
32 #include <wifi.h>
33 #include <linux/netlink.h>
34 #include <linux/rtnetlink.h>
35 #include <arpa/inet.h>
36 #include <netinet/in.h>
37
38 #include "caipnwmonitor.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 "IP_MONITOR"
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 adapter changes callback interface.
53  */
54 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
55
56 /**
57  * Create new interface item.
58  */
59 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
60                                          const char *addr, int flags);
61
62 /**
63  * Add new network interface in list.
64  */
65 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
66                                      char *name, int family, const char *addr, int flags);
67
68 /**
69  * Pass the changed network status through the stored callback.
70  */
71 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
72
73 /**
74  * Callback function to received connection state changes.
75  */
76 static void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
77                                            void *userData);
78
79 /**
80  * Callback function to received device state changes.
81  */
82 static void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData);
83
84 int CAGetPollingInterval(int interval)
85 {
86     return interval;
87 }
88
89 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
90 {
91     CAIPCBData_t *cbitem = NULL;
92     LL_FOREACH(g_adapterCallbackList, cbitem)
93     {
94         if (cbitem && cbitem->adapter)
95         {
96             cbitem->callback(cbitem->adapter, status);
97         }
98     }
99 }
100
101 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
102                                          CATransportAdapter_t adapter)
103 {
104     if (!callback)
105     {
106         OIC_LOG(ERROR, TAG, "callback is null");
107         return CA_STATUS_INVALID_PARAM;
108     }
109
110     CAIPCBData_t *cbitem = NULL;
111     LL_FOREACH(g_adapterCallbackList, cbitem)
112     {
113         if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
114         {
115             OIC_LOG(DEBUG, TAG, "this callback is already added");
116             return CA_STATUS_OK;
117         }
118     }
119
120     cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
121     if (!cbitem)
122     {
123         OIC_LOG(ERROR, TAG, "Malloc failed");
124         return CA_STATUS_FAILED;
125     }
126
127     cbitem->adapter = adapter;
128     cbitem->callback = callback;
129     LL_APPEND(g_adapterCallbackList, cbitem);
130
131     return CA_STATUS_OK;
132 }
133
134 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
135 {
136     CAIPCBData_t *cbitem = NULL;
137     CAIPCBData_t *tmpCbitem = NULL;
138     LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
139     {
140         if (cbitem && adapter == cbitem->adapter)
141         {
142             OIC_LOG(DEBUG, TAG, "remove specific callback");
143             LL_DELETE(g_adapterCallbackList, cbitem);
144             OICFree(cbitem);
145             return CA_STATUS_OK;
146         }
147     }
148     return CA_STATUS_OK;
149 }
150
151 u_arraylist_t *CAFindInterfaceChange()
152 {
153     u_arraylist_t *iflist = NULL;
154     char buf[NETLINK_MESSAGE_LENGTH] = { 0 };
155     struct sockaddr_nl sa = { 0 };
156     struct iovec iov = { .iov_base = buf,
157                          .iov_len = sizeof (buf) };
158     struct msghdr msg = { .msg_name = (void *)&sa,
159                           .msg_namelen = sizeof (sa),
160                           .msg_iov = &iov,
161                           .msg_iovlen = 1 };
162
163     ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
164
165     for (struct nlmsghdr *nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
166     {
167         if (nh != NULL && nh->nlmsg_type != RTM_NEWLINK)
168         {
169             continue;
170         }
171         struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
172
173         if ((!ifi || (ifi->ifi_flags & IFF_LOOPBACK) || !(ifi->ifi_flags & IFF_RUNNING)))
174         {
175             continue;
176         }
177
178         int ifiIndex = ifi->ifi_index;
179
180         iflist = CAIPGetInterfaceInformation(ifiIndex);
181
182         if (!iflist)
183         {
184             OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
185             return NULL;
186         }
187     }
188     return iflist;
189 }
190
191 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
192                                    CATransportAdapter_t adapter)
193 {
194     OIC_LOG(DEBUG, TAG, "IN");
195
196     if (!g_adapterCallbackList)
197     {
198         // Initialize Wifi service
199        wifi_error_e ret = wifi_initialize();
200        if (WIFI_ERROR_NONE != ret)
201        {
202            OIC_LOG(ERROR, TAG, "wifi_initialize failed");
203            return CA_STATUS_FAILED;
204        }
205
206        // Set callback for receiving state changes
207        ret = wifi_set_device_state_changed_cb(CAWIFIDeviceStateChangedCb, NULL);
208        if (WIFI_ERROR_NONE != ret)
209        {
210            OIC_LOG(ERROR, TAG, "wifi_set_device_state_changed_cb failed");
211            return CA_STATUS_FAILED;
212        }
213
214        // Set callback for receiving connection state changes
215        ret = wifi_set_connection_state_changed_cb(CAWIFIConnectionStateChangedCb, NULL);
216        if (WIFI_ERROR_NONE != ret)
217        {
218            OIC_LOG(ERROR, TAG, "wifi_set_connection_state_changed_cb failed");
219            return CA_STATUS_FAILED;
220        }
221     }
222
223     return CAIPSetNetworkMonitorCallback(callback, adapter);
224 }
225
226 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
227 {
228     OIC_LOG(DEBUG, TAG, "IN");
229
230     CAIPUnSetNetworkMonitorCallback(adapter);
231     if (!g_adapterCallbackList)
232     {
233         // Reset callback for receiving state changes
234        wifi_error_e ret = wifi_unset_device_state_changed_cb();
235        if (WIFI_ERROR_NONE != ret)
236        {
237            OIC_LOG(ERROR, TAG, "wifi_unset_device_state_changed_cb failed");
238        }
239
240        // Reset callback for receiving connection state changes
241        ret = wifi_unset_connection_state_changed_cb();
242        if (WIFI_ERROR_NONE != ret)
243        {
244            OIC_LOG(ERROR, TAG, "wifi_unset_connection_state_changed_cb failed");
245        }
246
247        // Deinitialize Wifi service
248        ret = wifi_deinitialize();
249        if (WIFI_ERROR_NONE != ret)
250        {
251            OIC_LOG(ERROR, TAG, "wifi_deinitialize failed");
252        }
253     }
254
255     return CA_STATUS_OK;
256 }
257
258 /**
259  * Used to send netlink query to kernel and recv response from kernel.
260  *
261  * @param[in]   idx       desired network interface index, 0 means all interfaces.
262  * @param[out]  iflist    linked list.
263  *
264  */
265 static bool CAIPGetAddrInfo(int idx, u_arraylist_t *iflist)
266 {
267     if ((idx < 0) || (iflist == NULL))
268     {
269         return false;
270     }
271
272     struct ifaddrs *ifp = NULL;
273     if (-1 == getifaddrs(&ifp))
274     {
275         OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs: %s", strerror(errno));
276         return false;
277     }
278
279     struct ifaddrs *ifa = NULL;
280     for (ifa = ifp; ifa; ifa = ifa->ifa_next)
281     {
282         if (!ifa->ifa_addr)
283         {
284             continue;
285         }
286
287         int family = ifa->ifa_addr->sa_family;
288         if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
289         {
290             continue;
291         }
292
293         int ifindex = if_nametoindex(ifa->ifa_name);
294         if (idx && (ifindex != idx))
295         {
296             continue;
297         }
298
299         char ipaddr[MAX_ADDR_STR_SIZE_CA] = {0};
300         if (family == AF_INET6)
301         {
302             struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
303             inet_ntop(family, (void *)&(in6->sin6_addr), ipaddr, sizeof(ipaddr));
304         }
305         else if (family == AF_INET)
306         {
307             struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
308             inet_ntop(family, (void *)&(in->sin_addr), ipaddr, sizeof(ipaddr));
309         }
310
311         if ((strcmp(ipaddr, IFC_ADDR_LOOP_IPV4) == 0) ||
312             (strcmp(ipaddr, IFC_ADDR_LOOP_IPV6) == 0) ||
313             (strcmp(ifa->ifa_name, IFC_LABEL_LOOP) == 0))
314         {
315             OIC_LOG(DEBUG, TAG, "LOOPBACK continue!!!");
316             continue;
317         }
318
319         CAResult_t result = CAAddInterfaceItem(iflist, ifindex,
320                                                ifa->ifa_name, family,
321                                                ipaddr, ifa->ifa_flags);
322         if (CA_STATUS_OK != result)
323         {
324             OIC_LOG(ERROR, TAG, "CAAddInterfaceItem fail");
325             goto exit;
326         }
327     }
328     freeifaddrs(ifp);
329     return true;
330
331 exit:
332     freeifaddrs(ifp);
333     return false;
334 }
335
336 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
337 {
338     u_arraylist_t *iflist = u_arraylist_create();
339     if (!iflist)
340     {
341         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
342         return NULL;
343     }
344
345     if (!CAIPGetAddrInfo(desiredIndex, iflist))
346     {
347         goto exit;
348     }
349
350     return iflist;
351
352 exit:
353     u_arraylist_destroy(iflist);
354     return NULL;
355 }
356
357 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
358                                      char *name, int family, const char *addr, int flags)
359 {
360     CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
361     if (!ifitem)
362     {
363         return CA_STATUS_FAILED;
364     }
365     bool result = u_arraylist_add(iflist, ifitem);
366     if (!result)
367     {
368         OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
369         OICFree(ifitem);
370         return CA_STATUS_FAILED;
371     }
372
373     return CA_STATUS_OK;
374 }
375
376 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
377                                          const char *addr, int flags)
378 {
379     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
380     if (!ifitem)
381     {
382         OIC_LOG(ERROR, TAG, "Malloc failed");
383         return NULL;
384     }
385
386     OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, name);
387     ifitem->index = index;
388     ifitem->family = family;
389     OICStrcpy(ifitem->addr, sizeof(ifitem->addr), addr);
390     ifitem->flags = flags;
391
392     return ifitem;
393 }
394
395 void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
396                                     void *userData)
397 {
398     OIC_LOG(DEBUG, TAG, "IN");
399
400     if (WIFI_CONNECTION_STATE_ASSOCIATION == state
401         || WIFI_CONNECTION_STATE_CONFIGURATION == state)
402     {
403         OIC_LOG(DEBUG, TAG, "Connection is in Association State");
404         return;
405     }
406
407     if (WIFI_CONNECTION_STATE_CONNECTED == state)
408     {
409         CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
410     }
411     else
412     {
413         CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
414     }
415
416     OIC_LOG(DEBUG, TAG, "OUT");
417 }
418
419 void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData)
420 {
421     OIC_LOG(DEBUG, TAG, "IN");
422
423     if (WIFI_DEVICE_STATE_ACTIVATED == state)
424     {
425         OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
426     }
427     else
428     {
429         CAWIFIConnectionStateChangedCb(WIFI_CONNECTION_STATE_DISCONNECTED, NULL, NULL);
430         OIC_LOG(DEBUG, TAG, "Wifi is in Deactivated State");
431     }
432
433     OIC_LOG(DEBUG, TAG, "OUT");
434 }