1 /*
2 * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 /* ****************************************************************************
20 1头文件包含
21 **************************************************************************** */
22
23 #include "hmac_traffic_classify.h"
24 #include "hmac_user.h"
25
26 #ifdef __cplusplus
27 #if __cplusplus
28 extern "C" {
29 #endif
30 #endif
31
32 /* ****************************************************************************
33 2宏定义
34 **************************************************************************** */
35 #define RTP_VERSION 2 /* RTP协议版本号,占2位,当前协议版本号为2 */
36 #define RTP_VER_SHIFT 6 /* RTP协议版本号位移量 */
37 #define RTP_CSRC_MASK 0x0f /* CSRC计数器,占4位,指示CSRC标识符的个数 */
38 #define RTP_CSRC_LEN_BYTE 4 /* 每个CSRC标识符占32位,一共4字节 */
39 #define RTP_HDR_LEN_BYTE 12 /* RTP帧头固定字节数(不包含CSRC字段) */
40 #define TCP_HTTP_VI_LEN_THR 1000 /* HTTP视频流报文长度阈值 */
41 #define JUDGE_CACHE_LIFETIME 1 /* 待识别队列失效时间: 1s */
42 #define IP_FRAGMENT_MASK 0x1FFF /* IP分片Fragment Offset字段 */
43 /* RTP Payload_Type 编号:RFC3551 */
44 #define RTP_PT_VO_G729 18 /* RTP载荷类型:18-Audio-G729 */
45 #define RTP_PT_VI_CELB 25 /* RTP载荷类型:25-Video-CelB */
46 #define RTP_PT_VI_JPEG 26 /* RTP载荷类型:26-Video-JPEG */
47 #define RTP_PT_VI_NV 28 /* RTP载荷类型:28-Video-nv */
48 #define RTP_PT_VI_H261 31 /* RTP载荷类型:31-Video-H261 */
49 #define RTP_PT_VI_MPV 32 /* RTP载荷类型:32-Video-MPV */
50 #define RTP_PT_VI_MP2T 33 /* RTP载荷类型:33-Video-MP2T */
51 #define RTP_PT_VI_H263 34 /* RTP载荷类型:34-Video-H263 */
52 /* HTTP流媒体端口 */
53 #define HTTP_PORT_80 80 /* HTTP协议默认端口号80 */
54 #define HTTP_PORT_8080 8080 /* HTTP协议默认端口号8080 */
55
56 /* ****************************************************************************
57 3 函数实现
58 **************************************************************************** */
59 /* ****************************************************************************
60 函 数 名 : hmac_tx_add_cfm_traffic
61 功能描述 : 将用户已识别业务加入已识别记录表
62 输入参数 : hmac用户结构体指针,TID指针,hmac_tx_major_flow_stru结构体指针
63 输出参数 :
64 返 回 值 : 成功返回HI_SUCCESS,失败返回HI_FAIL
65 调用函数 :
66 被调函数 :
67
68 修改历史 :
69 1.日期: 2015.09.16
70 修改内容: 生成新函数
71 **************************************************************************** */
hmac_tx_add_cfm_traffic(hmac_user_stru * hmac_user,hi_u8 tid,const hmac_tx_major_flow_stru * max)72 static hi_u32 hmac_tx_add_cfm_traffic(hmac_user_stru *hmac_user, hi_u8 tid, const hmac_tx_major_flow_stru *max)
73 {
74 hi_u32 time_stamp;
75 hi_u8 mark = 0;
76 hi_u8 traffic_idx = 0;
77
78 hmac_tx_cfm_flow_stru *cfm_info = HI_NULL;
79
80 if (hmac_user->cfm_num == MAX_CONFIRMED_FLOW_NUM) {
81 /* 已识别列表已满,将列表中最长时间没有来包的业务进行替换 */
82 time_stamp = hmac_user->ast_cfm_flow_list[traffic_idx].last_jiffies;
83
84 for (traffic_idx = 1; traffic_idx < MAX_CONFIRMED_FLOW_NUM; traffic_idx++) {
85 cfm_info = (hmac_user->ast_cfm_flow_list + traffic_idx);
86 if (time_stamp > cfm_info->last_jiffies) {
87 time_stamp = cfm_info->last_jiffies;
88 mark = traffic_idx;
89 }
90 }
91 } else {
92 /* 已识别列表不满,找到可记录的index */
93 for (traffic_idx = 0; traffic_idx < MAX_CONFIRMED_FLOW_NUM; traffic_idx++) {
94 cfm_info = (hmac_user->ast_cfm_flow_list + traffic_idx);
95 if (cfm_info->us_cfm_flag == HI_FALSE) {
96 mark = traffic_idx;
97 hmac_user->cfm_num++;
98 cfm_info->us_cfm_flag = HI_TRUE;
99 break;
100 }
101 }
102 }
103
104 /* 更新列表 */
105 cfm_info = (hmac_user->ast_cfm_flow_list + mark);
106
107 if (memcpy_s(&cfm_info->cfm_flow_info, sizeof(hmac_tx_flow_info_stru), &max->flow_info,
108 sizeof(hmac_tx_flow_info_stru)) != EOK) {
109 oam_error_log0(0, OAM_SF_CFG, "hmac_tx_add_cfm_traffic:: st_flow_info memcpy_s fail.");
110 return HI_FALSE;
111 }
112
113 cfm_info->us_cfm_tid = tid;
114 cfm_info->last_jiffies = hi_get_tick();
115
116 return HI_SUCCESS;
117 }
118
119 /* ****************************************************************************
120 函 数 名 : hmac_tx_traffic_judge
121 功能描述 : 对主要业务进行业务识别处理
122 输入参数 : hmac用户结构体指针,主要业务结构体指针,TID指针
123 输出参数 : TID
124 返 回 值 :
125 调用函数 :
126 被调函数 :
127
128 修改历史 :
129 1.日期: 2015.11.26
130 修改内容: 生成新函数
131 2.日期: 2015.12.26
132 修改内容: TCP识别功能裁剪
133 **************************************************************************** */
hmac_tx_traffic_judge(hmac_user_stru * hmac_user,const hmac_tx_major_flow_stru * major_flow,hi_u8 * puc_tid)134 static hi_u32 hmac_tx_traffic_judge(hmac_user_stru *hmac_user, const hmac_tx_major_flow_stru *major_flow, hi_u8 *puc_tid)
135 {
136 hi_u32 ret = HI_FAIL;
137 hi_u8 cache_idx;
138 hi_u32 pt;
139
140 hmac_tx_judge_list_stru *judge_list = &(hmac_user->judge_list);
141 hmac_tx_judge_info_stru *judge_info = HI_NULL;
142
143 /* 主要业务帧为UDP帧,进行RTP帧检测 */
144 for (cache_idx = 0; cache_idx < MAX_JUDGE_CACHE_LENGTH; cache_idx++) {
145 judge_info = (hmac_tx_judge_info_stru *)(judge_list->ast_judge_cache + cache_idx);
146
147 if (!memcmp(&judge_info->flow_info, &major_flow->flow_info, sizeof(hmac_tx_flow_info_stru))) {
148 /* RTP帧判断标准:version位保持为2,SSRC、PT保持不变,且帧长度大于RTP包头长度 */
149 if (((judge_info->rtpver >> RTP_VER_SHIFT) != RTP_VERSION) ||
150 (major_flow->rtpssrc != judge_info->rtpssrc) ||
151 (major_flow->payload_type != judge_info->payload_type) ||
152 (major_flow->average_len <
153 (hi_u32)(judge_info->rtpver & RTP_CSRC_MASK) * RTP_CSRC_LEN_BYTE + RTP_HDR_LEN_BYTE)) {
154 hmac_user->judge_list.to_judge_num = 0; /* 识别失败,清空队列 */
155 return HI_FAIL;
156 }
157 }
158 }
159
160 pt = (major_flow->payload_type & (~BIT7));
161 if (pt <= RTP_PT_VO_G729) { /* 依据PayloadType判断RTP载荷类型 */
162 *puc_tid = WLAN_TIDNO_VOICE;
163 } else if ((pt == RTP_PT_VI_CELB) || (pt == RTP_PT_VI_JPEG) || (pt == RTP_PT_VI_NV) ||
164 ((pt >= RTP_PT_VI_H261) && (pt <= RTP_PT_VI_H263))) {
165 *puc_tid = WLAN_TIDNO_VIDEO;
166 }
167
168 /* 识别成功,更新用户已识别流列表 */
169 if ((*puc_tid == WLAN_TIDNO_VOICE) || (*puc_tid == WLAN_TIDNO_VIDEO)) {
170 ret = hmac_tx_add_cfm_traffic(hmac_user, *puc_tid, major_flow);
171 }
172 hmac_user->judge_list.to_judge_num = 0; /* 识别完成,清空队列 */
173
174 return ret;
175 }
176
177 /* ****************************************************************************
178 函 数 名 : hmac_tx_find_major_traffic
179 功能描述 : 找到待识别队列中主要业务
180 输入参数 : hmac用户结构体指针,TID指针
181 输出参数 :
182 返 回 值 : 成功返回HI_SUCCESS,失败返回HI_FAIL
183 调用函数 :
184 被调函数 :
185
186 修改历史 :
187 1.日期: 2015.11.26
188 修改内容: 生成新函数
189 **************************************************************************** */
hmac_tx_find_major_traffic(hmac_user_stru * hmac_user,hi_u8 * puc_tid)190 static hi_u32 hmac_tx_find_major_traffic(hmac_user_stru *hmac_user, hi_u8 *puc_tid)
191 {
192 hmac_tx_major_flow_stru mark = { 0 };
193 hmac_tx_major_flow_stru max = { 0 };
194 hmac_tx_judge_list_stru *judge_list = &(hmac_user->judge_list);
195 hmac_tx_judge_info_stru *judge_info = HI_NULL;
196
197 /* 队列超时,清空队列记录 */
198 if (((hi_s32)judge_list->jiffies_end - (hi_s32)judge_list->jiffies_st) > (hi_s32)(JUDGE_CACHE_LIFETIME * HZ)) {
199 /* 强制转换为long防止jiffies溢出 */
200 hmac_user->judge_list.to_judge_num = 0; /* 清空队列 */
201 return HI_FAIL;
202 }
203
204 /* 队列已满且未超时 */
205 for (hi_u8 cache_idx_i = 0; cache_idx_i < (MAX_JUDGE_CACHE_LENGTH >> 1); cache_idx_i++) {
206 judge_info = (hmac_tx_judge_info_stru *)(judge_list->ast_judge_cache + cache_idx_i);
207
208 if (judge_info->flag == HI_FALSE) {
209 continue;
210 }
211
212 judge_info->flag = HI_FALSE;
213 if (memcpy_s(&mark, sizeof(hmac_tx_judge_info_stru), judge_info, sizeof(hmac_tx_judge_info_stru)) != EOK) {
214 oam_error_log0(0, OAM_SF_CFG, "hmac_tx_find_major_traffic:: pst_judge_info memcpy_s fail.");
215 continue;
216 }
217 mark.wait_check_num = 1;
218
219 for (hi_u8 cache_idx_j = 0; cache_idx_j < MAX_JUDGE_CACHE_LENGTH; cache_idx_j++) {
220 judge_info = (hmac_tx_judge_info_stru *)(judge_list->ast_judge_cache + cache_idx_j);
221
222 if ((judge_info->flag == HI_TRUE) &&
223 !memcmp(&judge_info->flow_info, &mark.flow_info, sizeof(hmac_tx_flow_info_stru))) {
224 judge_info->flag = HI_FALSE;
225 mark.average_len += judge_info->len;
226 mark.wait_check_num += 1;
227 }
228
229 if (mark.wait_check_num <= max.wait_check_num) {
230 continue;
231 }
232 if (memcpy_s(&max, sizeof(hmac_tx_major_flow_stru), &mark, sizeof(hmac_tx_major_flow_stru)) != EOK) {
233 oam_error_log0(0, OAM_SF_CFG, "hmac_tx_find_major_traffic:: st_mark memcpy_s fail.");
234 continue;
235 }
236 if (max.wait_check_num >= (MAX_JUDGE_CACHE_LENGTH >> 1)) {
237 /* 已找到主要业务流,不必继续搜索 */
238 max.average_len = max.average_len / max.wait_check_num;
239 return hmac_tx_traffic_judge(hmac_user, &max, puc_tid);
240 }
241 }
242 }
243
244 if (max.wait_check_num < (MAX_JUDGE_CACHE_LENGTH >> 2)) { /* 2:右移2位 */
245 /* 认为没有主要业务流 */
246 hmac_user->judge_list.to_judge_num = 0; /* 清空队列 */
247 return HI_FAIL;
248 }
249
250 max.average_len = max.average_len / max.wait_check_num;
251 return hmac_tx_traffic_judge(hmac_user, &max, puc_tid);
252 }
253
hmac_tx_traffic_classify_list_proc(const mac_ip_header_stru * ip,hi_u8 * puc_tid,const hmac_tx_flow_info_stru * flow_info,hmac_user_stru * hmac_user,udp_hdr_stru * udp_hdr)254 hi_void hmac_tx_traffic_classify_list_proc(const mac_ip_header_stru *ip, hi_u8 *puc_tid,
255 const hmac_tx_flow_info_stru *flow_info, hmac_user_stru *hmac_user, udp_hdr_stru *udp_hdr)
256 {
257 /* 来包尚未识别,存入用户待识别队列 */
258 hmac_tx_judge_list_stru *judge_list = &(hmac_user->judge_list);
259 hmac_tx_judge_info_stru *judge_info = (hmac_tx_judge_info_stru *)(judge_list->ast_judge_cache +
260 judge_list->to_judge_num);
261
262 if (judge_list->to_judge_num >= MAX_JUDGE_CACHE_LENGTH) { /* 队列已满,识别过程中的来包不作记录 */
263 return;
264 }
265
266 judge_list->jiffies_end = hi_get_tick(); /* 更新最新来包时间 */
267 if (judge_list->to_judge_num == 0) { /* 若队列为空 */
268 judge_list->jiffies_st = hi_get_tick(); /* 更新队列产生时间 */
269 }
270 judge_list->to_judge_num += 1; /* 更新队列长度 */
271
272 if (memset_s(judge_info, sizeof(hmac_tx_judge_info_stru), 0, sizeof(hmac_tx_judge_info_stru)) != EOK) {
273 return;
274 }
275 if (memcpy_s(&(judge_info->flow_info), sizeof(hmac_tx_flow_info_stru), flow_info,
276 sizeof(hmac_tx_flow_info_stru)) != EOK) {
277 oam_error_log0(0, OAM_SF_CFG, "hmac_tx_traffic_classify:: st_flow_info memcpy_s fail.");
278 return;
279 }
280
281 hmac_tx_rtp_hdr *rtp_hdr = (hmac_tx_rtp_hdr *)(udp_hdr + 1); /* 偏移一个UDP头,取RTP头 */
282
283 judge_info->flag = HI_TRUE;
284 judge_info->len = oal_net2host_short(ip->us_tot_len) - sizeof(mac_ip_header_stru) - sizeof(udp_hdr_stru);
285 judge_info->rtpver = rtp_hdr->version_and_csrc;
286 judge_info->payload_type = (hi_u32)(rtp_hdr->payload_type);
287
288 /* 此处由于2字节对齐指针引用4字节对齐变量,在liteos上会崩溃,故用linux的宏括起来 */
289 /* pst_rtp_hdr:为2字节对齐地址 */
290 if (memcpy_s(&(judge_info->rtpssrc), sizeof(hi_u32), &(rtp_hdr->ssrc), sizeof(hi_u32)) != EOK) {
291 oam_error_log0(0, OAM_SF_CFG, "hmac_tx_traffic_classify:: ul_SSRC memcpy_s fail.");
292 return;
293 }
294
295 /* 若待识别队列已满,尝试提取队列主要业务并进行业务识别 */ /* "<=":防止进程并发使此值大于待识别队列长度而踩内存 */
296 if ((judge_list->to_judge_num >= MAX_JUDGE_CACHE_LENGTH) &&
297 (hmac_tx_find_major_traffic(hmac_user, puc_tid) != HI_SUCCESS)) {
298 oam_info_log0(0, OAM_SF_TX, "hmac_tx_traffic_classify::the classify process failed.");
299 }
300 }
301
302 /* ****************************************************************************
303 函 数 名 : hmac_tx_traffic_classify
304 功能描述 : 对下行数据包进行处理:
305 若业务已被识别,直接返回TID, 若否,提取包头信息并进入待检测队列
306 输入参数 : netbuff CB字段指针,ip头指针,TID指针
307 输出参数 :
308 返 回 值 :
309 调用函数 :
310 被调函数 :
311
312 修改历史 :
313 1.日期: 2015.11.26
314 修改内容: 生成新函数
315 2.日期: 2015.12.26
316 修改内容: TCP业务识别功能裁剪
317 **************************************************************************** */
hmac_tx_traffic_classify(const hmac_tx_ctl_stru * tx_ctl,mac_ip_header_stru * ip,hi_u8 * puc_tid)318 hi_void hmac_tx_traffic_classify(const hmac_tx_ctl_stru *tx_ctl, mac_ip_header_stru *ip, hi_u8 *puc_tid)
319 {
320 hmac_tx_flow_info_stru flow_info;
321 hmac_user_stru *hmac_user = (hmac_user_stru *)hmac_user_get_user_stru(tx_ctl->us_tx_user_idx);
322
323 if (hmac_user == HI_NULL) {
324 oam_error_log0(0, OAM_SF_ANY, "hmac_tx_traffic_classify::cannot find hmac_user_stru!");
325 return;
326 }
327
328 /* 功能裁剪,只处理UDP报文,以及识别WifiDisplay RTSP业务为VI */
329 if (ip->protocol != MAC_UDP_PROTOCAL) {
330 if (ip->protocol == MAC_TCP_PROTOCAL) {
331 mac_tcp_header_stru *tcp_hdr = (mac_tcp_header_stru *)(ip + 1);
332
333 /* 识别WifiDisplay RTSP业务为VI */
334 if (oal_ntoh_16(MAC_WFD_RTSP_PORT) == tcp_hdr->us_sport) {
335 *puc_tid = WLAN_TIDNO_VIDEO;
336 return;
337 }
338 }
339 return;
340 }
341
342 /* 若为IP分片帧,没有端口号,直接返回 */
343 if ((oal_ntoh_16(ip->us_frag_off) & IP_FRAGMENT_MASK) != 0) {
344 return;
345 }
346
347 udp_hdr_stru *udp_hdr = (udp_hdr_stru *)(ip + 1); /* 偏移一个IP头,取UDP头 */
348
349 /* 提取五元组 */
350 flow_info.us_dport = udp_hdr->us_des_port;
351 flow_info.us_sport = udp_hdr->us_src_port;
352 flow_info.dip = ip->daddr;
353 flow_info.sip = ip->saddr;
354 flow_info.proto = (hi_u32)(ip->protocol);
355
356 /* 若来包属于用户已识别业务,直接返回TID */
357 for (hi_u8 loop = 0; loop < hmac_user->cfm_num; loop++) {
358 hmac_tx_cfm_flow_stru *cfm_info = (hmac_tx_cfm_flow_stru *)(hmac_user->ast_cfm_flow_list + loop);
359 if (!memcmp(&cfm_info->cfm_flow_info, &flow_info, sizeof(hmac_tx_flow_info_stru))) {
360 *puc_tid = (hi_u8)(cfm_info->us_cfm_tid);
361 cfm_info->last_jiffies = hi_get_tick(); /* 更新业务最新来包时间 */
362 return;
363 }
364 }
365
366 hmac_tx_traffic_classify_list_proc(ip, puc_tid, &flow_info, hmac_user, udp_hdr);
367 }
368
369 #ifdef __cplusplus
370 #if __cplusplus
371 }
372 #endif
373 #endif
374