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