1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
5  *
6  ******************************************************************************/
7 #include <drv_types.h>
8 #include <rtw_debug.h>
9 
10 
11 uint rtw_remainder_len(struct pkt_file *pfile)
12 {
13 	return (pfile->buf_len - ((SIZE_PTR)(pfile->cur_addr) - (SIZE_PTR)(pfile->buf_start)));
14 }
15 
16 void _rtw_open_pktfile(struct sk_buff *pktptr, struct pkt_file *pfile)
17 {
18 	pfile->pkt = pktptr;
19 	pfile->cur_addr = pfile->buf_start = pktptr->data;
20 	pfile->pkt_len = pfile->buf_len = pktptr->len;
21 
22 	pfile->cur_buffer = pfile->buf_start;
23 }
24 
25 uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen)
26 {
27 	uint	len = 0;
28 
29 	len =  rtw_remainder_len(pfile);
30 	len = (rlen > len) ? len : rlen;
31 
32 	if (rmem)
33 		skb_copy_bits(pfile->pkt, pfile->buf_len - pfile->pkt_len, rmem, len);
34 
35 	pfile->cur_addr += len;
36 	pfile->pkt_len -= len;
37 	return len;
38 }
39 
40 signed int rtw_endofpktfile(struct pkt_file *pfile)
41 {
42 	if (pfile->pkt_len == 0)
43 		return true;
44 	return false;
45 }
46 
47 int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz, u8 flag)
48 {
49 	if (alloc_sz > 0) {
50 		pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz);
51 		if (!pxmitbuf->pallocated_buf)
52 			return _FAIL;
53 
54 		pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
55 	}
56 
57 	return _SUCCESS;
58 }
59 
60 void rtw_os_xmit_resource_free(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 free_sz, u8 flag)
61 {
62 	if (free_sz > 0)
63 		kfree(pxmitbuf->pallocated_buf);
64 }
65 
66 #define WMM_XMIT_THRESHOLD	(NR_XMITFRAME * 2 / 5)
67 
68 void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt)
69 {
70 	u16 queue;
71 	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
72 
73 	queue = skb_get_queue_mapping(pkt);
74 	if (padapter->registrypriv.wifi_spec) {
75 		if (__netif_subqueue_stopped(padapter->pnetdev, queue) &&
76 		    (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD))
77 			netif_wake_subqueue(padapter->pnetdev, queue);
78 	} else {
79 		if (__netif_subqueue_stopped(padapter->pnetdev, queue))
80 			netif_wake_subqueue(padapter->pnetdev, queue);
81 	}
82 
83 	dev_kfree_skb_any(pkt);
84 }
85 
86 void rtw_os_xmit_complete(struct adapter *padapter, struct xmit_frame *pxframe)
87 {
88 	if (pxframe->pkt)
89 		rtw_os_pkt_complete(padapter, pxframe->pkt);
90 
91 	pxframe->pkt = NULL;
92 }
93 
94 void rtw_os_xmit_schedule(struct adapter *padapter)
95 {
96 	struct adapter *pri_adapter = padapter;
97 
98 	if (!padapter)
99 		return;
100 
101 	if (!list_empty(&padapter->xmitpriv.pending_xmitbuf_queue.queue))
102 		complete(&pri_adapter->xmitpriv.xmit_comp);
103 }
104 
105 static void rtw_check_xmit_resource(struct adapter *padapter, struct sk_buff *pkt)
106 {
107 	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
108 	u16 queue;
109 
110 	queue = skb_get_queue_mapping(pkt);
111 	if (padapter->registrypriv.wifi_spec) {
112 		/* No free space for Tx, tx_worker is too slow */
113 		if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD)
114 			netif_stop_subqueue(padapter->pnetdev, queue);
115 	} else {
116 		if (pxmitpriv->free_xmitframe_cnt <= 4) {
117 			if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue)))
118 				netif_stop_subqueue(padapter->pnetdev, queue);
119 		}
120 	}
121 }
122 
123 static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb)
124 {
125 	struct	sta_priv *pstapriv = &padapter->stapriv;
126 	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
127 	struct list_head	*phead, *plist;
128 	struct sk_buff *newskb;
129 	struct sta_info *psta = NULL;
130 	u8 chk_alive_num = 0;
131 	char chk_alive_list[NUM_STA];
132 	u8 bc_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
133 	u8 null_addr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
134 
135 	int i;
136 	s32	res;
137 
138 	spin_lock_bh(&pstapriv->asoc_list_lock);
139 	phead = &pstapriv->asoc_list;
140 	/* free sta asoc_queue */
141 	list_for_each(plist, phead) {
142 		int stainfo_offset;
143 
144 		psta = list_entry(plist, struct sta_info, asoc_list);
145 
146 		stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
147 		if (stainfo_offset_valid(stainfo_offset)) {
148 			chk_alive_list[chk_alive_num++] = stainfo_offset;
149 		}
150 	}
151 	spin_unlock_bh(&pstapriv->asoc_list_lock);
152 
153 	for (i = 0; i < chk_alive_num; i++) {
154 		psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
155 		if (!(psta->state & _FW_LINKED))
156 			continue;
157 
158 		/* avoid come from STA1 and send back STA1 */
159 		if (!memcmp(psta->hwaddr, &skb->data[6], 6) ||
160 		    !memcmp(psta->hwaddr, null_addr, 6) ||
161 		    !memcmp(psta->hwaddr, bc_addr, 6))
162 			continue;
163 
164 		newskb = rtw_skb_copy(skb);
165 
166 		if (newskb) {
167 			memcpy(newskb->data, psta->hwaddr, 6);
168 			res = rtw_xmit(padapter, &newskb);
169 			if (res < 0) {
170 				pxmitpriv->tx_drop++;
171 				dev_kfree_skb_any(newskb);
172 			}
173 		} else {
174 			pxmitpriv->tx_drop++;
175 			/* dev_kfree_skb_any(skb); */
176 			return false;	/*  Caller shall tx this multicast frame via normal way. */
177 		}
178 	}
179 
180 	dev_kfree_skb_any(skb);
181 	return true;
182 }
183 
184 void _rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev)
185 {
186 	struct adapter *padapter = rtw_netdev_priv(pnetdev);
187 	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
188 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
189 	s32 res = 0;
190 
191 	if (rtw_if_up(padapter) == false)
192 		goto drop_packet;
193 
194 	rtw_check_xmit_resource(padapter, pkt);
195 
196 	if (!rtw_mc2u_disable
197 		&& check_fwstate(pmlmepriv, WIFI_AP_STATE) == true
198 		&& (IP_MCAST_MAC(pkt->data)
199 			|| ICMPV6_MCAST_MAC(pkt->data)
200 			)
201 		&& padapter->registrypriv.wifi_spec == 0) {
202 		if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME / 4)) {
203 			res = rtw_mlcst2unicst(padapter, pkt);
204 			if (res)
205 				return;
206 		}
207 	}
208 
209 	res = rtw_xmit(padapter, &pkt);
210 	if (res < 0)
211 		goto drop_packet;
212 
213 	return;
214 
215 drop_packet:
216 	pxmitpriv->tx_drop++;
217 	dev_kfree_skb_any(pkt);
218 }
219 
220 netdev_tx_t rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev)
221 {
222 	if (pkt)
223 		_rtw_xmit_entry(pkt, pnetdev);
224 
225 	return NETDEV_TX_OK;
226 }
227