• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  ******************************************************************************/
15 #define _RTL8192CU_RECV_C_
16 #include <osdep_service.h>
17 #include <drv_types.h>
18 #include <recv_osdep.h>
19 #include <mlme_osdep.h>
20 #include <linux/ip.h>
21 #include <linux/if_ether.h>
22 #include <usb_ops.h>
23 #include <wifi.h>
24 #include <rtl8723a_hal.h>
25 
rtl8723au_init_recv_priv(struct rtw_adapter * padapter)26 int rtl8723au_init_recv_priv(struct rtw_adapter *padapter)
27 {
28 	struct recv_priv *precvpriv = &padapter->recvpriv;
29 	int i, size, res = _SUCCESS;
30 	struct recv_buf *precvbuf;
31 	unsigned long tmpaddr;
32 	unsigned long alignment;
33 	struct sk_buff *pskb;
34 
35 	tasklet_init(&precvpriv->recv_tasklet,
36 		     (void(*)(unsigned long))rtl8723au_recv_tasklet,
37 		     (unsigned long)padapter);
38 
39 	precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
40 	if (!precvpriv->int_in_urb)
41 		DBG_8723A("alloc_urb for interrupt in endpoint fail !!!!\n");
42 	precvpriv->int_in_buf = kzalloc(USB_INTR_CONTENT_LENGTH, GFP_KERNEL);
43 	if (!precvpriv->int_in_buf)
44 		DBG_8723A("alloc_mem for interrupt in endpoint fail !!!!\n");
45 
46 	size = NR_RECVBUFF * sizeof(struct recv_buf);
47 	precvpriv->precv_buf = kzalloc(size, GFP_KERNEL);
48 	if (!precvpriv->precv_buf) {
49 		res = _FAIL;
50 		RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
51 			 "alloc recv_buf fail!\n");
52 		goto exit;
53 	}
54 
55 	precvbuf = (struct recv_buf *)precvpriv->precv_buf;
56 
57 	for (i = 0; i < NR_RECVBUFF; i++) {
58 		INIT_LIST_HEAD(&precvbuf->list);
59 
60 		precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL);
61 		if (!precvbuf->purb)
62 			break;
63 
64 		precvbuf->adapter = padapter;
65 
66 		precvbuf++;
67 	}
68 
69 	skb_queue_head_init(&precvpriv->rx_skb_queue);
70 	skb_queue_head_init(&precvpriv->free_recv_skb_queue);
71 
72 	for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) {
73 		size = MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ;
74 		pskb = __netdev_alloc_skb(padapter->pnetdev, size, GFP_KERNEL);
75 
76 		if (pskb) {
77 			pskb->dev = padapter->pnetdev;
78 
79 			tmpaddr = (unsigned long)pskb->data;
80 			alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
81 			skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));
82 
83 			skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
84 		}
85 
86 		pskb = NULL;
87 	}
88 
89 exit:
90 	return res;
91 }
92 
rtl8723au_free_recv_priv(struct rtw_adapter * padapter)93 void rtl8723au_free_recv_priv(struct rtw_adapter *padapter)
94 {
95 	int	i;
96 	struct recv_buf	*precvbuf;
97 	struct recv_priv *precvpriv = &padapter->recvpriv;
98 
99 	precvbuf = (struct recv_buf *)precvpriv->precv_buf;
100 
101 	for (i = 0; i < NR_RECVBUFF; i++) {
102 		usb_free_urb(precvbuf->purb);
103 
104 		if (precvbuf->pskb)
105 			dev_kfree_skb_any(precvbuf->pskb);
106 
107 		precvbuf++;
108 	}
109 
110 	kfree(precvpriv->precv_buf);
111 
112 	usb_free_urb(precvpriv->int_in_urb);
113 	kfree(precvpriv->int_in_buf);
114 
115 	if (skb_queue_len(&precvpriv->rx_skb_queue))
116 		DBG_8723A(KERN_WARNING "rx_skb_queue not empty\n");
117 
118 	skb_queue_purge(&precvpriv->rx_skb_queue);
119 
120 	if (skb_queue_len(&precvpriv->free_recv_skb_queue)) {
121 		DBG_8723A(KERN_WARNING "free_recv_skb_queue not empty, %d\n",
122 			  skb_queue_len(&precvpriv->free_recv_skb_queue));
123 	}
124 
125 	skb_queue_purge(&precvpriv->free_recv_skb_queue);
126 }
127 
128 struct recv_stat_cpu {
129 	u32 rxdw0;
130 	u32 rxdw1;
131 	u32 rxdw2;
132 	u32 rxdw3;
133 	u32 rxdw4;
134 	u32 rxdw5;
135 };
136 
update_recvframe_attrib(struct recv_frame * precvframe,struct recv_stat * prxstat)137 void update_recvframe_attrib(struct recv_frame *precvframe,
138 			     struct recv_stat *prxstat)
139 {
140 	struct rx_pkt_attrib *pattrib;
141 	struct recv_stat_cpu report;
142 	struct rxreport_8723a *prxreport;
143 
144 	report.rxdw0 = le32_to_cpu(prxstat->rxdw0);
145 	report.rxdw1 = le32_to_cpu(prxstat->rxdw1);
146 	report.rxdw2 = le32_to_cpu(prxstat->rxdw2);
147 	report.rxdw3 = le32_to_cpu(prxstat->rxdw3);
148 	report.rxdw4 = le32_to_cpu(prxstat->rxdw4);
149 	report.rxdw5 = le32_to_cpu(prxstat->rxdw5);
150 
151 	prxreport = (struct rxreport_8723a *)&report;
152 
153 	pattrib = &precvframe->attrib;
154 	memset(pattrib, 0, sizeof(struct rx_pkt_attrib));
155 
156 	/*  update rx report to recv_frame attribute */
157 	pattrib->pkt_len = (u16)prxreport->pktlen;
158 	pattrib->drvinfo_sz = (u8)(prxreport->drvinfosize << 3);
159 	pattrib->physt = (u8)prxreport->physt;
160 
161 	pattrib->crc_err = (u8)prxreport->crc32;
162 	pattrib->icv_err = (u8)prxreport->icverr;
163 
164 	pattrib->bdecrypted = (u8)(prxreport->swdec ? 0 : 1);
165 	pattrib->encrypt = (u8)prxreport->security;
166 
167 	pattrib->qos = (u8)prxreport->qos;
168 	pattrib->priority = (u8)prxreport->tid;
169 
170 	pattrib->amsdu = (u8)prxreport->amsdu;
171 
172 	pattrib->seq_num = (u16)prxreport->seq;
173 	pattrib->frag_num = (u8)prxreport->frag;
174 	pattrib->mfrag = (u8)prxreport->mf;
175 	pattrib->mdata = (u8)prxreport->md;
176 
177 	pattrib->mcs_rate = (u8)prxreport->rxmcs;
178 	pattrib->rxht = (u8)prxreport->rxht;
179 }
180 
update_recvframe_phyinfo(struct recv_frame * precvframe,struct phy_stat * pphy_status)181 void update_recvframe_phyinfo(struct recv_frame *precvframe,
182 			      struct phy_stat *pphy_status)
183 {
184 	struct rtw_adapter *padapter = precvframe->adapter;
185 	struct rx_pkt_attrib *pattrib = &precvframe->attrib;
186 	struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
187 	struct phy_info *pPHYInfo = &pattrib->phy_info;
188 	struct odm_packet_info pkt_info;
189 	u8 *sa = NULL, *da;
190 	struct sta_priv *pstapriv;
191 	struct sta_info *psta;
192 	struct sk_buff *skb = precvframe->pkt;
193 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
194 	bool matchbssid = false;
195 	u8 *bssid;
196 
197 	matchbssid = !ieee80211_is_ctl(hdr->frame_control) &&
198 		      !pattrib->icv_err && !pattrib->crc_err;
199 
200 	if (matchbssid) {
201 		switch (hdr->frame_control &
202 			cpu_to_le16(IEEE80211_FCTL_TODS |
203 				    IEEE80211_FCTL_FROMDS)) {
204 		case cpu_to_le16(IEEE80211_FCTL_TODS):
205 			bssid = hdr->addr1;
206 			break;
207 		case cpu_to_le16(IEEE80211_FCTL_FROMDS):
208 			bssid = hdr->addr2;
209 			break;
210 		case cpu_to_le16(0):
211 			bssid = hdr->addr3;
212 			break;
213 		default:
214 			bssid = NULL;
215 			matchbssid = false;
216 		}
217 
218 		if (bssid)
219 			matchbssid = ether_addr_equal(
220 				get_bssid(&padapter->mlmepriv), bssid);
221 	}
222 
223 	pkt_info.bPacketMatchBSSID = matchbssid;
224 
225 	da = ieee80211_get_DA(hdr);
226 	pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID &&
227 		(!memcmp(da, myid(&padapter->eeprompriv), ETH_ALEN));
228 
229 	pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID &&
230 		ieee80211_is_beacon(hdr->frame_control);
231 
232 	pkt_info.StationID = 0xFF;
233 	if (pkt_info.bPacketBeacon) {
234 		if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) == true)
235 			sa = padapter->mlmepriv.cur_network.network.MacAddress;
236 		/* to do Ad-hoc */
237 	} else {
238 		sa = ieee80211_get_SA(hdr);
239 	}
240 
241 	pstapriv = &padapter->stapriv;
242 	psta = rtw_get_stainfo23a(pstapriv, sa);
243 	if (psta) {
244 		pkt_info.StationID = psta->mac_id;
245 		/* printk("%s ==> StationID(%d)\n", __func__, pkt_info.StationID); */
246 	}
247 	pkt_info.Rate = pattrib->mcs_rate;
248 
249 	ODM_PhyStatusQuery23a(&pHalData->odmpriv, pPHYInfo,
250 			      (u8 *)pphy_status, &pkt_info);
251 	precvframe->psta = NULL;
252 	if (pkt_info.bPacketMatchBSSID &&
253 	    (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true)) {
254 		if (psta) {
255 			precvframe->psta = psta;
256 			rtl8723a_process_phy_info(padapter, precvframe);
257 		}
258 	} else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) {
259 		if (check_fwstate(&padapter->mlmepriv,
260 				  WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) ==
261 		    true) {
262 			if (psta)
263 				precvframe->psta = psta;
264 		}
265 		rtl8723a_process_phy_info(padapter, precvframe);
266 	}
267 }
268