1 /*
2  * Copyright (C) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "mac_address.h"
17 #include <unistd.h>
18 #include <algorithm>
19 #include <cctype>
20 #include <cstdlib>
21 #include <securec.h>
22 #include <net/if.h>
23 #include <net/if_arp.h>
24 #include <netinet/if_ether.h>
25 #include <sys/ioctl.h>
26 #include <sys/socket.h>
27 #include "wifi_log.h"
28 
29 #undef LOG_TAG
30 #define LOG_TAG "OHWIFI_UTIL_MacAddress"
31 
32 static constexpr char INVALID_MAC[MAC_STRING_LENGTH + 1] = "00:00:00:00:00:00"; /* Indicates an invalid MAC address. */
33 static constexpr int MAC_BLOCK = 2;
34 constexpr int INTERVAL = 3; /* MAC addresses:character spacing */
35 constexpr int HEX_BASE = 16;
36 
37 namespace OHOS {
38 namespace Wifi {
39 const MacAddress MacAddress::INVALID_MAC_ADDRESS = MacAddress(INVALID_MAC);
40 
IsValidMac(const std::string & mac)41 bool MacAddress::IsValidMac(const std::string &mac)
42 {
43     if (mac.length() != MAC_STRING_LENGTH) {
44         return false;
45     }
46 
47     if (INVALID_MAC_ADDRESS.GetMacAddressWifiString() == mac) {
48         return false;
49     }
50 
51     std::string macBuf = mac;
52     std::transform(macBuf.begin(), macBuf.end(), macBuf.begin(), ::tolower);
53 
54     for (size_t i = 0; i < MAC_STRING_LENGTH; i++) {
55         if (i % INTERVAL == MAC_BLOCK) {
56             if (macBuf[i] != ':') {
57                 return false;
58             }
59         } else {
60             if ((macBuf[i] < '0' || macBuf[i] > '9') && (macBuf[i] < 'a' || macBuf[i] > 'f')) {
61                 return false;
62             }
63         }
64     }
65 
66     return true;
67 }
68 
Create(const std::string & mac)69 MacAddress MacAddress::Create(const std::string &mac)
70 {
71     if (IsValidMac(mac)) {
72         std::string macBuf = mac;
73         std::transform(macBuf.begin(), macBuf.end(), macBuf.begin(), ::tolower);
74         return MacAddress(macBuf);
75     }
76 
77     return INVALID_MAC_ADDRESS;
78 }
79 
Create(const sockaddr & hwAddr)80 MacAddress MacAddress::Create(const sockaddr &hwAddr)
81 {
82     char mac[MAC_STRING_LENGTH + 1];
83     if (snprintf_s(mac,
84         sizeof(mac),
85         sizeof(mac) - 1,
86         "%02x:%02x:%02x:%02x:%02x:%02x",
87         (unsigned char)hwAddr.sa_data[ZERO],
88         (unsigned char)hwAddr.sa_data[ONE],
89         (unsigned char)hwAddr.sa_data[TWO],
90         (unsigned char)hwAddr.sa_data[THREE],
91         (unsigned char)hwAddr.sa_data[FOUR],
92         (unsigned char)hwAddr.sa_data[FIVE]) < 0) {
93         return INVALID_MAC_ADDRESS;
94     }
95 
96     return Create(mac);
97 }
98 
MacAddress(const std::string & mac)99 MacAddress::MacAddress(const std::string &mac) : mac_(mac)
100 {}
101 
operator ==(const MacAddress & mac) const102 bool MacAddress::operator==(const MacAddress &mac) const
103 {
104     return mac_ == mac.mac_;
105 }
106 
operator ==(const struct sockaddr & hwAddr) const107 bool MacAddress::operator==(const struct sockaddr &hwAddr) const
108 {
109     MacAddress mac = Create(hwAddr);
110     return mac_ == mac.mac_;
111 }
112 
IsValid() const113 bool MacAddress::IsValid() const
114 {
115     return IsValidMac(mac_);
116 }
117 
Dump() const118 void MacAddress::Dump() const
119 {
120     LOGI("MAC: [%{private}s]", mac_.c_str());
121 }
122 
GetMacAddressWifiString() const123 const std::string &MacAddress::GetMacAddressWifiString() const
124 {
125     return mac_;
126 }
127 
GetMacAddressWifiSockaddr() const128 struct sockaddr MacAddress::GetMacAddressWifiSockaddr() const
129 {
130     struct sockaddr hwAddr = {0};
131     hwAddr.sa_family = 1; /* Ethernet 10Mbps */
132 
133     for (size_t i = 0; i < mac_.length(); i += INTERVAL) {
134         std::string byte = mac_.substr(i, MAC_BLOCK);
135         hwAddr.sa_data[i / INTERVAL] = static_cast<char>(strtol(byte.c_str(), nullptr, HEX_BASE));
136     }
137     return hwAddr;
138 }
139 
GetMacAddr(const std::string & ifName,unsigned char macAddr[MAC_LEN])140 bool MacAddress::GetMacAddr(const std::string& ifName, unsigned char macAddr[MAC_LEN])
141 {
142     struct ifreq ifr;
143     if (memset_s(&ifr, sizeof(ifr), 0, sizeof(ifr)) != EOK ||
144         strcpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), ifName.c_str()) != EOK) {
145         LOGE("Init the ifreq struct failed!");
146         return false;
147     }
148     int fd = socket(AF_INET, SOCK_DGRAM, 0);
149     if (fd < 0) {
150         LOGE("get mac addr socket error");
151         return false;
152     }
153 
154     ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
155     if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
156         LOGE("get mac addr ioctl SIOCGIFHWADDR error");
157         close(fd);
158         return false;
159     }
160 
161     if (memcpy_s(macAddr, ETH_ALEN, ifr.ifr_hwaddr.sa_data, ETH_ALEN) != EOK) {
162         LOGE("get mac addr memcpy_s error");
163         close(fd);
164         return false;
165     }
166     close(fd);
167     return true;
168 }
169 } // namespace WiFi
170 } // namespace OHOS
171