1 /* *****************************************************************
3 * Copyright 2016 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 "caifaddrs.h"
22 #include "oic_malloc.h"
23 #include "oic_string.h"
30 #include <sys/socket.h>
31 #include <net/if_arp.h>
33 #include <netinet/in.h>
34 #include <linux/netlink.h>
35 #include <linux/rtnetlink.h>
37 #define TAG "OIC_CA_IFADDRS"
38 #define VERIFY_NON_NULL(arg) { if (!arg) {OIC_LOG(ERROR, TAG, #arg " is NULL"); goto exit;} }
40 #define NETLINK_MESSAGE_LENGTH (4096)
41 #define IFC_LABEL_LOOP "lo"
42 #define IFC_ADDR_LOOP_IPV4 "127.0.0.1"
43 #define IFC_ADDR_LOOP_IPV6 "::1"
46 struct nlmsghdr msgInfo;
47 struct ifaddrmsg ifaddrInfo;
51 static bool CASendNetlinkMessage(int netlinkFd, const void* data, size_t len)
53 ssize_t sentByteCount = 0;
54 sentByteCount = TEMP_FAILURE_RETRY(send(netlinkFd, data, len, 0));
55 return (sentByteCount == (ssize_t)(len));
58 void CAFreeIfAddrs(struct ifaddrs *ifa)
60 struct ifaddrs *cur = NULL;
65 OICFree(cur->ifa_name);
66 OICFree(cur->ifa_addr);
72 static struct ifaddrs *CAParsingAddr(struct nlmsghdr *recvMsg)
74 struct ifaddrmsg *ifaddrmsgData = (struct ifaddrmsg*)NLMSG_DATA(recvMsg);
75 if (ifaddrmsgData-> ifa_family != AF_INET && ifaddrmsgData-> ifa_family != AF_INET6)
80 struct rtattr *rtattrData = (struct rtattr*)IFA_RTA(ifaddrmsgData);
81 int ifaddrmsgLen = IFA_PAYLOAD(recvMsg);
83 struct ifaddrs *node = (struct ifaddrs *)OICCalloc(1, sizeof(struct ifaddrs));
84 VERIFY_NON_NULL(node);
86 char nameBuf[IFNAMSIZ] = { 0 };
87 node->ifa_next = NULL;
88 if_indextoname(ifaddrmsgData->ifa_index, nameBuf);
89 node->ifa_name = (char *)OICCalloc(strlen(nameBuf)+1, sizeof(char));
90 VERIFY_NON_NULL(node->ifa_name);
92 OICStrcpy(node->ifa_name, strlen(nameBuf)+1, nameBuf);
93 node->ifa_flags = ifaddrmsgData->ifa_flags;
94 node->ifa_flags |= (IFF_UP|IFF_RUNNING);
96 struct sockaddr_storage* ss = NULL;
98 for (; RTA_OK(rtattrData, ifaddrmsgLen); rtattrData = RTA_NEXT(rtattrData, ifaddrmsgLen))
100 switch (rtattrData->rta_type)
103 ss = (struct sockaddr_storage*)OICCalloc(1, sizeof(struct sockaddr_storage));
106 ss->ss_family = ifaddrmsgData-> ifa_family;
108 if (ifaddrmsgData-> ifa_family == AF_INET)
110 dest = &((struct sockaddr_in*)ss)->sin_addr;
111 memcpy(dest, RTA_DATA(rtattrData), RTA_PAYLOAD(rtattrData));
113 else if (ifaddrmsgData-> ifa_family == AF_INET6)
115 dest = &((struct sockaddr_in6*)ss)->sin6_addr;
116 memcpy(dest, RTA_DATA(rtattrData), RTA_PAYLOAD(rtattrData));
119 node->ifa_addr = (struct sockaddr*)ss;
134 CAResult_t CAGetIfaddrsUsingNetlink(struct ifaddrs **ifap)
138 OIC_LOG(ERROR, TAG, "netlink argument error");
139 return CA_STATUS_INVALID_PARAM;
143 int netlinkFd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE);
144 CAResult_t state = CA_STATUS_FAILED;
147 OIC_LOG_V(ERROR, TAG, "netlink socket failed: %s", strerror(errno));
148 return CA_SOCKET_OPERATION_FAILED;
151 // send request to kernel
153 memset(&req, 0, sizeof(req));
154 req.msgInfo.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req)));
155 req.msgInfo.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
156 req.msgInfo.nlmsg_type = RTM_GETADDR;
157 req.ifaddrInfo.ifa_family = AF_UNSPEC;
158 req.ifaddrInfo.ifa_index = 0;
160 if (!CASendNetlinkMessage(netlinkFd, &req, req.msgInfo.nlmsg_len))
162 OIC_LOG(ERROR, TAG, "netlink send failed");
163 state = CA_SOCKET_OPERATION_FAILED;
169 char recvBuf[NETLINK_MESSAGE_LENGTH] = {0};
170 struct nlmsghdr *recvMsg = NULL;
171 struct ifaddrs *node = NULL;
172 struct sockaddr_nl sa = { .nl_family = 0 };
173 struct iovec iov = { .iov_base = recvBuf,
174 .iov_len = sizeof (recvBuf) };
176 struct msghdr msg = { .msg_name = (void *)&sa,
177 .msg_namelen = sizeof (sa),
181 ssize_t len = recvmsg(netlinkFd, &msg, 0);
183 for (recvMsg = (struct nlmsghdr *)recvBuf; NLMSG_OK(recvMsg, len);
184 recvMsg = NLMSG_NEXT(recvMsg, len))
186 switch (recvMsg->nlmsg_type)
189 OIC_LOG(DEBUG, TAG, "NLMSG_DONE");
190 state = CA_STATUS_OK;
194 OIC_LOG(ERROR, TAG, "NLMSG is invalid");
195 state = CA_SOCKET_OPERATION_FAILED;
199 node = CAParsingAddr(recvMsg);
200 state = CA_MEMORY_ALLOC_FAILED;
201 VERIFY_NON_NULL(node);
202 state = CA_STATUS_OK;
210 node->ifa_next = *ifap;
219 OIC_LOG(DEBUG, TAG, "ignore unknown NLMSG");
226 // release all resources
228 if (state != CA_STATUS_OK)
230 CAFreeIfAddrs(*ifap);