• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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