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 = TEMP_FAILURE_RETRY(send(netlinkFd, data, len, 0));
54 return (sentByteCount == (ssize_t)(len));
57 void CAFreeIfAddrs(struct ifaddrs *ifa)
59 struct ifaddrs *cur = NULL;
64 OICFree(cur->ifa_name);
65 OICFree(cur->ifa_addr);
71 static struct ifaddrs *CAParsingAddr(struct nlmsghdr *recvMsg)
73 struct ifaddrmsg *ifaddrmsgData = (struct ifaddrmsg*)NLMSG_DATA(recvMsg);
74 if (ifaddrmsgData-> ifa_family != AF_INET && ifaddrmsgData-> ifa_family != AF_INET6)
79 struct rtattr *rtattrData = (struct rtattr*)IFA_RTA(ifaddrmsgData);
80 int ifaddrmsgLen = IFA_PAYLOAD(recvMsg);
82 struct ifaddrs *node = (struct ifaddrs *)OICCalloc(1, sizeof(struct ifaddrs));
83 VERIFY_NON_NULL(node);
85 char nameBuf[IFNAMSIZ] = { 0 };
86 node->ifa_next = NULL;
87 if_indextoname(ifaddrmsgData->ifa_index, nameBuf);
88 node->ifa_name = (char *)OICCalloc(strlen(nameBuf)+1, sizeof(char));
89 VERIFY_NON_NULL(node->ifa_name);
91 OICStrcpy(node->ifa_name, strlen(nameBuf)+1, nameBuf);
92 node->ifa_flags = ifaddrmsgData->ifa_flags;
93 node->ifa_flags |= (IFF_UP|IFF_RUNNING);
95 struct sockaddr_storage* ss = NULL;
97 for (; RTA_OK(rtattrData, ifaddrmsgLen); rtattrData = RTA_NEXT(rtattrData, ifaddrmsgLen))
99 switch (rtattrData->rta_type)
102 ss = (struct sockaddr_storage*)OICCalloc(1, sizeof(struct sockaddr_storage));
105 ss->ss_family = ifaddrmsgData-> ifa_family;
107 if (ifaddrmsgData-> ifa_family == AF_INET)
109 dest = &((struct sockaddr_in*)ss)->sin_addr;
110 memcpy(dest, RTA_DATA(rtattrData), RTA_PAYLOAD(rtattrData));
112 else if (ifaddrmsgData-> ifa_family == AF_INET6)
114 dest = &((struct sockaddr_in6*)ss)->sin6_addr;
115 memcpy(dest, RTA_DATA(rtattrData), RTA_PAYLOAD(rtattrData));
118 node->ifa_addr = (struct sockaddr*)ss;
133 CAResult_t CAGetIfaddrsUsingNetlink(struct ifaddrs **ifap)
137 OIC_LOG(ERROR, TAG, "netlink argument error");
138 return CA_STATUS_INVALID_PARAM;
142 int netlinkFd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE);
143 CAResult_t state = CA_STATUS_FAILED;
146 OIC_LOG_V(ERROR, TAG, "netlink socket failed: %s", strerror(errno));
147 return CA_SOCKET_OPERATION_FAILED;
150 // send request to kernel
152 memset(&req, 0, sizeof(req));
153 req.msgInfo.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req)));
154 req.msgInfo.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
155 req.msgInfo.nlmsg_type = RTM_GETADDR;
156 req.ifaddrInfo.ifa_family = AF_UNSPEC;
157 req.ifaddrInfo.ifa_index = 0;
159 if (!CASendNetlinkMessage(netlinkFd, &req, req.msgInfo.nlmsg_len))
161 OIC_LOG(ERROR, TAG, "netlink send failed");
162 state = CA_SOCKET_OPERATION_FAILED;
168 char recvBuf[NETLINK_MESSAGE_LENGTH] = {0};
169 struct nlmsghdr *recvMsg = NULL;
170 struct ifaddrs *node = NULL;
171 struct sockaddr_nl sa = { .nl_family = 0 };
172 struct iovec iov = { .iov_base = recvBuf,
173 .iov_len = sizeof (recvBuf) };
175 struct msghdr msg = { .msg_name = (void *)&sa,
176 .msg_namelen = sizeof (sa),
180 ssize_t len = recvmsg(netlinkFd, &msg, 0);
182 for (recvMsg = (struct nlmsghdr *)recvBuf; NLMSG_OK(recvMsg, len);
183 recvMsg = NLMSG_NEXT(recvMsg, len))
185 switch (recvMsg->nlmsg_type)
188 OIC_LOG(DEBUG, TAG, "NLMSG_DONE");
189 state = CA_STATUS_OK;
193 OIC_LOG(ERROR, TAG, "NLMSG is invalid");
194 state = CA_SOCKET_OPERATION_FAILED;
198 node = CAParsingAddr(recvMsg);
199 state = CA_MEMORY_ALLOC_FAILED;
200 VERIFY_NON_NULL(node);
201 state = CA_STATUS_OK;
209 node->ifa_next = *ifap;
218 OIC_LOG(DEBUG, TAG, "ignore unknown NLMSG");
225 // release all resources
227 if (state != CA_STATUS_OK)
229 CAFreeIfAddrs(*ifap);