xref: /aosp_15_r20/external/ot-br-posix/src/ncp/posix/netif_linux.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1 /*
2  *  Copyright (c) 2024, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #ifdef __linux__
30 
31 #define OTBR_LOG_TAG "NETIF"
32 
33 #include "netif.hpp"
34 
35 #include <assert.h>
36 #include <fcntl.h>
37 #include <linux/if.h>
38 #include <linux/if_tun.h>
39 #include <linux/netlink.h>
40 #include <linux/rtnetlink.h>
41 #include <net/if.h>
42 #include <net/if_arp.h>
43 #include <sys/ioctl.h>
44 #include <unistd.h>
45 
46 #include "common/code_utils.hpp"
47 #include "common/logging.hpp"
48 #include "common/types.hpp"
49 #include "utils/socket_utils.hpp"
50 
51 #ifndef OTBR_POSIX_TUN_DEVICE
52 #define OTBR_POSIX_TUN_DEVICE "/dev/net/tun"
53 #endif
54 
55 namespace otbr {
56 
AddRtAttr(nlmsghdr * aHeader,uint32_t aMaxLen,uint8_t aType,const void * aData,uint8_t aLen)57 static struct rtattr *AddRtAttr(nlmsghdr *aHeader, uint32_t aMaxLen, uint8_t aType, const void *aData, uint8_t aLen)
58 {
59     uint8_t len = RTA_LENGTH(aLen);
60     rtattr *rta;
61 
62     assert(NLMSG_ALIGN(aHeader->nlmsg_len) + RTA_ALIGN(len) <= aMaxLen);
63     OTBR_UNUSED_VARIABLE(aMaxLen);
64 
65     rta           = reinterpret_cast<rtattr *>(reinterpret_cast<char *>(aHeader) + NLMSG_ALIGN((aHeader)->nlmsg_len));
66     rta->rta_type = aType;
67     rta->rta_len  = len;
68     if (aLen)
69     {
70         memcpy(RTA_DATA(rta), aData, aLen);
71     }
72     aHeader->nlmsg_len = NLMSG_ALIGN(aHeader->nlmsg_len) + RTA_ALIGN(len);
73 
74     return rta;
75 }
76 
CreateTunDevice(const std::string & aInterfaceName)77 otbrError Netif::CreateTunDevice(const std::string &aInterfaceName)
78 {
79     ifreq     ifr;
80     otbrError error = OTBR_ERROR_NONE;
81 
82     VerifyOrExit(aInterfaceName.size() < IFNAMSIZ, error = OTBR_ERROR_INVALID_ARGS);
83 
84     memset(&ifr, 0, sizeof(ifr));
85     ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
86     if (aInterfaceName.size() > 0)
87     {
88         strncpy(ifr.ifr_name, aInterfaceName.c_str(), aInterfaceName.size());
89     }
90     else
91     {
92         strncpy(ifr.ifr_name, "wpan%d", IFNAMSIZ);
93     }
94 
95     mTunFd = open(OTBR_POSIX_TUN_DEVICE, O_RDWR | O_CLOEXEC | O_NONBLOCK);
96     VerifyOrExit(mTunFd >= 0, error = OTBR_ERROR_ERRNO);
97 
98     VerifyOrExit(ioctl(mTunFd, TUNSETIFF, &ifr) == 0, error = OTBR_ERROR_ERRNO);
99 
100     mNetifName.assign(ifr.ifr_name, strlen(ifr.ifr_name));
101     otbrLogInfo("Netif name: %s", mNetifName.c_str());
102 
103     VerifyOrExit(ioctl(mTunFd, TUNSETLINK, ARPHRD_NONE) == 0, error = OTBR_ERROR_ERRNO);
104 
105     ifr.ifr_mtu = static_cast<int>(kIp6Mtu);
106     VerifyOrExit(ioctl(mIpFd, SIOCSIFMTU, &ifr) == 0, error = OTBR_ERROR_ERRNO);
107 
108 exit:
109     return error;
110 }
111 
InitNetlink(void)112 otbrError Netif::InitNetlink(void)
113 {
114     otbrError error = OTBR_ERROR_NONE;
115 
116     mNetlinkFd = SocketWithCloseExec(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, kSocketNonBlock);
117     VerifyOrExit(mNetlinkFd >= 0, error = OTBR_ERROR_ERRNO);
118 
119 #if defined(SOL_NETLINK)
120     {
121         int enable = 1;
122 
123 #if defined(NETLINK_EXT_ACK)
124         if (setsockopt(mNetlinkFd, SOL_NETLINK, NETLINK_EXT_ACK, &enable, sizeof(enable)) != 0)
125         {
126             otbrLogWarning("Failed to enable NETLINK_EXT_ACK: %s", strerror(errno));
127         }
128 #endif
129 #if defined(NETLINK_CAP_ACK)
130         if (setsockopt(mNetlinkFd, SOL_NETLINK, NETLINK_CAP_ACK, &enable, sizeof(enable)) != 0)
131         {
132             otbrLogWarning("Failed to enable NETLINK_CAP_ACK: %s", strerror(errno));
133         }
134 #endif
135     }
136 #endif
137 
138     {
139         sockaddr_nl sa;
140 
141         memset(&sa, 0, sizeof(sa));
142         sa.nl_family = AF_NETLINK;
143         sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR;
144         VerifyOrExit(bind(mNetlinkFd, reinterpret_cast<sockaddr *>(&sa), sizeof(sa)) == 0, error = OTBR_ERROR_ERRNO);
145     }
146 
147 exit:
148     return error;
149 }
150 
PlatformSpecificInit(void)151 void Netif::PlatformSpecificInit(void)
152 {
153     SetAddrGenModeToNone();
154 }
155 
SetAddrGenModeToNone(void)156 void Netif::SetAddrGenModeToNone(void)
157 {
158     struct
159     {
160         nlmsghdr  nh;
161         ifinfomsg ifi;
162         char      buf[512];
163     } req;
164 
165     const uint8_t mode = IN6_ADDR_GEN_MODE_NONE;
166 
167     memset(&req, 0, sizeof(req));
168 
169     req.nh.nlmsg_len   = NLMSG_LENGTH(sizeof(ifinfomsg));
170     req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
171     req.nh.nlmsg_type  = RTM_NEWLINK;
172     req.nh.nlmsg_pid   = 0;
173     req.nh.nlmsg_seq   = ++mNetlinkSequence;
174 
175     req.ifi.ifi_index  = static_cast<int>(mNetifIndex);
176     req.ifi.ifi_change = 0xffffffff;
177     req.ifi.ifi_flags  = IFF_MULTICAST | IFF_NOARP;
178 
179     {
180         rtattr *afSpec           = AddRtAttr(&req.nh, sizeof(req), IFLA_AF_SPEC, 0, 0);
181         rtattr *afInet6          = AddRtAttr(&req.nh, sizeof(req), AF_INET6, 0, 0);
182         rtattr *inet6AddrGenMode = AddRtAttr(&req.nh, sizeof(req), IFLA_INET6_ADDR_GEN_MODE, &mode, sizeof(mode));
183 
184         afInet6->rta_len += inet6AddrGenMode->rta_len;
185         afSpec->rta_len += afInet6->rta_len;
186     }
187 
188     if (send(mNetlinkFd, &req, req.nh.nlmsg_len, 0) != -1)
189     {
190         otbrLogInfo("Sent request#%u to set addr_gen_mode to %d", mNetlinkSequence, mode);
191     }
192     else
193     {
194         otbrLogWarning("Failed to send request#%u to set addr_gen_mode to %d", mNetlinkSequence, mode);
195     }
196 }
197 
ProcessUnicastAddressChange(const Ip6AddressInfo & aAddressInfo,bool aIsAdded)198 void Netif::ProcessUnicastAddressChange(const Ip6AddressInfo &aAddressInfo, bool aIsAdded)
199 {
200     struct
201     {
202         nlmsghdr  nh;
203         ifaddrmsg ifa;
204         char      buf[512];
205     } req;
206 
207     assert(mIpFd >= 0);
208     memset(&req, 0, sizeof(req));
209 
210     req.nh.nlmsg_len   = NLMSG_LENGTH(sizeof(ifaddrmsg));
211     req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (aIsAdded ? (NLM_F_CREATE | NLM_F_EXCL) : 0);
212     req.nh.nlmsg_type  = aIsAdded ? RTM_NEWADDR : RTM_DELADDR;
213     req.nh.nlmsg_pid   = 0;
214     req.nh.nlmsg_seq   = ++mNetlinkSequence;
215 
216     req.ifa.ifa_family    = AF_INET6;
217     req.ifa.ifa_prefixlen = aAddressInfo.mPrefixLength;
218     req.ifa.ifa_flags     = IFA_F_NODAD;
219     req.ifa.ifa_scope     = aAddressInfo.mScope;
220     req.ifa.ifa_index     = mNetifIndex;
221 
222     AddRtAttr(&req.nh, sizeof(req), IFA_LOCAL, &aAddressInfo.mAddress, sizeof(aAddressInfo.mAddress));
223 
224     if (!aAddressInfo.mPreferred || aAddressInfo.mMeshLocal)
225     {
226         ifa_cacheinfo cacheinfo;
227 
228         memset(&cacheinfo, 0, sizeof(cacheinfo));
229         cacheinfo.ifa_valid = UINT32_MAX;
230 
231         AddRtAttr(&req.nh, sizeof(req), IFA_CACHEINFO, &cacheinfo, sizeof(cacheinfo));
232     }
233 
234     if (send(mNetlinkFd, &req, req.nh.nlmsg_len, 0) != -1)
235     {
236         otbrLogInfo("Sent request#%u to %s %s/%u", mNetlinkSequence, (aIsAdded ? "add" : "remove"),
237                     Ip6Address(aAddressInfo.mAddress).ToString().c_str(), aAddressInfo.mPrefixLength);
238     }
239     else
240     {
241         otbrLogWarning("Failed to send request#%u to %s %s/%u", mNetlinkSequence, (aIsAdded ? "add" : "remove"),
242                        Ip6Address(aAddressInfo.mAddress).ToString().c_str(), aAddressInfo.mPrefixLength);
243     }
244 }
245 
246 } // namespace otbr
247 
248 #endif // __linux__
249