1 /*
2 * Copyright (C) 2024 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 "wifi_netlink.h"
17 #include <asm/types.h>
18 #include <cstdlib>
19 #include <cstring>
20 #include <iostream>
21 #include <unistd.h>
22 #include "securec.h"
23 #include <linux/netlink.h>
24 #include "wifi_logger.h"
25
26 namespace OHOS {
27 namespace Wifi {
28 DEFINE_WIFILOG_LABEL("WifiNetLink");
29 static const int32_t NETLINK_WIFIPRO_EVENT_NL = 24;
30 static const int32_t NEW_INT_ARR_LENGTH = 10;
31 static const int32_t QOS_RTT = 0;
32 static const int32_t QOS_RTT_PKTS = 1;
33 static const int32_t QOS_RTT_WHEN = 2;
34 static const int32_t QOS_CONGESTION = 3;
35 static const int32_t QOS_CONG_WHEN = 4;
36 static const int32_t QOS_TCP_QUALITY = 5;
37 static const int32_t QOS_TCP_TX_PKTS = 6;
38 static const int32_t QOS_TCP_RX_PKTS = 7;
39 static const int32_t QOS_TCP_RETRANS_PKTS = 8;
40 static const int32_t QOS_MSG_FROM = 9;
41
42 enum WifiKnlMsgType {
43 NETLINK_WIFIPRO_START_MONITOR = 0,
44 NETLINK_WIFIPRO_GET_MSG,
45 };
46
47 enum CmdWord {
48 CMD_START_MONITOR = 10,
49 CMD_QUERY_PKTS = 15,
50 MSG_REPORT_IPQOS = 100,
51 };
52
53 struct WifiNlPacketMsg {
54 uint32_t msgFrom;
55 uint32_t rtt;
56 uint32_t rttPkts;
57 uint32_t rttWhen;
58 uint32_t congestion;
59 uint32_t congWhen;
60 uint32_t tcpQuality;
61 uint32_t tcpTxPkts;
62 uint32_t tcpRxPkts;
63 uint32_t tcpRetransPkts;
64 };
65
66 struct TagMsg2Knl {
67 struct nlmsghdr hdr;
68 };
69
70 struct PacketInfo {
71 struct nlmsghdr hdr;
72 struct WifiNlPacketMsg qos;
73 };
74
GetInstance()75 WifiNetLink &WifiNetLink::GetInstance()
76 {
77 static WifiNetLink gWifiNetLink;
78 return gWifiNetLink;
79 }
80
InitWifiNetLink(const WifiNetLinkCallbacks & wifiNetLinkCallbacks)81 void WifiNetLink::InitWifiNetLink(const WifiNetLinkCallbacks &wifiNetLinkCallbacks)
82 {
83 mWifiNetLinkCallbacks = wifiNetLinkCallbacks;
84 }
85
SendCmdKernel(int32_t sockFd,int32_t cmd,int32_t flag)86 int32_t WifiNetLink::SendCmdKernel(int32_t sockFd, int32_t cmd, int32_t flag)
87 {
88 int32_t ret = -1;
89 struct timeval tv;
90 struct sockaddr_nl stKpeer;
91 struct TagMsg2Knl stMessage;
92 if (memset_s(&stKpeer, sizeof(stKpeer), 0, sizeof(stKpeer)) != EOK) {
93 WIFI_LOGE("SendCmdKernel memset_s failed stKpeer");
94 return ret;
95 }
96 stKpeer.nl_family = AF_NETLINK;
97 stKpeer.nl_pid = 0;
98 stKpeer.nl_groups = 0;
99
100 if (memset_s(&stMessage, sizeof(struct TagMsg2Knl), 0, sizeof(struct TagMsg2Knl)) != EOK) {
101 WIFI_LOGE("SendCmdKernel memset_s failed stMessage.");
102 return ret;
103 }
104 stMessage.hdr.nlmsg_len = static_cast<unsigned int>(NLMSG_LENGTH(0));
105 stMessage.hdr.nlmsg_flags = flag;
106 stMessage.hdr.nlmsg_type = cmd;
107 stMessage.hdr.nlmsg_pid = static_cast<unsigned int>(getpid());
108 tv.tv_sec = 1;
109 tv.tv_usec = 0;
110 if (setsockopt(sockFd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
111 WIFI_LOGE("socket option SO_RCVTIMEO not support.");
112 return ret;
113 }
114 ret = sendto(sockFd, &stMessage, stMessage.hdr.nlmsg_len, 0,
115 reinterpret_cast<struct sockaddr *>(&stKpeer), sizeof(stKpeer));
116 if (ret == -1) {
117 WIFI_LOGE("send %{public}d to kernel failed!!!", cmd);
118 }
119 return ret;
120 }
121
StartMonitor(int32_t sockFd)122 int32_t WifiNetLink::StartMonitor(int32_t sockFd)
123 {
124 return SendCmdKernel(sockFd, NETLINK_WIFIPRO_START_MONITOR, 0);
125 }
126
ProcessQueryTcp(int32_t sockFd)127 int32_t WifiNetLink::ProcessQueryTcp(int32_t sockFd)
128 {
129 return SendCmdKernel(sockFd, NETLINK_WIFIPRO_GET_MSG, 0);
130 }
131
SendQoeCmd(int32_t cmd,int32_t arg)132 int32_t WifiNetLink::SendQoeCmd(int32_t cmd, int32_t arg)
133 {
134 int32_t sockFd = -1;
135 int32_t sendResult = -1;
136 bool isNeedReport = false;
137 int32_t ret = -1;
138 sockFd = socket(PF_NETLINK, SOCK_RAW, NETLINK_WIFIPRO_EVENT_NL);
139 if (sockFd < 0) {
140 WIFI_LOGE("%{public}s: open monitor_fd error, sockFd: %{public}d, errno: %{public}d",
141 __FUNCTION__, sockFd, errno);
142 return ret;
143 }
144 switch (cmd) {
145 case CMD_START_MONITOR:
146 sendResult = StartMonitor(sockFd);
147 break;
148 case CMD_QUERY_PKTS:
149 sendResult = ProcessQueryTcp(sockFd);
150 isNeedReport = true;
151 break;
152 default:
153 break;
154 }
155 if (sendResult != -1 && isNeedReport) {
156 ret = ProcessReportMsg(sockFd, cmd);
157 close(sockFd);
158 return ret;
159 }
160 close(sockFd);
161 return sendResult;
162 }
163
ProcessReportMsg(int32_t sockFd,int32_t cmd)164 int32_t WifiNetLink::ProcessReportMsg(int32_t sockFd, int32_t cmd)
165 {
166 WIFI_LOGI("ProcessReportMsg cmd = %{public}d", cmd);
167 struct sockaddr_nl stKpeer;
168 struct PacketInfo info;
169 struct timeval tv;
170 int32_t uiKpeerLen = 0;
171 int32_t uiRcvLen = 0;
172
173 stKpeer.nl_family = AF_NETLINK;
174 stKpeer.nl_pid = 0;
175 stKpeer.nl_groups = 0;
176 uiKpeerLen = sizeof(struct sockaddr_nl);
177
178 tv.tv_sec = 1;
179 tv.tv_usec = 0;
180 if (setsockopt(sockFd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
181 WIFI_LOGE("socket option SO_RCVTIMEO not support.");
182 return -1;
183 }
184
185 uiRcvLen = recvfrom(sockFd, &info, sizeof(struct PacketInfo), 0,
186 reinterpret_cast<struct sockaddr *>(&stKpeer), reinterpret_cast<socklen_t *>(&uiKpeerLen));
187 if (uiRcvLen > 0) {
188 std::vector<int64_t> elems(NEW_INT_ARR_LENGTH, 0);
189 elems[QOS_RTT] = info.qos.rtt;
190 elems[QOS_RTT_PKTS] = info.qos.rttPkts;
191 elems[QOS_RTT_WHEN] = info.qos.rttWhen;
192 elems[QOS_CONGESTION] = info.qos.congestion;
193 elems[QOS_CONG_WHEN] = info.qos.congWhen;
194 elems[QOS_TCP_QUALITY] = info.qos.tcpQuality;
195 elems[QOS_TCP_TX_PKTS] = info.qos.tcpTxPkts;
196 elems[QOS_TCP_RX_PKTS] = info.qos.tcpRxPkts;
197 elems[QOS_TCP_RETRANS_PKTS] = info.qos.tcpRetransPkts;
198 elems[QOS_MSG_FROM] = info.qos.msgFrom;
199 mWifiNetLinkCallbacks.OnTcpReportMsgComplete(elems, cmd, mInstId);
200 return 0;
201 } else {
202 WIFI_LOGI("Received invalid message info.hdr.nlmsg_type = %{public}d", info.hdr.nlmsg_type);
203 return -1;
204 }
205 }
206
207 } // namespace Wifi
208 } // namespace OHOS
209