Commit | Line | Data |
---|---|---|
635d2b00 GKH |
1 | /* |
2 | * *************************************************************************** | |
3 | * FILE: unifi_event.c | |
4 | * | |
5 | * PURPOSE: | |
6 | * Process the signals received by UniFi. | |
7 | * It is part of the porting exercise. | |
8 | * | |
9 | * Copyright (C) 2009 by Cambridge Silicon Radio Ltd. | |
10 | * | |
11 | * Refer to LICENSE.txt included with this source code for details on | |
12 | * the license terms. | |
13 | * | |
14 | * *************************************************************************** | |
15 | */ | |
16 | ||
17 | ||
18 | /* | |
19 | * Porting notes: | |
20 | * The implementation of unifi_receive_event() in Linux is fairly complicated. | |
21 | * The linux driver support multiple userspace applications and several | |
22 | * build configurations, so the received signals are processed by different | |
23 | * processes and multiple times. | |
24 | * In a simple implementation, this function needs to deliver: | |
25 | * - The MLME-UNITDATA.ind signals to the Rx data plane and to the Traffic | |
26 | * Analysis using unifi_ta_sample(). | |
27 | * - The MLME-UNITDATA-STATUS.ind signals to the Tx data plane. | |
28 | * - All the other signals to the SME using unifi_sys_hip_ind(). | |
29 | */ | |
30 | ||
31 | #include "csr_wifi_hip_unifi.h" | |
32 | #include "csr_wifi_hip_conversions.h" | |
33 | #include "unifi_priv.h" | |
34 | ||
35 | ||
36 | /* | |
37 | * --------------------------------------------------------------------------- | |
38 | * send_to_client | |
39 | * | |
40 | * Helper for unifi_receive_event. | |
41 | * | |
42 | * This function forwards a signal to one client. | |
43 | * | |
44 | * Arguments: | |
45 | * priv Pointer to driver's private data. | |
46 | * client Pointer to the client structure. | |
47 | * receiver_id The reciever id of the signal. | |
48 | * sigdata Pointer to the packed signal buffer. | |
49 | * siglen Length of the packed signal. | |
50 | * bulkdata Pointer to the signal's bulk data. | |
51 | * | |
52 | * Returns: | |
53 | * None. | |
54 | * | |
55 | * --------------------------------------------------------------------------- | |
56 | */ | |
57 | static void send_to_client(unifi_priv_t *priv, ul_client_t *client, | |
58 | int receiver_id, | |
59 | unsigned char *sigdata, int siglen, | |
60 | const bulk_data_param_t *bulkdata) | |
61 | { | |
62 | if (client && client->event_hook) { | |
63 | /*unifi_trace(priv, UDBG3, | |
64 | "Receive: client %d, (s:0x%X, r:0x%X) - Signal 0x%.4X \n", | |
65 | client->client_id, client->sender_id, receiver_id, | |
66 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata));*/ | |
67 | ||
68 | client->event_hook(client, sigdata, siglen, bulkdata, UDI_TO_HOST); | |
69 | } | |
70 | } | |
71 | ||
72 | /* | |
73 | * --------------------------------------------------------------------------- | |
74 | * process_pkt_data_ind | |
75 | * | |
76 | * Dispatcher for received signals. | |
77 | * | |
78 | * This function receives the 'to host' signals and forwards | |
79 | * them to the unifi linux clients. | |
80 | * | |
81 | * Arguments: | |
82 | * priv Context | |
83 | * sigdata Pointer to the packed signal buffer(Its in form of MA-PACKET.ind). | |
84 | * bulkdata Pointer to signal's bulkdata | |
85 | * freeBulkData Pointer to a flag which gets set if the bulkdata needs to | |
86 | * be freed after calling the logging handlers. If it is not | |
87 | * set the bulkdata must be freed by the MLME handler or | |
88 | * passed to the network stack. | |
89 | * Returns: | |
90 | * TRUE if the packet should be routed to the SME etc. | |
91 | * FALSE if the packet is for the driver or network stack | |
92 | * --------------------------------------------------------------------------- | |
93 | */ | |
5379b13d | 94 | static u8 check_routing_pkt_data_ind(unifi_priv_t *priv, |
7e6f5794 | 95 | u8 *sigdata, |
635d2b00 | 96 | const bulk_data_param_t* bulkdata, |
5379b13d | 97 | u8 *freeBulkData, |
635d2b00 GKH |
98 | netInterface_priv_t *interfacePriv) |
99 | { | |
8c87f69a | 100 | u16 frmCtrl, receptionStatus, frmCtrlSubType; |
7e6f5794 GKH |
101 | u8 *macHdrLocation; |
102 | u8 interfaceTag; | |
5379b13d GKH |
103 | u8 isDataFrame; |
104 | u8 isProtocolVerInvalid = FALSE; | |
105 | u8 isDataFrameSubTypeNoData = FALSE; | |
635d2b00 GKH |
106 | |
107 | #ifdef CSR_WIFI_SECURITY_WAPI_ENABLE | |
4f70a8d4 | 108 | static const u8 wapiProtocolIdSNAPHeader[] = {0x88, 0xb4}; |
7e6f5794 GKH |
109 | static const u8 wapiProtocolIdSNAPHeaderOffset = 6; |
110 | u8 *destAddr; | |
111 | u8 *srcAddr; | |
5379b13d | 112 | u8 isWapiUnicastPkt = FALSE; |
95edd09e GKH |
113 | |
114 | #ifdef CSR_WIFI_SECURITY_WAPI_QOSCTRL_MIC_WORKAROUND | |
8c87f69a | 115 | u16 qosControl; |
95edd09e | 116 | #endif |
635d2b00 | 117 | |
7e6f5794 | 118 | u8 llcSnapHeaderOffset = 0; |
635d2b00 | 119 | |
7e6f5794 GKH |
120 | destAddr = (u8 *) bulkdata->d[0].os_data_ptr + MAC_HEADER_ADDR1_OFFSET; |
121 | srcAddr = (u8 *) bulkdata->d[0].os_data_ptr + MAC_HEADER_ADDR2_OFFSET; | |
635d2b00 GKH |
122 | |
123 | /*Individual/Group bit - Bit 0 of first byte*/ | |
95edd09e | 124 | isWapiUnicastPkt = (!(destAddr[0] & 0x01)) ? TRUE : FALSE; |
635d2b00 GKH |
125 | #endif |
126 | ||
127 | #define CSR_WIFI_MA_PKT_IND_RECEPTION_STATUS_OFFSET sizeof(CSR_SIGNAL_PRIMITIVE_HEADER) + 22 | |
128 | ||
129 | *freeBulkData = FALSE; | |
130 | ||
131 | /* Fetch the MAC header location from MA_PKT_IND packet */ | |
7e6f5794 | 132 | macHdrLocation = (u8 *) bulkdata->d[0].os_data_ptr; |
635d2b00 GKH |
133 | /* Fetch the Frame Control value from MAC header */ |
134 | frmCtrl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(macHdrLocation); | |
135 | ||
136 | /* Pull out interface tag from virtual interface identifier */ | |
137 | interfaceTag = (CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + 14)) & 0xff; | |
138 | ||
139 | /* check for MIC failure before processing the signal */ | |
140 | receptionStatus = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + CSR_WIFI_MA_PKT_IND_RECEPTION_STATUS_OFFSET); | |
141 | ||
142 | /* To discard any spurious MIC failures that could be reported by the firmware */ | |
143 | isDataFrame = ((frmCtrl & IEEE80211_FC_TYPE_MASK) == (IEEE802_11_FC_TYPE_DATA & IEEE80211_FC_TYPE_MASK)) ? TRUE : FALSE; | |
144 | /* 0x00 is the only valid protocol version*/ | |
145 | isProtocolVerInvalid = (frmCtrl & IEEE80211_FC_PROTO_VERSION_MASK) ? TRUE : FALSE; | |
146 | frmCtrlSubType = (frmCtrl & IEEE80211_FC_SUBTYPE_MASK) >> FRAME_CONTROL_SUBTYPE_FIELD_OFFSET; | |
147 | /*Exclude the no data & reserved sub-types from MIC failure processing*/ | |
148 | isDataFrameSubTypeNoData = (((frmCtrlSubType>0x03)&&(frmCtrlSubType<0x08)) || (frmCtrlSubType>0x0B)) ? TRUE : FALSE; | |
149 | if ((receptionStatus == CSR_MICHAEL_MIC_ERROR) && | |
150 | ((!isDataFrame) || isProtocolVerInvalid || (isDataFrame && isDataFrameSubTypeNoData))) { | |
151 | /* Currently MIC errors are discarded for frames other than data frames. This might need changing when we start | |
152 | * supporting 802.11w (Protected Management frames) | |
153 | */ | |
154 | *freeBulkData = TRUE; | |
155 | unifi_trace(priv, UDBG4, "Discarding this frame and ignoring the MIC failure as this is a garbage/non-data/no data frame\n"); | |
156 | return FALSE; | |
157 | } | |
158 | ||
159 | #ifdef CSR_WIFI_SECURITY_WAPI_ENABLE | |
160 | ||
161 | if (receptionStatus == CSR_MICHAEL_MIC_ERROR) { | |
162 | ||
163 | if (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA) { | |
164 | ||
95edd09e GKH |
165 | #ifdef CSR_WIFI_SECURITY_WAPI_QOSCTRL_MIC_WORKAROUND |
166 | if ((isDataFrame) && | |
167 | ((IEEE802_11_FC_TYPE_QOS_DATA & IEEE80211_FC_SUBTYPE_MASK) == (frmCtrl & IEEE80211_FC_SUBTYPE_MASK)) && | |
168 | (priv->isWapiConnection)) | |
169 | { | |
170 | qosControl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(macHdrLocation + (((frmCtrl & IEEE802_11_FC_TO_DS_MASK) && (frmCtrl & IEEE802_11_FC_FROM_DS_MASK)) ? 30 : 24) ); | |
171 | ||
172 | unifi_trace(priv, UDBG4, "check_routing_pkt_data_ind() :: Value of the QoS control field - 0x%04x \n", qosControl); | |
173 | ||
174 | if (qosControl & IEEE802_11_QC_NON_TID_BITS_MASK) | |
175 | { | |
176 | unifi_trace(priv, UDBG4, "Ignore the MIC failure and pass the MPDU to the stack when any of bits [4-15] is set in the QoS control field\n"); | |
177 | ||
178 | /*Exclude the MIC [16] and the PN [16] that are appended by the firmware*/ | |
179 | ((bulk_data_param_t*)bulkdata)->d[0].data_length = bulkdata->d[0].data_length - 32; | |
180 | ||
181 | /*Clear the reception status of the signal (CSR_RX_SUCCESS)*/ | |
182 | *(sigdata + CSR_WIFI_MA_PKT_IND_RECEPTION_STATUS_OFFSET) = 0x00; | |
183 | *(sigdata + CSR_WIFI_MA_PKT_IND_RECEPTION_STATUS_OFFSET+1) = 0x00; | |
184 | ||
185 | *freeBulkData = FALSE; | |
186 | ||
187 | return FALSE; | |
188 | } | |
189 | } | |
190 | #endif | |
635d2b00 | 191 | /* If this MIC ERROR reported by the firmware is either for |
95edd09e GKH |
192 | * [1] a WAPI Multicast MPDU and the Multicast filter has NOT been set (It is set only when group key index (MSKID) = 1 in Group Rekeying) OR |
193 | * [2] a WAPI Unicast MPDU and either the CONTROL PORT is open or the WAPI Unicast filter or filter(s) is NOT set | |
635d2b00 GKH |
194 | * then report a MIC FAILURE indication to the SME. |
195 | */ | |
95edd09e GKH |
196 | #ifndef CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION |
197 | if ((priv->wapi_multicast_filter == 0) || isWapiUnicastPkt) { | |
198 | #else | |
199 | /*When SW encryption is enabled and USKID=1 (wapi_unicast_filter = 1), we are expected | |
200 | *to receive MIC failure INDs for unicast MPDUs*/ | |
201 | if ( ((priv->wapi_multicast_filter == 0) && !isWapiUnicastPkt) || | |
202 | ((priv->wapi_unicast_filter == 0) && isWapiUnicastPkt) ) { | |
203 | #endif | |
635d2b00 GKH |
204 | /*Discard the frame*/ |
205 | *freeBulkData = TRUE; | |
206 | unifi_trace(priv, UDBG4, "Discarding the contents of the frame with MIC failure \n"); | |
207 | ||
95edd09e | 208 | if (isWapiUnicastPkt && |
4f70a8d4 | 209 | ((uf_sme_port_state(priv, srcAddr, UF_CONTROLLED_PORT_Q, interfaceTag) != CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN)|| |
95edd09e | 210 | #ifndef CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION |
635d2b00 | 211 | (priv->wapi_unicast_filter) || |
95edd09e | 212 | #endif |
635d2b00 GKH |
213 | (priv->wapi_unicast_queued_pkt_filter))) { |
214 | ||
215 | /* Workaround to handle MIC failures reported by the firmware for encrypted packets from the AP | |
216 | * while we are in the process of re-association induced by unsupported WAPI Unicast key index | |
217 | * - Discard the packets with MIC failures "until" we have | |
218 | * a. negotiated a key, | |
219 | * b. opened the CONTROL PORT and | |
220 | * c. the AP has started using the new key | |
221 | */ | |
222 | unifi_trace(priv, UDBG4, "Ignoring the MIC failure as either a. CONTROL PORT isn't OPEN or b. Unicast filter is set or c. WAPI AP using old key for buffered pkts\n"); | |
223 | ||
224 | /*Ignore this MIC failure*/ | |
225 | return FALSE; | |
226 | ||
227 | }/*WAPI re-key specific workaround*/ | |
228 | ||
229 | unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind - MIC FAILURE : interfaceTag %x Src Addr %x:%x:%x:%x:%x:%x\n", | |
230 | interfaceTag, srcAddr[0], srcAddr[1], srcAddr[2], srcAddr[3], srcAddr[4], srcAddr[5]); | |
231 | unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind - MIC FAILURE : Dest Addr %x:%x:%x:%x:%x:%x\n", | |
232 | destAddr[0], destAddr[1], destAddr[2], destAddr[3], destAddr[4], destAddr[5]); | |
233 | unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind - MIC FAILURE : Control Port State - 0x%.4X \n", | |
4f70a8d4 | 234 | uf_sme_port_state(priv, srcAddr, UF_CONTROLLED_PORT_Q, interfaceTag)); |
635d2b00 GKH |
235 | |
236 | unifi_error(priv, "MIC failure in %s\n", __FUNCTION__); | |
237 | ||
238 | /*Report the MIC failure to the SME*/ | |
239 | return TRUE; | |
240 | } | |
241 | }/* STA mode */ | |
242 | else { | |
243 | /* Its AP Mode . Just Return */ | |
244 | *freeBulkData = TRUE; | |
245 | unifi_error(priv, "MIC failure in %s\n", __FUNCTION__); | |
246 | return TRUE; | |
247 | } /* AP mode */ | |
248 | }/* MIC error */ | |
249 | #else | |
250 | if (receptionStatus == CSR_MICHAEL_MIC_ERROR) { | |
251 | *freeBulkData = TRUE; | |
252 | unifi_error(priv, "MIC failure in %s\n", __FUNCTION__); | |
253 | return TRUE; | |
254 | } | |
255 | #endif /*CSR_WIFI_SECURITY_WAPI_ENABLE*/ | |
256 | ||
257 | unifi_trace(priv, UDBG4, "frmCtrl = 0x%04x %s\n", | |
258 | frmCtrl, | |
259 | (((frmCtrl & 0x000c)>>FRAME_CONTROL_TYPE_FIELD_OFFSET) == IEEE802_11_FRAMETYPE_MANAGEMENT) ? | |
260 | "Mgt" : "Ctrl/Data"); | |
261 | ||
262 | #ifdef CSR_WIFI_SECURITY_WAPI_ENABLE | |
263 | /* To ignore MIC failures reported due to the WAPI AP using the old key for queued packets before | |
264 | * starting to use the new key negotiated as part of unicast re-keying | |
265 | */ | |
95edd09e GKH |
266 | if ((interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA)&& |
267 | isWapiUnicastPkt && | |
635d2b00 GKH |
268 | (receptionStatus == CSR_RX_SUCCESS) && |
269 | (priv->wapi_unicast_queued_pkt_filter==1)) { | |
270 | ||
271 | unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind(): WAPI unicast pkt received when the (wapi_unicast_queued_pkt_filter) is set\n"); | |
272 | ||
273 | if (isDataFrame) { | |
274 | switch(frmCtrl & IEEE80211_FC_SUBTYPE_MASK) { | |
275 | case IEEE802_11_FC_TYPE_QOS_DATA & IEEE80211_FC_SUBTYPE_MASK: | |
276 | llcSnapHeaderOffset = MAC_HEADER_SIZE + 2; | |
277 | break; | |
278 | case IEEE802_11_FC_TYPE_QOS_NULL & IEEE80211_FC_SUBTYPE_MASK: | |
279 | case IEEE802_11_FC_TYPE_NULL & IEEE80211_FC_SUBTYPE_MASK: | |
280 | break; | |
281 | default: | |
282 | llcSnapHeaderOffset = MAC_HEADER_SIZE; | |
283 | } | |
284 | } | |
285 | ||
286 | if (llcSnapHeaderOffset > 0) { | |
287 | /* QoS data or Data */ | |
4f70a8d4 | 288 | unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind(): SNAP header found & its offset %d\n", llcSnapHeaderOffset); |
7e6f5794 | 289 | if (memcmp((u8 *)(bulkdata->d[0].os_data_ptr+llcSnapHeaderOffset+wapiProtocolIdSNAPHeaderOffset), |
4f70a8d4 | 290 | wapiProtocolIdSNAPHeader, sizeof(wapiProtocolIdSNAPHeader))) { |
635d2b00 GKH |
291 | |
292 | unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind(): This is a data & NOT a WAI protocol packet\n"); | |
293 | /* On the first unicast data pkt that is decrypted successfully after re-keying, reset the filter */ | |
294 | priv->wapi_unicast_queued_pkt_filter = 0; | |
295 | unifi_trace(priv, UDBG4, "check_routing_pkt_data_ind(): WAPI AP has started using the new unicast key, no more MIC failures expected (reset filter)\n"); | |
296 | } | |
297 | else { | |
298 | unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind(): WAPI - This is a WAI protocol packet\n"); | |
299 | } | |
300 | } | |
301 | } | |
302 | #endif | |
303 | ||
304 | ||
305 | switch ((frmCtrl & 0x000c)>>FRAME_CONTROL_TYPE_FIELD_OFFSET) { | |
306 | case IEEE802_11_FRAMETYPE_MANAGEMENT: | |
307 | *freeBulkData = TRUE; /* Free (after SME handler copies it) */ | |
308 | ||
309 | /* In P2P device mode, filter the legacy AP beacons here */ | |
310 | if((interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2P)&&\ | |
311 | ((CSR_WIFI_80211_GET_FRAME_SUBTYPE(macHdrLocation)) == CSR_WIFI_80211_FRAME_SUBTYPE_BEACON)){ | |
312 | ||
7e6f5794 GKH |
313 | u8 *pSsid, *pSsidLen; |
314 | static u8 P2PWildCardSsid[CSR_WIFI_P2P_WILDCARD_SSID_LENGTH] = {'D', 'I', 'R', 'E', 'C', 'T', '-'}; | |
635d2b00 GKH |
315 | |
316 | pSsidLen = macHdrLocation + MAC_HEADER_SIZE + CSR_WIFI_BEACON_FIXED_LENGTH; | |
317 | pSsid = pSsidLen + 2; | |
318 | ||
319 | if(*(pSsidLen + 1) >= CSR_WIFI_P2P_WILDCARD_SSID_LENGTH){ | |
320 | if(memcmp(pSsid, P2PWildCardSsid, CSR_WIFI_P2P_WILDCARD_SSID_LENGTH) == 0){ | |
321 | unifi_trace(priv, UDBG6, "Received a P2P Beacon, pass it to SME\n"); | |
322 | return TRUE; | |
323 | } | |
324 | } | |
325 | unifi_trace(priv, UDBG6, "Received a Legacy AP beacon in P2P mode, drop it\n"); | |
326 | return FALSE; | |
327 | } | |
328 | return TRUE; /* Route to SME */ | |
329 | case IEEE802_11_FRAMETYPE_DATA: | |
330 | case IEEE802_11_FRAMETYPE_CONTROL: | |
331 | *freeBulkData = FALSE; /* Network stack or MLME handler frees */ | |
332 | return FALSE; | |
333 | default: | |
334 | unifi_error(priv, "Unhandled frame type %04x\n", frmCtrl); | |
335 | *freeBulkData = TRUE; /* Not interested, but must free it */ | |
336 | return FALSE; | |
337 | } | |
338 | } | |
635d2b00 | 339 | |
635d2b00 GKH |
340 | /* |
341 | * --------------------------------------------------------------------------- | |
95edd09e | 342 | * unifi_process_receive_event |
635d2b00 GKH |
343 | * |
344 | * Dispatcher for received signals. | |
345 | * | |
346 | * This function receives the 'to host' signals and forwards | |
347 | * them to the unifi linux clients. | |
348 | * | |
349 | * Arguments: | |
350 | * ospriv Pointer to driver's private data. | |
351 | * sigdata Pointer to the packed signal buffer. | |
352 | * siglen Length of the packed signal. | |
353 | * bulkdata Pointer to the signal's bulk data. | |
354 | * | |
355 | * Returns: | |
356 | * None. | |
357 | * | |
358 | * Notes: | |
359 | * The signals are received in the format described in the host interface | |
360 | * specification, i.e wire formatted. Certain clients use the same format | |
361 | * to interpret them and other clients use the host formatted structures. | |
362 | * Each client has to call read_unpack_signal() to transform the wire | |
363 | * formatted signal into the host formatted signal, if necessary. | |
364 | * The code is in the core, since the signals are defined therefore | |
365 | * binded to the host interface specification. | |
366 | * --------------------------------------------------------------------------- | |
367 | */ | |
95edd09e GKH |
368 | static void |
369 | unifi_process_receive_event(void *ospriv, | |
26a6b2e1 | 370 | u8 *sigdata, u32 siglen, |
95edd09e | 371 | const bulk_data_param_t *bulkdata) |
635d2b00 | 372 | { |
635d2b00 GKH |
373 | unifi_priv_t *priv = (unifi_priv_t*)ospriv; |
374 | int i, receiver_id; | |
375 | int client_id; | |
ab2b8c73 | 376 | s16 signal_id; |
5379b13d | 377 | u8 pktIndToSme = FALSE, freeBulkData = FALSE; |
635d2b00 | 378 | |
95edd09e GKH |
379 | unifi_trace(priv, UDBG5, "unifi_process_receive_event: " |
380 | "%04x %04x %04x %04x %04x %04x %04x %04x (%d)\n", | |
ab2b8c73 GKH |
381 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*0) & 0xFFFF, |
382 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*1) & 0xFFFF, | |
383 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*2) & 0xFFFF, | |
384 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*3) & 0xFFFF, | |
385 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*4) & 0xFFFF, | |
386 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*5) & 0xFFFF, | |
387 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*6) & 0xFFFF, | |
388 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*7) & 0xFFFF, | |
95edd09e | 389 | siglen); |
635d2b00 | 390 | |
ab2b8c73 | 391 | receiver_id = CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)) & 0xFF00; |
635d2b00 GKH |
392 | client_id = (receiver_id & 0x0F00) >> UDI_SENDER_ID_SHIFT; |
393 | signal_id = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata); | |
394 | ||
395 | ||
396 | ||
397 | /* check for the type of frame received (checks for 802.11 management frames) */ | |
398 | if (signal_id == CSR_MA_PACKET_INDICATION_ID) | |
399 | { | |
95edd09e | 400 | #define CSR_MA_PACKET_INDICATION_INTERFACETAG_OFFSET 14 |
7e6f5794 | 401 | u8 interfaceTag; |
635d2b00 GKH |
402 | netInterface_priv_t *interfacePriv; |
403 | ||
404 | /* Pull out interface tag from virtual interface identifier */ | |
95edd09e | 405 | interfaceTag = (CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + CSR_MA_PACKET_INDICATION_INTERFACETAG_OFFSET)) & 0xff; |
635d2b00 GKH |
406 | interfacePriv = priv->interfacePriv[interfaceTag]; |
407 | ||
408 | /* Update activity for this station in case of IBSS */ | |
409 | #ifdef CSR_SUPPORT_SME | |
95edd09e GKH |
410 | if (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_IBSS) |
411 | { | |
7e6f5794 | 412 | u8 *saddr; |
635d2b00 | 413 | /* Fetch the source address from mac header */ |
7e6f5794 | 414 | saddr = (u8 *) bulkdata->d[0].os_data_ptr + MAC_HEADER_ADDR2_OFFSET; |
635d2b00 GKH |
415 | unifi_trace(priv, UDBG5, |
416 | "Updating sta activity in IBSS interfaceTag %x Src Addr %x:%x:%x:%x:%x:%x\n", | |
417 | interfaceTag, saddr[0], saddr[1], saddr[2], saddr[3], saddr[4], saddr[5]); | |
418 | ||
419 | uf_update_sta_activity(priv, interfaceTag, saddr); | |
420 | } | |
421 | #endif | |
422 | ||
423 | pktIndToSme = check_routing_pkt_data_ind(priv, sigdata, bulkdata, &freeBulkData, interfacePriv); | |
424 | ||
425 | unifi_trace(priv, UDBG6, "RX: packet entry point to driver from HIP,pkt to SME ?(%s) \n", (pktIndToSme)? "YES":"NO"); | |
95edd09e | 426 | |
635d2b00 GKH |
427 | } |
428 | ||
429 | if (pktIndToSme) | |
430 | { | |
431 | /* Management MA_PACKET_IND for SME */ | |
432 | if(sigdata != NULL && bulkdata != NULL){ | |
433 | send_to_client(priv, priv->sme_cli, receiver_id, sigdata, siglen, bulkdata); | |
434 | } | |
435 | else{ | |
95edd09e | 436 | unifi_error(priv, "unifi_receive_event2: sigdata or Bulkdata is NULL \n"); |
635d2b00 GKH |
437 | } |
438 | #ifdef CSR_NATIVE_LINUX | |
439 | send_to_client(priv, priv->wext_client, | |
440 | receiver_id, | |
441 | sigdata, siglen, bulkdata); | |
442 | #endif | |
443 | } | |
444 | else | |
445 | { | |
446 | /* Signals with ReceiverId==0 are also reported to SME / WEXT, | |
447 | * unless they are data/control MA_PACKET_INDs or VIF_AVAILABILITY_INDs | |
448 | */ | |
449 | if (!receiver_id) { | |
95edd09e GKH |
450 | if(signal_id == CSR_MA_VIF_AVAILABILITY_INDICATION_ID) { |
451 | uf_process_ma_vif_availibility_ind(priv, sigdata, siglen); | |
452 | } | |
453 | else if (signal_id != CSR_MA_PACKET_INDICATION_ID) { | |
454 | send_to_client(priv, priv->sme_cli, receiver_id, sigdata, siglen, bulkdata); | |
635d2b00 | 455 | #ifdef CSR_NATIVE_LINUX |
95edd09e GKH |
456 | send_to_client(priv, priv->wext_client, |
457 | receiver_id, | |
458 | sigdata, siglen, bulkdata); | |
635d2b00 | 459 | #endif |
95edd09e GKH |
460 | } |
461 | else | |
462 | { | |
463 | ||
464 | #if (defined(CSR_SUPPORT_SME) && defined(CSR_WIFI_SECURITY_WAPI_ENABLE)) | |
465 | #define CSR_MA_PACKET_INDICATION_RECEPTION_STATUS_OFFSET sizeof(CSR_SIGNAL_PRIMITIVE_HEADER) + 22 | |
466 | netInterface_priv_t *interfacePriv; | |
7e6f5794 | 467 | u8 interfaceTag; |
8c87f69a | 468 | u16 receptionStatus = CSR_RX_SUCCESS; |
95edd09e GKH |
469 | |
470 | /* Pull out interface tag from virtual interface identifier */ | |
471 | interfaceTag = (CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + CSR_MA_PACKET_INDICATION_INTERFACETAG_OFFSET)) & 0xff; | |
472 | interfacePriv = priv->interfacePriv[interfaceTag]; | |
473 | ||
474 | /* check for MIC failure */ | |
475 | receptionStatus = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + CSR_MA_PACKET_INDICATION_RECEPTION_STATUS_OFFSET); | |
476 | ||
477 | /* Send a WAPI MPDU to SME for re-check MIC if the respective filter has been set*/ | |
478 | if ((!freeBulkData) && | |
479 | (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA) && | |
480 | (receptionStatus == CSR_MICHAEL_MIC_ERROR) && | |
481 | ((priv->wapi_multicast_filter == 1) | |
482 | #ifdef CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION | |
483 | || (priv->wapi_unicast_filter == 1) | |
635d2b00 | 484 | #endif |
95edd09e GKH |
485 | )) |
486 | { | |
487 | CSR_SIGNAL signal; | |
7e6f5794 | 488 | u8 *destAddr; |
95edd09e | 489 | CsrResult res; |
8c87f69a | 490 | u16 interfaceTag = 0; |
5379b13d | 491 | u8 isMcastPkt = TRUE; |
95edd09e GKH |
492 | |
493 | unifi_trace(priv, UDBG6, "Received a WAPI data packet when the Unicast/Multicast filter is set\n"); | |
494 | res = read_unpack_signal(sigdata, &signal); | |
495 | if (res) { | |
496 | unifi_error(priv, "Received unknown or corrupted signal (0x%x).\n", | |
497 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata)); | |
498 | return; | |
499 | } | |
500 | ||
501 | /* Check if the type of MPDU and the respective filter status*/ | |
7e6f5794 | 502 | destAddr = (u8 *) bulkdata->d[0].os_data_ptr + MAC_HEADER_ADDR1_OFFSET; |
95edd09e GKH |
503 | isMcastPkt = (destAddr[0] & 0x01) ? TRUE : FALSE; |
504 | unifi_trace(priv, UDBG6, | |
505 | "1.MPDU type: (%s), 2.Multicast filter: (%s), 3. Unicast filter: (%s)\n", | |
506 | ((isMcastPkt) ? "Multiast":"Unicast"), | |
507 | ((priv->wapi_multicast_filter) ? "Enabled":"Disabled"), | |
508 | ((priv->wapi_unicast_filter) ? "Enabled":"Disabled")); | |
509 | ||
510 | if (((isMcastPkt) && (priv->wapi_multicast_filter == 1)) | |
511 | #ifdef CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION | |
512 | || ((!isMcastPkt) && (priv->wapi_unicast_filter == 1)) | |
635d2b00 | 513 | #endif |
95edd09e GKH |
514 | ) |
515 | { | |
516 | unifi_trace(priv, UDBG4, "Sending the WAPI MPDU for MIC check\n"); | |
7e6f5794 | 517 | CsrWifiRouterCtrlWapiRxMicCheckIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, interfaceTag, siglen, sigdata, bulkdata->d[0].data_length, (u8*)bulkdata->d[0].os_data_ptr); |
95edd09e GKH |
518 | |
519 | for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) { | |
520 | if (bulkdata->d[i].data_length != 0) { | |
521 | unifi_net_data_free(priv, (void *)&bulkdata->d[i]); | |
522 | } | |
523 | } | |
95edd09e GKH |
524 | return; |
525 | } | |
526 | } /* CSR_MA_PACKET_INDICATION_ID */ | |
527 | #endif /*CSR_SUPPORT_SME && CSR_WIFI_SECURITY_WAPI_ENABLE*/ | |
528 | } | |
529 | } | |
635d2b00 GKH |
530 | |
531 | /* calls the registered clients handler callback func. | |
532 | * netdev_mlme_event_handler is one of the registered handler used to route | |
533 | * data packet to network stack or AMP/EAPOL related data to SME | |
95edd09e GKH |
534 | * |
535 | * The freeBulkData check ensures that, it has received a management frame and | |
635d2b00 GKH |
536 | * the frame needs to be freed here. So not to be passed to netdev handler |
537 | */ | |
538 | if(!freeBulkData){ | |
539 | if ((client_id < MAX_UDI_CLIENTS) && | |
540 | (&priv->ul_clients[client_id] != priv->logging_client)) { | |
95edd09e | 541 | unifi_trace(priv, UDBG6, "Call the registered clients handler callback func\n"); |
635d2b00 GKH |
542 | send_to_client(priv, &priv->ul_clients[client_id], |
543 | receiver_id, | |
544 | sigdata, siglen, bulkdata); | |
545 | } | |
546 | } | |
547 | } | |
548 | ||
549 | /* | |
550 | * Free bulk data buffers here unless it is a CSR_MA_PACKET_INDICATION | |
551 | */ | |
552 | switch (signal_id) | |
553 | { | |
554 | #ifdef UNIFI_SNIFF_ARPHRD | |
555 | case CSR_MA_SNIFFDATA_INDICATION_ID: | |
556 | #endif | |
557 | break; | |
558 | ||
559 | case CSR_MA_PACKET_INDICATION_ID: | |
560 | if (!freeBulkData) | |
561 | { | |
562 | break; | |
563 | } | |
564 | /* FALLS THROUGH... */ | |
565 | default: | |
566 | for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) { | |
567 | if (bulkdata->d[i].data_length != 0) { | |
568 | unifi_net_data_free(priv, (void *)&bulkdata->d[i]); | |
569 | } | |
570 | } | |
571 | } | |
95edd09e | 572 | |
95edd09e GKH |
573 | } /* unifi_process_receive_event() */ |
574 | ||
635d2b00 GKH |
575 | |
576 | #ifdef CSR_WIFI_RX_PATH_SPLIT | |
5379b13d | 577 | static u8 signal_buffer_is_full(unifi_priv_t* priv) |
95edd09e GKH |
578 | { |
579 | return (((priv->rxSignalBuffer.writePointer + 1)% priv->rxSignalBuffer.size) == (priv->rxSignalBuffer.readPointer)); | |
580 | } | |
581 | ||
582 | void unifi_rx_queue_flush(void *ospriv) | |
583 | { | |
584 | unifi_priv_t *priv = (unifi_priv_t*)ospriv; | |
585 | ||
95edd09e | 586 | unifi_trace(priv, UDBG4, "rx_wq_handler: RdPtr = %d WritePtr = %d\n", |
4f70a8d4 | 587 | priv->rxSignalBuffer.readPointer, priv->rxSignalBuffer.writePointer); |
95edd09e | 588 | if(priv != NULL) { |
7e6f5794 | 589 | u8 readPointer = priv->rxSignalBuffer.readPointer; |
95edd09e GKH |
590 | while (readPointer != priv->rxSignalBuffer.writePointer) |
591 | { | |
592 | rx_buff_struct_t *buf = &priv->rxSignalBuffer.rx_buff[readPointer]; | |
593 | unifi_trace(priv, UDBG6, "rx_wq_handler: RdPtr = %d WritePtr = %d\n", | |
4f70a8d4 | 594 | readPointer, priv->rxSignalBuffer.writePointer); |
95edd09e GKH |
595 | unifi_process_receive_event(priv, buf->bufptr, buf->sig_len, &buf->data_ptrs); |
596 | readPointer ++; | |
597 | if(readPointer >= priv->rxSignalBuffer.size) { | |
598 | readPointer = 0; | |
599 | } | |
600 | } | |
601 | priv->rxSignalBuffer.readPointer = readPointer; | |
602 | } | |
95edd09e GKH |
603 | } |
604 | ||
605 | void rx_wq_handler(struct work_struct *work) | |
606 | { | |
607 | unifi_priv_t *priv = container_of(work, unifi_priv_t, rx_work_struct); | |
608 | unifi_rx_queue_flush(priv); | |
609 | } | |
610 | #endif | |
611 | ||
612 | ||
613 | ||
635d2b00 GKH |
614 | /* |
615 | * --------------------------------------------------------------------------- | |
95edd09e | 616 | * unifi_receive_event |
635d2b00 GKH |
617 | * |
618 | * Dispatcher for received signals. | |
619 | * | |
620 | * This function receives the 'to host' signals and forwards | |
621 | * them to the unifi linux clients. | |
622 | * | |
623 | * Arguments: | |
624 | * ospriv Pointer to driver's private data. | |
625 | * sigdata Pointer to the packed signal buffer. | |
626 | * siglen Length of the packed signal. | |
627 | * bulkdata Pointer to the signal's bulk data. | |
628 | * | |
629 | * Returns: | |
630 | * None. | |
631 | * | |
632 | * Notes: | |
633 | * The signals are received in the format described in the host interface | |
634 | * specification, i.e wire formatted. Certain clients use the same format | |
635 | * to interpret them and other clients use the host formatted structures. | |
636 | * Each client has to call read_unpack_signal() to transform the wire | |
637 | * formatted signal into the host formatted signal, if necessary. | |
638 | * The code is in the core, since the signals are defined therefore | |
639 | * binded to the host interface specification. | |
640 | * --------------------------------------------------------------------------- | |
641 | */ | |
95edd09e GKH |
642 | void |
643 | unifi_receive_event(void *ospriv, | |
26a6b2e1 | 644 | u8 *sigdata, u32 siglen, |
95edd09e | 645 | const bulk_data_param_t *bulkdata) |
635d2b00 | 646 | { |
95edd09e | 647 | #ifdef CSR_WIFI_RX_PATH_SPLIT |
635d2b00 | 648 | unifi_priv_t *priv = (unifi_priv_t*)ospriv; |
7e6f5794 | 649 | u8 writePointer; |
95edd09e GKH |
650 | int i; |
651 | rx_buff_struct_t * rx_buff; | |
635d2b00 | 652 | |
95edd09e | 653 | unifi_trace(priv, UDBG5, "unifi_receive_event: " |
635d2b00 | 654 | "%04x %04x %04x %04x %04x %04x %04x %04x (%d)\n", |
ab2b8c73 GKH |
655 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*0) & 0xFFFF, |
656 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*1) & 0xFFFF, | |
657 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*2) & 0xFFFF, | |
658 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*3) & 0xFFFF, | |
659 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*4) & 0xFFFF, | |
660 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*5) & 0xFFFF, | |
661 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*6) & 0xFFFF, | |
662 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*7) & 0xFFFF, siglen); | |
95edd09e | 663 | if(signal_buffer_is_full(priv)) { |
4f70a8d4 | 664 | unifi_error(priv, "TO HOST signal queue FULL dropping the PDU\n"); |
95edd09e GKH |
665 | for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) { |
666 | if (bulkdata->d[i].data_length != 0) { | |
667 | unifi_net_data_free(priv, (void *)&bulkdata->d[i]); | |
668 | } | |
635d2b00 | 669 | } |
95edd09e | 670 | return; |
635d2b00 | 671 | } |
95edd09e GKH |
672 | writePointer = priv->rxSignalBuffer.writePointer; |
673 | rx_buff = &priv->rxSignalBuffer.rx_buff[writePointer]; | |
4f70a8d4 | 674 | memcpy(rx_buff->bufptr, sigdata, siglen); |
95edd09e GKH |
675 | rx_buff->sig_len = siglen; |
676 | rx_buff->data_ptrs = *bulkdata; | |
677 | writePointer++; | |
678 | if(writePointer >= priv->rxSignalBuffer.size) { | |
679 | writePointer =0; | |
635d2b00 | 680 | } |
4f70a8d4 | 681 | unifi_trace(priv, UDBG4, "unifi_receive_event:writePtr = %d\n", priv->rxSignalBuffer.writePointer); |
95edd09e | 682 | priv->rxSignalBuffer.writePointer = writePointer; |
635d2b00 | 683 | |
95edd09e GKH |
684 | #ifndef CSR_WIFI_RX_PATH_SPLIT_DONT_USE_WQ |
685 | queue_work(priv->rx_workqueue, &priv->rx_work_struct); | |
635d2b00 GKH |
686 | #endif |
687 | ||
95edd09e GKH |
688 | #else |
689 | unifi_process_receive_event(ospriv, sigdata, siglen, bulkdata); | |
635d2b00 | 690 | #endif |
95edd09e | 691 | } /* unifi_receive_event() */ |
635d2b00 | 692 |