[IOT-1361]Change "CAFindInterfaceChange()" to support IPv4/6
[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
47 #define MAX_INTERFACE_INFO_LENGTH (1024)
48
49 #define NETLINK_MESSAGE_LENGTH  (4096)
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
85 int CAGetPollingInterval(int interval)
86 {
87     return interval;
88 }
89
90 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
91 {
92     CAIPCBData_t *cbitem = NULL;
93     LL_FOREACH(g_adapterCallbackList, cbitem)
94     {
95         if (cbitem && cbitem->adapter)
96         {
97             cbitem->callback(cbitem->adapter, status);
98         }
99     }
100 }
101
102 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
103                                          CATransportAdapter_t adapter)
104 {
105     if (!callback)
106     {
107         OIC_LOG(ERROR, TAG, "callback is null");
108         return CA_STATUS_INVALID_PARAM;
109     }
110
111     CAIPCBData_t *cbitem = NULL;
112     LL_FOREACH(g_adapterCallbackList, cbitem)
113     {
114         if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
115         {
116             OIC_LOG(DEBUG, TAG, "this callback is already added");
117             return CA_STATUS_OK;
118         }
119     }
120
121     cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
122     if (!cbitem)
123     {
124         OIC_LOG(ERROR, TAG, "Malloc failed");
125         return CA_STATUS_FAILED;
126     }
127
128     cbitem->adapter = adapter;
129     cbitem->callback = callback;
130     LL_APPEND(g_adapterCallbackList, cbitem);
131
132     return CA_STATUS_OK;
133 }
134
135 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
136 {
137     CAIPCBData_t *cbitem = NULL;
138     CAIPCBData_t *tmpCbitem = NULL;
139     LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
140     {
141         if (cbitem && adapter == cbitem->adapter)
142         {
143             OIC_LOG(DEBUG, TAG, "remove specific callback");
144             LL_DELETE(g_adapterCallbackList, cbitem);
145             OICFree(cbitem);
146             return CA_STATUS_OK;
147         }
148     }
149     return CA_STATUS_OK;
150 }
151
152 u_arraylist_t *CAFindInterfaceChange()
153 {
154     u_arraylist_t *iflist = NULL;
155     char buf[NETLINK_MESSAGE_LENGTH] = { 0 };
156     struct sockaddr_nl sa = { 0 };
157     struct iovec iov = { .iov_base = buf,
158                          .iov_len = sizeof (buf) };
159     struct msghdr msg = { .msg_name = (void *)&sa,
160                           .msg_namelen = sizeof (sa),
161                           .msg_iov = &iov,
162                           .msg_iovlen = 1 };
163
164     size_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
165
166     for (struct nlmsghdr *nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
167     {
168         if (nh != NULL && nh->nlmsg_type != RTM_NEWLINK)
169         {
170             continue;
171         }
172
173         struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
174
175         if ((!ifi || (ifi->ifi_flags & IFF_LOOPBACK) || !(ifi->ifi_flags & IFF_RUNNING)))
176         {
177             continue;
178         }
179
180         int ifiIndex = ifi->ifi_index;
181         iflist = CAIPGetInterfaceInformation(ifiIndex);
182
183         if (!iflist)
184         {
185             OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
186             return NULL;
187         }
188     }
189     return iflist;
190 }
191
192 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
193                                    CATransportAdapter_t adapter)
194 {
195     OIC_LOG(DEBUG, TAG, "IN");
196
197     if (!g_adapterCallbackList)
198     {
199         // Initialize Wifi service
200        wifi_error_e ret = wifi_initialize();
201        if (WIFI_ERROR_NONE != ret)
202        {
203            OIC_LOG(ERROR, TAG, "wifi_initialize failed");
204            return CA_STATUS_FAILED;
205        }
206
207        // Set callback for receiving state changes
208        ret = wifi_set_device_state_changed_cb(CAWIFIDeviceStateChangedCb, NULL);
209        if (WIFI_ERROR_NONE != ret)
210        {
211            OIC_LOG(ERROR, TAG, "wifi_set_device_state_changed_cb failed");
212            return CA_STATUS_FAILED;
213        }
214
215        // Set callback for receiving connection state changes
216        ret = wifi_set_connection_state_changed_cb(CAWIFIConnectionStateChangedCb, NULL);
217        if (WIFI_ERROR_NONE != ret)
218        {
219            OIC_LOG(ERROR, TAG, "wifi_set_connection_state_changed_cb failed");
220            return CA_STATUS_FAILED;
221        }
222     }
223
224     return CAIPSetNetworkMonitorCallback(callback, adapter);
225 }
226
227 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
228 {
229     OIC_LOG(DEBUG, TAG, "IN");
230
231     CAIPUnSetNetworkMonitorCallback(adapter);
232     if (!g_adapterCallbackList)
233     {
234         // Reset callback for receiving state changes
235        wifi_error_e ret = wifi_unset_device_state_changed_cb();
236        if (WIFI_ERROR_NONE != ret)
237        {
238            OIC_LOG(ERROR, TAG, "wifi_unset_device_state_changed_cb failed");
239        }
240
241        // Reset callback for receiving connection state changes
242        ret = wifi_unset_connection_state_changed_cb();
243        if (WIFI_ERROR_NONE != ret)
244        {
245            OIC_LOG(ERROR, TAG, "wifi_unset_connection_state_changed_cb failed");
246        }
247
248        // Deinitialize Wifi service
249        ret = wifi_deinitialize();
250        if (WIFI_ERROR_NONE != ret)
251        {
252            OIC_LOG(ERROR, TAG, "wifi_deinitialize failed");
253        }
254     }
255
256     return CA_STATUS_OK;
257 }
258
259 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
260 {
261     u_arraylist_t *iflist = u_arraylist_create();
262     if (!iflist)
263     {
264         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
265         return NULL;
266     }
267
268     char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
269     struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
270
271     int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
272     if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
273     {
274         OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
275         u_arraylist_destroy(iflist);
276         return NULL;
277     }
278
279     struct ifreq* ifr = ifc.ifc_req;
280     size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
281     size_t ifreqsize = ifc.ifc_len;
282
283     if (ifreqsize > caglobals.ip.nm.sizeIfItems)
284     {
285         CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
286         if (!items)
287         {
288             OIC_LOG(ERROR, TAG, "OICRealloc failed");
289             goto exit;
290         }
291         caglobals.ip.nm.ifItems = items;
292         caglobals.ip.nm.sizeIfItems = ifreqsize;
293     }
294
295     caglobals.ip.nm.numIfItems = 0;
296     for (size_t i = 0; i < interfaces; i++)
297     {
298         struct ifreq* item = &ifr[i];
299         char *name = item->ifr_name;
300
301         if (ioctl(s, SIOCGIFFLAGS, item) < 0)
302         {
303             OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
304             continue;
305         }
306         int16_t flags = item->ifr_flags;
307         if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
308         {
309             continue;
310         }
311         if (ioctl(s, SIOCGIFINDEX, item) < 0)
312         {
313             OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
314             continue;
315         }
316
317         int ifindex = item->ifr_ifindex;
318         caglobals.ip.nm.ifItems[i].ifIndex = ifindex;
319         caglobals.ip.nm.numIfItems++;
320
321         if (desiredIndex && (ifindex != desiredIndex))
322         {
323             continue;
324         }
325
326         // Get address of network interface.
327         char addr[MAX_ADDR_STR_SIZE_CA] = { 0 };
328         struct sockaddr_in *sa = (struct sockaddr_in *)&item->ifr_addr;
329         inet_ntop(AF_INET, (void *)&(sa->sin_addr), addr, sizeof(addr));
330
331         // Add IPv4 interface
332         CAResult_t result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, addr, flags);
333         if (CA_STATUS_OK != result)
334         {
335             goto exit;
336         }
337
338         // Add IPv6 interface
339         result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, addr, flags);
340         if (CA_STATUS_OK != result)
341         {
342             goto exit;
343         }
344     }
345     return iflist;
346
347 exit:
348     u_arraylist_destroy(iflist);
349     return NULL;
350 }
351
352 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
353                                      char *name, int family, const char *addr, int flags)
354 {
355     CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
356     if (!ifitem)
357     {
358         return CA_STATUS_FAILED;
359     }
360     bool result = u_arraylist_add(iflist, ifitem);
361     if (!result)
362     {
363         OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
364         OICFree(ifitem);
365         return CA_STATUS_FAILED;
366     }
367
368     return CA_STATUS_OK;
369 }
370
371 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
372                                          const char *addr, int flags)
373 {
374     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
375     if (!ifitem)
376     {
377         OIC_LOG(ERROR, TAG, "Malloc failed");
378         return NULL;
379     }
380
381     OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, name);
382     ifitem->index = index;
383     ifitem->family = family;
384     OICStrcpy(ifitem->addr, sizeof(ifitem->addr), addr);
385     ifitem->flags = flags;
386
387     return ifitem;
388 }
389
390 void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
391                                     void *userData)
392 {
393     OIC_LOG(DEBUG, TAG, "IN");
394
395     if (WIFI_CONNECTION_STATE_ASSOCIATION == state
396         || WIFI_CONNECTION_STATE_CONFIGURATION == state)
397     {
398         OIC_LOG(DEBUG, TAG, "Connection is in Association State");
399         return;
400     }
401
402     if (WIFI_CONNECTION_STATE_CONNECTED == state)
403     {
404         CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
405     }
406     else
407     {
408         CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
409     }
410
411     OIC_LOG(DEBUG, TAG, "OUT");
412 }
413
414 void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData)
415 {
416     OIC_LOG(DEBUG, TAG, "IN");
417
418     if (WIFI_DEVICE_STATE_ACTIVATED == state)
419     {
420         OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
421     }
422     else
423     {
424         CAWIFIConnectionStateChangedCb(WIFI_CONNECTION_STATE_DISCONNECTED, NULL, NULL);
425         OIC_LOG(DEBUG, TAG, "Wifi is in Deactivated State");
426     }
427
428     OIC_LOG(DEBUG, TAG, "OUT");
429 }