Enable IPv6 Interface for Android, Tizen
[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 "caadapterutils.h"
39 #include "logger.h"
40 #include "oic_malloc.h"
41 #include "oic_string.h"
42
43 #define TAG "IP_MONITOR"
44
45 #define MAX_INTERFACE_INFO_LENGTH (1024)
46
47 #define NETLINK_MESSAGE_LENGTH  (4096)
48
49 static CAIPConnectionStateChangeCallback g_networkChangeCallback;
50
51 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
52                                          const char *addr, int flags);
53
54 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
55                                      char *name, int family, const char *addr, int flags);
56
57 static void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
58                                            void *userData);
59
60 static void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData);
61
62
63 int CAGetPollingInterval(int interval)
64 {
65     return interval;
66 }
67
68 void CAIPSetNetworkMonitorCallback(CAIPConnectionStateChangeCallback callback)
69 {
70     g_networkChangeCallback = callback;
71 }
72
73 CAInterface_t *CAFindInterfaceChange()
74 {
75     CAInterface_t *foundNewInterface = NULL;
76     char buf[NETLINK_MESSAGE_LENGTH] = { 0 };
77     struct sockaddr_nl sa = { 0 };
78     struct iovec iov = { .iov_base = buf,
79                          .iov_len = sizeof (buf) };
80     struct msghdr msg = { .msg_name = (void *)&sa,
81                           .msg_namelen = sizeof (sa),
82                           .msg_iov = &iov,
83                           .msg_iovlen = 1 };
84
85     size_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
86
87     for (struct nlmsghdr *nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
88     {
89         if (nh != NULL && nh->nlmsg_type != RTM_NEWLINK)
90         {
91             continue;
92         }
93
94         struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
95
96         int ifiIndex = ifi->ifi_index;
97         u_arraylist_t *iflist = CAIPGetInterfaceInformation(ifiIndex);
98
99         if ((!ifi || (ifi->ifi_flags & IFF_LOOPBACK) || !(ifi->ifi_flags & IFF_RUNNING)))
100         {
101             continue;
102         }
103
104         if (!iflist)
105         {
106             OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
107             return NULL;
108         }
109
110         uint32_t listLength = u_arraylist_length(iflist);
111         for (uint32_t i = 0; i < listLength; i++)
112         {
113             CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
114             if (!ifitem)
115             {
116                 continue;
117             }
118
119             if ((int)ifitem->index != ifiIndex)
120             {
121                 continue;
122             }
123
124             foundNewInterface = CANewInterfaceItem(ifitem->index, ifitem->name, ifitem->family,
125                                                    ifitem->addr, ifitem->flags);
126             break;    // we found the one we were looking for
127         }
128         u_arraylist_destroy(iflist);
129     }
130     return foundNewInterface;
131 }
132
133 CAResult_t CAIPStartNetworkMonitor()
134 {
135     OIC_LOG(DEBUG, TAG, "IN");
136
137      // Initialize Wifi service
138     wifi_error_e ret = wifi_initialize();
139     if (WIFI_ERROR_NONE != ret)
140     {
141         OIC_LOG(ERROR, TAG, "wifi_initialize failed");
142         return CA_STATUS_FAILED;
143     }
144
145     // Set callback for receiving state changes
146     ret = wifi_set_device_state_changed_cb(CAWIFIDeviceStateChangedCb, NULL);
147     if (WIFI_ERROR_NONE != ret)
148     {
149         OIC_LOG(ERROR, TAG, "wifi_set_device_state_changed_cb failed");
150         return CA_STATUS_FAILED;
151     }
152
153     // Set callback for receiving connection state changes
154     ret = wifi_set_connection_state_changed_cb(CAWIFIConnectionStateChangedCb, NULL);
155     if (WIFI_ERROR_NONE != ret)
156     {
157         OIC_LOG(ERROR, TAG, "wifi_set_connection_state_changed_cb failed");
158         return CA_STATUS_FAILED;
159     }
160
161     OIC_LOG(DEBUG, TAG, "OUT");
162     return CA_STATUS_OK;
163 }
164
165 CAResult_t CAIPStopNetworkMonitor()
166 {
167     OIC_LOG(DEBUG, TAG, "IN");
168
169      // Reset callback for receiving state changes
170     wifi_error_e ret = wifi_unset_device_state_changed_cb();
171     if (WIFI_ERROR_NONE != ret)
172     {
173         OIC_LOG(ERROR, TAG, "wifi_unset_device_state_changed_cb failed");
174     }
175
176     // Reset callback for receiving connection state changes
177     ret = wifi_unset_connection_state_changed_cb();
178     if (WIFI_ERROR_NONE != ret)
179     {
180         OIC_LOG(ERROR, TAG, "wifi_unset_connection_state_changed_cb failed");
181     }
182
183     // Deinitialize Wifi service
184     ret = wifi_deinitialize();
185     if (WIFI_ERROR_NONE != ret)
186     {
187         OIC_LOG(ERROR, TAG, "wifi_deinitialize failed");
188     }
189
190     OIC_LOG(DEBUG, TAG, "OUT");
191     return CA_STATUS_OK;
192 }
193
194 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
195 {
196     u_arraylist_t *iflist = u_arraylist_create();
197     if (!iflist)
198     {
199         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
200         return NULL;
201     }
202
203     char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
204     struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
205
206     int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
207     if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
208     {
209         OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
210         u_arraylist_destroy(iflist);
211         return NULL;
212     }
213
214     struct ifreq* ifr = ifc.ifc_req;
215     size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
216     size_t ifreqsize = ifc.ifc_len;
217
218     if (ifreqsize > caglobals.ip.nm.sizeIfItems)
219     {
220         CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
221         if (!items)
222         {
223             OIC_LOG(ERROR, TAG, "OICRealloc failed");
224             goto exit;
225         }
226         caglobals.ip.nm.ifItems = items;
227         caglobals.ip.nm.sizeIfItems = ifreqsize;
228     }
229
230     caglobals.ip.nm.numIfItems = 0;
231     for (size_t i = 0; i < interfaces; i++)
232     {
233         struct ifreq* item = &ifr[i];
234         char *name = item->ifr_name;
235
236         if (ioctl(s, SIOCGIFFLAGS, item) < 0)
237         {
238             OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
239             continue;
240         }
241         int16_t flags = item->ifr_flags;
242         if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
243         {
244             continue;
245         }
246         if (ioctl(s, SIOCGIFINDEX, item) < 0)
247         {
248             OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
249             continue;
250         }
251
252         int ifindex = item->ifr_ifindex;
253         caglobals.ip.nm.ifItems[i].ifIndex = ifindex;
254         caglobals.ip.nm.numIfItems++;
255
256         if (desiredIndex && (ifindex != desiredIndex))
257         {
258             continue;
259         }
260
261         // Get address of network interface.
262         char addr[MAX_ADDR_STR_SIZE_CA] = { 0 };
263         struct sockaddr_in *sa = (struct sockaddr_in *)&item->ifr_addr;
264         inet_ntop(AF_INET, (void *)&(sa->sin_addr), addr, sizeof(addr));
265
266         // Add IPv4 interface
267         CAResult_t result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, addr, flags);
268         if (CA_STATUS_OK != result)
269         {
270             goto exit;
271         }
272
273         // Add IPv6 interface
274         result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, addr, flags);
275         if (CA_STATUS_OK != result)
276         {
277             goto exit;
278         }
279     }
280     return iflist;
281
282 exit:
283     u_arraylist_destroy(iflist);
284     return NULL;
285 }
286
287 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
288                                      char *name, int family, const char *addr, int flags)
289 {
290     CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
291     if (!ifitem)
292     {
293         return CA_STATUS_FAILED;
294     }
295     bool result = u_arraylist_add(iflist, ifitem);
296     if (!result)
297     {
298         OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
299         OICFree(ifitem);
300         return CA_STATUS_FAILED;
301     }
302
303     return CA_STATUS_OK;
304 }
305
306 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
307                                          const char *addr, int flags)
308 {
309     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
310     if (!ifitem)
311     {
312         OIC_LOG(ERROR, TAG, "Malloc failed");
313         return NULL;
314     }
315
316     OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, name);
317     ifitem->index = index;
318     ifitem->family = family;
319     OICStrcpy(ifitem->addr, sizeof(ifitem->addr), addr);
320     ifitem->flags = flags;
321
322     return ifitem;
323 }
324
325 void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
326                                     void *userData)
327 {
328     OIC_LOG(DEBUG, TAG, "IN");
329
330     if (WIFI_CONNECTION_STATE_ASSOCIATION == state
331         || WIFI_CONNECTION_STATE_CONFIGURATION == state)
332     {
333         OIC_LOG(DEBUG, TAG, "Connection is in Association State");
334         return;
335     }
336
337     if (WIFI_CONNECTION_STATE_CONNECTED == state)
338     {
339         g_networkChangeCallback(CA_ADAPTER_IP, CA_INTERFACE_UP);
340     }
341     else
342     {
343         g_networkChangeCallback(CA_ADAPTER_IP, CA_INTERFACE_DOWN);
344     }
345
346     OIC_LOG(DEBUG, TAG, "OUT");
347 }
348
349 void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData)
350 {
351     OIC_LOG(DEBUG, TAG, "IN");
352
353     if (WIFI_DEVICE_STATE_ACTIVATED == state)
354     {
355         OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
356     }
357     else
358     {
359         CAWIFIConnectionStateChangedCb(WIFI_CONNECTION_STATE_DISCONNECTED, NULL, NULL);
360         OIC_LOG(DEBUG, TAG, "Wifi is in Deactivated State");
361     }
362
363     OIC_LOG(DEBUG, TAG, "OUT");
364 }