1 // SPDX-License-Identifier: GPL-2.0 2 /****************************************************************************** 3 * 4 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. 5 * 6 ******************************************************************************/ 7 #define _XMIT_OSDEP_C_ 8 9 #include <drv_types.h> 10 #include <rtw_debug.h> 11 12 13 uint rtw_remainder_len(struct pkt_file *pfile) 14 { 15 return (pfile->buf_len - ((SIZE_PTR)(pfile->cur_addr) - (SIZE_PTR)(pfile->buf_start))); 16 } 17 18 void _rtw_open_pktfile(_pkt *pktptr, struct pkt_file *pfile) 19 { 20 pfile->pkt = pktptr; 21 pfile->cur_addr = pfile->buf_start = pktptr->data; 22 pfile->pkt_len = pfile->buf_len = pktptr->len; 23 24 pfile->cur_buffer = pfile->buf_start; 25 } 26 27 uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen) 28 { 29 uint len = 0; 30 31 len = rtw_remainder_len(pfile); 32 len = (rlen > len) ? len : rlen; 33 34 if (rmem) 35 skb_copy_bits(pfile->pkt, pfile->buf_len - pfile->pkt_len, rmem, len); 36 37 pfile->cur_addr += len; 38 pfile->pkt_len -= len; 39 return len; 40 } 41 42 sint rtw_endofpktfile(struct pkt_file *pfile) 43 { 44 if (pfile->pkt_len == 0) 45 return true; 46 return false; 47 } 48 49 int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz, u8 flag) 50 { 51 if (alloc_sz > 0) { 52 pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz); 53 if (!pxmitbuf->pallocated_buf) 54 return _FAIL; 55 56 pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ); 57 } 58 59 return _SUCCESS; 60 } 61 62 void rtw_os_xmit_resource_free(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 free_sz, u8 flag) 63 { 64 if (free_sz > 0) 65 kfree(pxmitbuf->pallocated_buf); 66 } 67 68 #define WMM_XMIT_THRESHOLD (NR_XMITFRAME * 2 / 5) 69 70 void rtw_os_pkt_complete(struct adapter *padapter, _pkt *pkt) 71 { 72 u16 queue; 73 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 74 75 queue = skb_get_queue_mapping(pkt); 76 if (padapter->registrypriv.wifi_spec) { 77 if (__netif_subqueue_stopped(padapter->pnetdev, queue) && 78 (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD)) 79 netif_wake_subqueue(padapter->pnetdev, queue); 80 } else { 81 if (__netif_subqueue_stopped(padapter->pnetdev, queue)) 82 netif_wake_subqueue(padapter->pnetdev, queue); 83 } 84 85 dev_kfree_skb_any(pkt); 86 } 87 88 void rtw_os_xmit_complete(struct adapter *padapter, struct xmit_frame *pxframe) 89 { 90 if (pxframe->pkt) 91 rtw_os_pkt_complete(padapter, pxframe->pkt); 92 93 pxframe->pkt = NULL; 94 } 95 96 void rtw_os_xmit_schedule(struct adapter *padapter) 97 { 98 struct adapter *pri_adapter = padapter; 99 100 if (!padapter) 101 return; 102 103 if (!list_empty(&padapter->xmitpriv.pending_xmitbuf_queue.queue)) 104 complete(&pri_adapter->xmitpriv.xmit_comp); 105 } 106 107 static void rtw_check_xmit_resource(struct adapter *padapter, _pkt *pkt) 108 { 109 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 110 u16 queue; 111 112 queue = skb_get_queue_mapping(pkt); 113 if (padapter->registrypriv.wifi_spec) { 114 /* No free space for Tx, tx_worker is too slow */ 115 if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD) { 116 /* DBG_871X("%s(): stop netif_subqueue[%d]\n", __func__, queue); */ 117 netif_stop_subqueue(padapter->pnetdev, queue); 118 } 119 } else { 120 if (pxmitpriv->free_xmitframe_cnt <= 4) { 121 if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue))) 122 netif_stop_subqueue(padapter->pnetdev, queue); 123 } 124 } 125 } 126 127 static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb) 128 { 129 struct sta_priv *pstapriv = &padapter->stapriv; 130 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 131 struct list_head *phead, *plist; 132 struct sk_buff *newskb; 133 struct sta_info *psta = NULL; 134 u8 chk_alive_num = 0; 135 char chk_alive_list[NUM_STA]; 136 u8 bc_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 137 u8 null_addr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 138 139 int i; 140 s32 res; 141 142 DBG_COUNTER(padapter->tx_logs.os_tx_m2u); 143 144 spin_lock_bh(&pstapriv->asoc_list_lock); 145 phead = &pstapriv->asoc_list; 146 plist = get_next(phead); 147 148 /* free sta asoc_queue */ 149 while (phead != plist) { 150 int stainfo_offset; 151 psta = container_of(plist, struct sta_info, asoc_list); 152 plist = get_next(plist); 153 154 stainfo_offset = rtw_stainfo_offset(pstapriv, psta); 155 if (stainfo_offset_valid(stainfo_offset)) { 156 chk_alive_list[chk_alive_num++] = stainfo_offset; 157 } 158 } 159 spin_unlock_bh(&pstapriv->asoc_list_lock); 160 161 for (i = 0; i < chk_alive_num; i++) { 162 psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); 163 if (!(psta->state & _FW_LINKED)) { 164 DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_fw_linked); 165 continue; 166 } 167 168 /* avoid come from STA1 and send back STA1 */ 169 if (!memcmp(psta->hwaddr, &skb->data[6], 6) || 170 !memcmp(psta->hwaddr, null_addr, 6) || 171 !memcmp(psta->hwaddr, bc_addr, 6)) { 172 DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_self); 173 continue; 174 } 175 176 DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry); 177 178 newskb = rtw_skb_copy(skb); 179 180 if (newskb) { 181 memcpy(newskb->data, psta->hwaddr, 6); 182 res = rtw_xmit(padapter, &newskb); 183 if (res < 0) { 184 DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry_err_xmit); 185 DBG_871X("%s()-%d: rtw_xmit() return error!\n", __func__, __LINE__); 186 pxmitpriv->tx_drop++; 187 dev_kfree_skb_any(newskb); 188 } 189 } else { 190 DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry_err_skb); 191 DBG_871X("%s-%d: rtw_skb_copy() failed!\n", __func__, __LINE__); 192 pxmitpriv->tx_drop++; 193 /* dev_kfree_skb_any(skb); */ 194 return false; /* Caller shall tx this multicast frame via normal way. */ 195 } 196 } 197 198 dev_kfree_skb_any(skb); 199 return true; 200 } 201 202 int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev) 203 { 204 struct adapter *padapter = rtw_netdev_priv(pnetdev); 205 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 206 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 207 s32 res = 0; 208 209 DBG_COUNTER(padapter->tx_logs.os_tx); 210 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n")); 211 212 if (rtw_if_up(padapter) == false) { 213 DBG_COUNTER(padapter->tx_logs.os_tx_err_up); 214 RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n")); 215 #ifdef DBG_TX_DROP_FRAME 216 DBG_871X("DBG_TX_DROP_FRAME %s if_up fail\n", __func__); 217 #endif 218 goto drop_packet; 219 } 220 221 rtw_check_xmit_resource(padapter, pkt); 222 223 if (!rtw_mc2u_disable 224 && check_fwstate(pmlmepriv, WIFI_AP_STATE) == true 225 && (IP_MCAST_MAC(pkt->data) 226 || ICMPV6_MCAST_MAC(pkt->data) 227 #ifdef CONFIG_TX_BCAST2UNI 228 || is_broadcast_mac_addr(pkt->data) 229 #endif 230 ) 231 && padapter->registrypriv.wifi_spec == 0) { 232 if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME / 4)) { 233 res = rtw_mlcst2unicst(padapter, pkt); 234 if (res) 235 goto exit; 236 } else { 237 /* DBG_871X("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt); */ 238 /* DBG_871X("!m2u); */ 239 DBG_COUNTER(padapter->tx_logs.os_tx_m2u_stop); 240 } 241 } 242 243 res = rtw_xmit(padapter, &pkt); 244 if (res < 0) { 245 #ifdef DBG_TX_DROP_FRAME 246 DBG_871X("DBG_TX_DROP_FRAME %s rtw_xmit fail\n", __func__); 247 #endif 248 goto drop_packet; 249 } 250 251 RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts =%d\n", (u32)pxmitpriv->tx_pkts)); 252 goto exit; 253 254 drop_packet: 255 pxmitpriv->tx_drop++; 256 dev_kfree_skb_any(pkt); 257 RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop =%d\n", (u32)pxmitpriv->tx_drop)); 258 259 exit: 260 return 0; 261 } 262 263 int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev) 264 { 265 int ret = 0; 266 267 if (pkt) { 268 rtw_mstat_update(MSTAT_TYPE_SKB, MSTAT_ALLOC_SUCCESS, pkt->truesize); 269 ret = _rtw_xmit_entry(pkt, pnetdev); 270 } 271 272 return ret; 273 } 274