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"
28 #include <sys/socket.h>
29 #include <net/if_arp.h>
30 #include <netinet/in.h>
31 #include <linux/netlink.h>
32 #include <linux/rtnetlink.h>
34 #define TAG "OIC_CA_ifaddrs"
36 #define NETLINK_MESSAGE_LENGTH (4096)
37 #define IFC_LABEL_LOOP "lo"
38 #define IFC_ADDR_LOOP_IPV4 "127.0.0.1"
39 #define IFC_ADDR_LOOP_IPV6 "::1"
42 struct nlmsghdr msgInfo;
43 struct ifaddrmsg ifaddrInfo;
47 static bool CASendNetlinkMessage(int netlinkFd, const void* data, size_t len)
49 ssize_t sentByteCount = TEMP_FAILURE_RETRY(send(netlinkFd, data, len, 0));
50 return (sentByteCount == (ssize_t)(len));
53 void CAFreeIfAddrs(struct ifaddrs *ifa)
64 static struct ifaddrs *CAParsingAddr(struct nlmsghdr *recvMsg)
66 struct ifaddrmsg *ifaddrmsgData = (struct ifaddrmsg*)NLMSG_DATA(recvMsg);
67 if (ifaddrmsgData-> ifa_family != AF_INET && ifaddrmsgData-> ifa_family != AF_INET6)
72 struct rtattr *rtattrData = (struct rtattr*)IFA_RTA(ifaddrmsgData);
73 int ifaddrmsgLen = IFA_PAYLOAD(recvMsg);
75 struct ifaddrs *node = (struct ifaddrs *)OICCalloc(1, sizeof(struct ifaddrs));
76 char nameBuf[IFNAMSIZ] = { 0 };
77 node->ifa_next = NULL;
78 if_indextoname(ifaddrmsgData->ifa_index, nameBuf);
79 node->ifa_name = (char *)OICCalloc(strlen(nameBuf)+1, sizeof(char));
80 OICStrcpy(node->ifa_name, strlen(nameBuf)+1, nameBuf);
81 node->ifa_flags = ifaddrmsgData->ifa_flags;
82 node->ifa_flags |= (IFF_UP|IFF_RUNNING);
84 struct sockaddr_storage* ss = NULL;
86 for (; RTA_OK(rtattrData, ifaddrmsgLen); rtattrData = RTA_NEXT(rtattrData, ifaddrmsgLen))
88 switch (rtattrData->rta_type)
91 ss = (struct sockaddr_storage*)OICCalloc(1, sizeof(struct sockaddr_storage));
92 ss->ss_family = ifaddrmsgData-> ifa_family;
94 if (ifaddrmsgData-> ifa_family == AF_INET)
96 dest = &((struct sockaddr_in*)ss)->sin_addr;
97 memcpy(dest, RTA_DATA(rtattrData), RTA_PAYLOAD(rtattrData));
99 else if (ifaddrmsgData-> ifa_family == AF_INET6)
101 dest = &((struct sockaddr_in6*)ss)->sin6_addr;
102 memcpy(dest, RTA_DATA(rtattrData), RTA_PAYLOAD(rtattrData));
105 node->ifa_addr = (struct sockaddr*)ss;
117 CAResult_t CAGetIfaddrsUsingNetlink(struct ifaddrs **ifap)
121 OIC_LOG(ERROR, TAG, "netlink argument error");
122 return CA_STATUS_INVALID_PARAM;
126 int netlinkFd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE);
130 OIC_LOG_V(ERROR, TAG, "netlink socket failed: %s", strerror(errno));
131 return CA_SOCKET_OPERATION_FAILED;
134 // send request to kernel
136 memset(&req, 0, sizeof(req));
137 req.msgInfo.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req)));
138 req.msgInfo.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
139 req.msgInfo.nlmsg_type = RTM_GETADDR;
140 req.ifaddrInfo.ifa_family = AF_UNSPEC;
141 req.ifaddrInfo.ifa_index = 0;
143 if (!CASendNetlinkMessage(netlinkFd, &req, req.msgInfo.nlmsg_len))
145 OIC_LOG(ERROR, TAG, "netlink send failed");
151 char recvBuf[NETLINK_MESSAGE_LENGTH] = {0};
152 struct nlmsghdr *recvMsg = NULL;
153 struct ifaddrs *node = NULL;
154 struct sockaddr_nl sa = { .nl_family = 0 };
155 struct iovec iov = { .iov_base = recvBuf,
156 .iov_len = sizeof (recvBuf) };
158 struct msghdr msg = { .msg_name = (void *)&sa,
159 .msg_namelen = sizeof (sa),
163 ssize_t len = recvmsg(netlinkFd, &msg, 0);
165 for (recvMsg = (struct nlmsghdr *)recvBuf; NLMSG_OK(recvMsg, len);
166 recvMsg = NLMSG_NEXT(recvMsg, len))
168 switch (recvMsg->nlmsg_type)
171 OIC_LOG(DEBUG, TAG, "NLMSG_DONE");
176 OIC_LOG(ERROR, TAG, "NLMSG is invalid");
181 OIC_LOG(DEBUG, TAG, "RTM_NEWADDR");
182 node = CAParsingAddr(recvMsg);
190 node->ifa_next = *ifap;
198 OIC_LOG(DEBUG, TAG, "ignore unknown NLMSG");
206 // release all resources
210 CAFreeIfAddrs(*ifap);
211 return CA_SOCKET_OPERATION_FAILED;