1 /******************************************************************
3 * Copyright 2014 Samsung Electronics All Rights Reserved.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 ******************************************************************/
21 #include "caipinterface.h"
23 #include <sys/types.h>
26 #include <sys/socket.h>
31 #include <sys/ioctl.h>
33 #include <linux/netlink.h>
34 #include <linux/rtnetlink.h>
35 #include <arpa/inet.h>
36 #include <netinet/in.h>
38 #include "caadapterutils.h"
40 #include "oic_malloc.h"
41 #include "oic_string.h"
43 #define TAG "IP_MONITOR"
45 #define MAX_INTERFACE_INFO_LENGTH (1024)
47 #define NETLINK_MESSAGE_LENGTH (4096)
49 static CAIPConnectionStateChangeCallback g_networkChangeCallback;
51 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
52 uint32_t addr, int flags);
54 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
55 char *name, int family, uint32_t addr, int flags);
57 static void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
60 static void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData);
63 int CAGetPollingInterval(int interval)
68 void CAIPSetNetworkMonitorCallback(CAIPConnectionStateChangeCallback callback)
70 g_networkChangeCallback = callback;
73 CAInterface_t *CAFindInterfaceChange()
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),
85 size_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
87 for (struct nlmsghdr *nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
89 if (nh != NULL && nh->nlmsg_type != RTM_NEWLINK)
94 struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
96 int ifiIndex = ifi->ifi_index;
97 u_arraylist_t *iflist = CAIPGetInterfaceInformation(ifiIndex);
99 if ((!ifi || (ifi->ifi_flags & IFF_LOOPBACK) || !(ifi->ifi_flags & IFF_RUNNING)))
106 OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
110 uint32_t listLength = u_arraylist_length(iflist);
111 for (uint32_t i = 0; i < listLength; i++)
113 CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
119 if ((int)ifitem->index != ifiIndex)
125 foundNewInterface = CANewInterfaceItem(ifitem->index, ifitem->name, ifitem->family,
126 ifitem->ipv4addr, ifitem->flags);
127 break; // we found the one we were looking for
129 u_arraylist_destroy(iflist);
131 return foundNewInterface;
134 CAResult_t CAIPStartNetworkMonitor()
136 OIC_LOG(DEBUG, TAG, "IN");
138 // Initialize Wifi service
139 wifi_error_e ret = wifi_initialize();
140 if (WIFI_ERROR_NONE != ret)
142 OIC_LOG(ERROR, TAG, "wifi_initialize failed");
143 return CA_STATUS_FAILED;
146 // Set callback for receiving state changes
147 ret = wifi_set_device_state_changed_cb(CAWIFIDeviceStateChangedCb, NULL);
148 if (WIFI_ERROR_NONE != ret)
150 OIC_LOG(ERROR, TAG, "wifi_set_device_state_changed_cb failed");
151 return CA_STATUS_FAILED;
154 // Set callback for receiving connection state changes
155 ret = wifi_set_connection_state_changed_cb(CAWIFIConnectionStateChangedCb, NULL);
156 if (WIFI_ERROR_NONE != ret)
158 OIC_LOG(ERROR, TAG, "wifi_set_connection_state_changed_cb failed");
159 return CA_STATUS_FAILED;
162 OIC_LOG(DEBUG, TAG, "OUT");
166 CAResult_t CAIPStopNetworkMonitor()
168 OIC_LOG(DEBUG, TAG, "IN");
170 // Reset callback for receiving state changes
171 wifi_error_e ret = wifi_unset_device_state_changed_cb();
172 if (WIFI_ERROR_NONE != ret)
174 OIC_LOG(ERROR, TAG, "wifi_unset_device_state_changed_cb failed");
177 // Reset callback for receiving connection state changes
178 ret = wifi_unset_connection_state_changed_cb();
179 if (WIFI_ERROR_NONE != ret)
181 OIC_LOG(ERROR, TAG, "wifi_unset_connection_state_changed_cb failed");
184 // Deinitialize Wifi service
185 ret = wifi_deinitialize();
186 if (WIFI_ERROR_NONE != ret)
188 OIC_LOG(ERROR, TAG, "wifi_deinitialize failed");
191 OIC_LOG(DEBUG, TAG, "OUT");
195 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
197 u_arraylist_t *iflist = u_arraylist_create();
200 OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
204 char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
205 struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
207 int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
208 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
210 OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
211 u_arraylist_destroy(iflist);
215 struct ifreq* ifr = ifc.ifc_req;
216 size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
217 size_t ifreqsize = ifc.ifc_len;
219 if (ifreqsize > caglobals.ip.nm.sizeIfItems)
221 CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
224 OIC_LOG(ERROR, TAG, "OICRealloc failed");
227 caglobals.ip.nm.ifItems = items;
228 caglobals.ip.nm.sizeIfItems = ifreqsize;
231 caglobals.ip.nm.numIfItems = 0;
232 for (size_t i = 0; i < interfaces; i++)
234 struct ifreq* item = &ifr[i];
235 char *name = item->ifr_name;
236 struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
237 uint32_t ipv4addr = sa4->sin_addr.s_addr;
239 if (ioctl(s, SIOCGIFFLAGS, item) < 0)
241 OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
244 int16_t flags = item->ifr_flags;
245 if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
249 if (ioctl(s, SIOCGIFINDEX, item) < 0)
251 OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
255 int ifindex = item->ifr_ifindex;
256 caglobals.ip.nm.ifItems[i].ifIndex = ifindex;
257 caglobals.ip.nm.numIfItems++;
259 if (desiredIndex && (ifindex != desiredIndex))
264 // Add IPv4 interface
265 CAResult_t result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, ipv4addr, flags);
266 if (CA_STATUS_OK != result)
271 // Add IPv6 interface
272 result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, ipv4addr, flags);
273 if (CA_STATUS_OK != result)
281 u_arraylist_destroy(iflist);
285 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
286 char *name, int family, uint32_t addr, int flags)
288 CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
291 return CA_STATUS_FAILED;
293 bool result = u_arraylist_add(iflist, ifitem);
296 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
298 return CA_STATUS_FAILED;
304 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
305 uint32_t addr, int flags)
307 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
310 OIC_LOG(ERROR, TAG, "Malloc failed");
314 OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, name);
315 ifitem->index = index;
316 ifitem->family = family;
317 ifitem->ipv4addr = addr;
318 ifitem->flags = flags;
323 void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
326 OIC_LOG(DEBUG, TAG, "IN");
328 if (WIFI_CONNECTION_STATE_ASSOCIATION == state
329 || WIFI_CONNECTION_STATE_CONFIGURATION == state)
331 OIC_LOG(DEBUG, TAG, "Connection is in Association State");
335 if (WIFI_CONNECTION_STATE_CONNECTED == state)
337 g_networkChangeCallback(CA_ADAPTER_IP, CA_INTERFACE_UP);
341 g_networkChangeCallback(CA_ADAPTER_IP, CA_INTERFACE_DOWN);
344 OIC_LOG(DEBUG, TAG, "OUT");
347 void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData)
349 OIC_LOG(DEBUG, TAG, "IN");
351 if (WIFI_DEVICE_STATE_ACTIVATED == state)
353 OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
357 CAWIFIConnectionStateChangedCb(WIFI_CONNECTION_STATE_DISCONNECTED, NULL, NULL);
358 OIC_LOG(DEBUG, TAG, "Wifi is in Deactivated State");
361 OIC_LOG(DEBUG, TAG, "OUT");