]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/csr/unifi_sme.c
51d679234a522cef13480f509ebae1a85b5ee137
[karo-tx-linux.git] / drivers / staging / csr / unifi_sme.c
1 /*
2  * ***************************************************************************
3  *  FILE:     unifi_sme.c
4  *
5  *  PURPOSE:    SME related functions.
6  *
7  *  Copyright (C) 2007-2009 by Cambridge Silicon Radio Ltd.
8  *
9  * Refer to LICENSE.txt included with this source code for details on
10  * the license terms.
11  *
12  * ***************************************************************************
13  */
14
15 #include "unifi_priv.h"
16 #include "csr_wifi_hip_unifi.h"
17 #include "csr_wifi_hip_conversions.h"
18
19
20
21
22     int
23 convert_sme_error(CsrResult error)
24 {
25     switch (error) {
26         case CSR_RESULT_SUCCESS:
27             return 0;
28         case CSR_RESULT_FAILURE:
29         case CSR_WIFI_RESULT_NOT_FOUND:
30         case CSR_WIFI_RESULT_TIMED_OUT:
31         case CSR_WIFI_RESULT_CANCELLED:
32         case CSR_WIFI_RESULT_UNAVAILABLE:
33             return -EIO;
34         case CSR_WIFI_RESULT_NO_ROOM:
35             return -EBUSY;
36         case CSR_WIFI_RESULT_INVALID_PARAMETER:
37             return -EINVAL;
38         case CSR_WIFI_RESULT_UNSUPPORTED:
39             return -EOPNOTSUPP;
40         default:
41             return -EIO;
42     }
43 }
44
45
46 /*
47  * ---------------------------------------------------------------------------
48  *  sme_log_event
49  *
50  *      Callback function to be registered as the SME event callback.
51  *      Copies the signal content into a new udi_log_t struct and adds
52  *      it to the read queue for the SME client.
53  *
54  *  Arguments:
55  *      arg             This is the value given to unifi_add_udi_hook, in
56  *                      this case a pointer to the client instance.
57  *      signal          Pointer to the received signal.
58  *      signal_len      Size of the signal structure in bytes.
59  *      bulkdata        Pointers to any associated bulk data.
60  *      dir             Direction of the signal. Zero means from host,
61  *                      non-zero means to host.
62  *
63  *  Returns:
64  *      None.
65  * ---------------------------------------------------------------------------
66  */
67     void
68 sme_log_event(ul_client_t *pcli,
69         const u8 *signal, int signal_len,
70         const bulk_data_param_t *bulkdata,
71         int dir)
72 {
73     unifi_priv_t *priv;
74     CSR_SIGNAL unpacked_signal;
75     CsrWifiSmeDataBlock mlmeCommand;
76     CsrWifiSmeDataBlock dataref1;
77     CsrWifiSmeDataBlock dataref2;
78     CsrResult result = CSR_RESULT_SUCCESS;
79     int r;
80
81     func_enter();
82     /* Just a sanity check */
83     if ((signal == NULL) || (signal_len <= 0)) {
84         func_exit();
85         return;
86     }
87
88     priv = uf_find_instance(pcli->instance);
89     if (!priv) {
90         unifi_error(priv, "sme_log_event: invalid priv\n");
91         func_exit();
92         return;
93     }
94
95     if (priv->smepriv == NULL) {
96         unifi_error(priv, "sme_log_event: invalid smepriv\n");
97         func_exit();
98         return;
99     }
100
101     unifi_trace(priv, UDBG3,
102             "sme_log_event: Process signal 0x%.4X\n",
103             CSR_GET_UINT16_FROM_LITTLE_ENDIAN(signal));
104
105
106     /* If the signal is known, then do any filtering required, otherwise it pass it to the SME. */
107     r = read_unpack_signal(signal, &unpacked_signal);
108     if (r == CSR_RESULT_SUCCESS) {
109         if ((unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_DEBUG_STRING_INDICATION_ID) ||
110             (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_DEBUG_WORD16_INDICATION_ID))
111         {
112             func_exit();
113             return;
114         }
115         if (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_MA_PACKET_INDICATION_ID)
116         {
117             u16 frmCtrl;
118             u8 unicastPdu = TRUE;
119             u8 *macHdrLocation;
120             u8 *raddr = NULL, *taddr = NULL;
121             CsrWifiMacAddress peerMacAddress;
122             /* Check if we need to send CsrWifiRouterCtrlMicFailureInd*/
123             CSR_MA_PACKET_INDICATION *ind = &unpacked_signal.u.MaPacketIndication;
124
125             macHdrLocation = (u8 *) bulkdata->d[0].os_data_ptr;
126             /* Fetch the frame control value from  mac header */
127             frmCtrl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(macHdrLocation);
128
129             /* Point to the addresses */
130             raddr = macHdrLocation + MAC_HEADER_ADDR1_OFFSET;
131             taddr = macHdrLocation + MAC_HEADER_ADDR2_OFFSET;
132
133             memcpy(peerMacAddress.a, taddr, ETH_ALEN);
134
135             if(ind->ReceptionStatus == CSR_MICHAEL_MIC_ERROR)
136             {
137                 if (*raddr & 0x1)
138                     unicastPdu = FALSE;
139
140                 CsrWifiRouterCtrlMicFailureIndSend (priv->CSR_WIFI_SME_IFACEQUEUE, 0,
141                         (ind->VirtualInterfaceIdentifier & 0xff),peerMacAddress,
142                         unicastPdu);
143                 return;
144             }
145             else
146             {
147                 if(ind->ReceptionStatus == CSR_RX_SUCCESS)
148                 {
149                     u8 pmBit = (frmCtrl & 0x1000)?0x01:0x00;
150                     u16 interfaceTag = (ind->VirtualInterfaceIdentifier & 0xff);
151                     CsrWifiRouterCtrlStaInfo_t *srcStaInfo =  CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv,taddr,interfaceTag);
152                     if((srcStaInfo != NULL) && (uf_check_broadcast_bssid(priv, bulkdata)== FALSE))
153                     {
154                         uf_process_pm_bit_for_peer(priv,srcStaInfo,pmBit,interfaceTag);
155
156                         /* Update station last activity flag */
157                         srcStaInfo->activity_flag = TRUE;
158                     }
159                 }
160             }
161         }
162
163         if (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_MA_PACKET_CONFIRM_ID)
164         {
165             CSR_MA_PACKET_CONFIRM *cfm = &unpacked_signal.u.MaPacketConfirm;
166             u16 interfaceTag = (cfm->VirtualInterfaceIdentifier & 0xff);
167             netInterface_priv_t *interfacePriv;
168             CSR_MA_PACKET_REQUEST *req;
169             CsrWifiMacAddress peerMacAddress;
170
171             if (interfaceTag >= CSR_WIFI_NUM_INTERFACES)
172             {
173                 unifi_error(priv, "Bad MA_PACKET_CONFIRM interfaceTag %d\n", interfaceTag);
174                 func_exit();
175                 return;
176             }
177
178             unifi_trace(priv,UDBG1,"MA-PACKET Confirm (%x, %x)\n", cfm->HostTag, cfm->TransmissionStatus);
179
180             interfacePriv = priv->interfacePriv[interfaceTag];
181 #ifdef CSR_SUPPORT_SME
182             if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
183                  interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
184
185                 if(cfm->HostTag == interfacePriv->multicastPduHostTag){
186                     uf_process_ma_pkt_cfm_for_ap(priv ,interfaceTag, cfm);
187                 }
188             }
189 #endif
190
191             req = &interfacePriv->m4_signal.u.MaPacketRequest;
192
193             if(cfm->HostTag & 0x80000000)
194             {
195                 if (cfm->TransmissionStatus != CSR_TX_SUCCESSFUL)
196                 {
197                     result = CSR_RESULT_FAILURE;
198                 }
199 #ifdef CSR_SUPPORT_SME
200                 memcpy(peerMacAddress.a, req->Ra.x, ETH_ALEN);
201                 /* Check if this is a confirm for EAPOL M4 frame and we need to send transmistted ind*/
202                 if (interfacePriv->m4_sent && (cfm->HostTag == interfacePriv->m4_hostTag))
203                 {
204                     unifi_trace(priv, UDBG1, "%s: Sending M4 Transmit CFM\n", __FUNCTION__);
205                     CsrWifiRouterCtrlM4TransmittedIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0,
206                             interfaceTag,
207                             peerMacAddress,
208                             result);
209                     interfacePriv->m4_sent = FALSE;
210                     interfacePriv->m4_hostTag = 0xffffffff;
211                 }
212 #endif
213                 /* If EAPOL was requested via router APIs then send cfm else ignore*/
214                 if((cfm->HostTag & 0x80000000) != CSR_WIFI_EAPOL_M4_HOST_TAG) {
215                     CsrWifiRouterMaPacketCfmSend((u16)signal[2],
216                         cfm->VirtualInterfaceIdentifier,
217                         result,
218                         (cfm->HostTag & 0x3fffffff), cfm->Rate);
219                 } else {
220                     unifi_trace(priv, UDBG1, "%s: M4 received from netdevice\n", __FUNCTION__);
221                 }
222                 func_exit();
223                 return;
224             }
225         }
226     }
227
228     mlmeCommand.length = signal_len;
229     mlmeCommand.data = (u8*)signal;
230
231     dataref1.length = bulkdata->d[0].data_length;
232     if (dataref1.length > 0) {
233         dataref1.data = (u8 *) bulkdata->d[0].os_data_ptr;
234     } else
235     {
236         dataref1.data = NULL;
237     }
238
239     dataref2.length = bulkdata->d[1].data_length;
240     if (dataref2.length > 0) {
241         dataref2.data = (u8 *) bulkdata->d[1].os_data_ptr;
242     } else
243     {
244         dataref2.data = NULL;
245     }
246
247     CsrWifiRouterCtrlHipIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, mlmeCommand.length, mlmeCommand.data,
248             dataref1.length, dataref1.data,
249             dataref2.length, dataref2.data);
250
251     func_exit();
252 } /* sme_log_event() */
253
254
255 /*
256  * ---------------------------------------------------------------------------
257  * uf_sme_port_state
258  *
259  *      Return the state of the controlled port.
260  *
261  * Arguments:
262  *      priv            Pointer to device private context struct
263  *      address    Pointer to the destination for tx or sender for rx address
264  *      queue           Controlled or uncontrolled queue
265  *
266  * Returns:
267  *      An unifi_ControlledPortAction value.
268  * ---------------------------------------------------------------------------
269  */
270 CsrWifiRouterCtrlPortAction
271 uf_sme_port_state(unifi_priv_t *priv, unsigned char *address, int queue, u16 interfaceTag)
272 {
273     int i;
274     unifi_port_config_t *port;
275     netInterface_priv_t *interfacePriv;
276
277     if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
278         unifi_error(priv, "uf_sme_port_state: bad interfaceTag\n");
279         return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
280     }
281
282     interfacePriv = priv->interfacePriv[interfaceTag];
283
284     if (queue == UF_CONTROLLED_PORT_Q) {
285         port = &interfacePriv->controlled_data_port;
286     } else {
287         port = &interfacePriv->uncontrolled_data_port;
288     }
289
290     if (!port->entries_in_use) {
291         unifi_trace(priv, UDBG5, "No port configurations, return Discard.\n");
292         return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
293     }
294
295     /* If the port configuration is common for all destinations, return it. */
296     if (port->overide_action == UF_DATA_PORT_OVERIDE) {
297         unifi_trace(priv, UDBG5, "Single port configuration (%d).\n",
298                 port->port_cfg[0].port_action);
299         return port->port_cfg[0].port_action;
300     }
301
302     unifi_trace(priv, UDBG5, "Multiple (%d) port configurations.\n", port->entries_in_use);
303
304     /* If multiple configurations exist.. */
305     for (i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
306         /* .. go through the list and match the destination address. */
307         if (port->port_cfg[i].in_use &&
308             memcmp(address, port->port_cfg[i].mac_address.a, ETH_ALEN) == 0) {
309             /* Return the desired action. */
310             return port->port_cfg[i].port_action;
311         }
312     }
313
314     /* Could not find any information, return Open. */
315     unifi_trace(priv, UDBG5, "port configuration not found, return Open.\n");
316     return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN;
317 } /* uf_sme_port_state() */
318
319 /*
320  * ---------------------------------------------------------------------------
321  * uf_sme_port_config_handle
322  *
323  *      Return the port config handle of the controlled/uncontrolled port.
324  *
325  * Arguments:
326  *      priv            Pointer to device private context struct
327  *      address    Pointer to the destination for tx or sender for rx address
328  *      queue           Controlled or uncontrolled queue
329  *
330  * Returns:
331  *      An  unifi_port_cfg_t* .
332  * ---------------------------------------------------------------------------
333  */
334 unifi_port_cfg_t*
335 uf_sme_port_config_handle(unifi_priv_t *priv, unsigned char *address, int queue, u16 interfaceTag)
336 {
337     int i;
338     unifi_port_config_t *port;
339     netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
340
341     if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
342         unifi_error(priv, "uf_sme_port_config_handle: bad interfaceTag\n");
343         return NULL;
344     }
345
346     if (queue == UF_CONTROLLED_PORT_Q) {
347         port = &interfacePriv->controlled_data_port;
348     } else {
349         port = &interfacePriv->uncontrolled_data_port;
350     }
351
352     if (!port->entries_in_use) {
353         unifi_trace(priv, UDBG5, "No port configurations, return Discard.\n");
354         return NULL;
355     }
356
357     /* If the port configuration is common for all destinations, return it. */
358     if (port->overide_action == UF_DATA_PORT_OVERIDE) {
359         unifi_trace(priv, UDBG5, "Single port configuration (%d).\n",
360                 port->port_cfg[0].port_action);
361         if (address) {
362             unifi_trace(priv, UDBG5, "addr[0] = %x, addr[1] = %x, addr[2] = %x, addr[3] = %x\n", address[0], address[1], address[2], address[3]);
363         }
364         return &port->port_cfg[0];
365     }
366
367     unifi_trace(priv, UDBG5, "Multiple port configurations.\n");
368
369     /* If multiple configurations exist.. */
370     for (i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
371         /* .. go through the list and match the destination address. */
372         if (port->port_cfg[i].in_use &&
373             memcmp(address, port->port_cfg[i].mac_address.a, ETH_ALEN) == 0) {
374             /* Return the desired action. */
375             return &port->port_cfg[i];
376         }
377     }
378
379     /* Could not find any information, return Open. */
380     unifi_trace(priv, UDBG5, "port configuration not found, returning NULL (debug).\n");
381     return NULL;
382 } /* uf_sme_port_config_handle */
383
384 void
385 uf_multicast_list_wq(struct work_struct *work)
386 {
387     unifi_priv_t *priv = container_of(work, unifi_priv_t,
388             multicast_list_task);
389     int i;
390     u16 interfaceTag = 0;
391     CsrWifiMacAddress* multicast_address_list = NULL;
392     int mc_count;
393     u8 *mc_list;
394     netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
395
396     if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
397         unifi_error(priv, "uf_multicast_list_wq: bad interfaceTag\n");
398         return;
399     }
400
401     unifi_trace(priv, UDBG5,
402             "uf_multicast_list_wq: list count = %d\n",
403             interfacePriv->mc_list_count);
404
405     /* Flush the current list */
406     CsrWifiRouterCtrlMulticastAddressIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, interfaceTag, CSR_WIFI_SME_LIST_ACTION_FLUSH, 0, NULL);
407
408     mc_count = interfacePriv->mc_list_count;
409     mc_list = interfacePriv->mc_list;
410     /*
411      * Allocate a new list, need to free it later
412      * in unifi_mgt_multicast_address_cfm().
413      */
414     multicast_address_list = CsrPmemAlloc(mc_count * sizeof(CsrWifiMacAddress));
415
416     if (multicast_address_list == NULL) {
417         return;
418     }
419
420     for (i = 0; i < mc_count; i++) {
421         memcpy(multicast_address_list[i].a, mc_list, ETH_ALEN);
422         mc_list += ETH_ALEN;
423     }
424
425     if (priv->smepriv == NULL) {
426         CsrPmemFree(multicast_address_list);
427         return;
428     }
429
430     CsrWifiRouterCtrlMulticastAddressIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,
431             interfaceTag,
432             CSR_WIFI_SME_LIST_ACTION_ADD,
433             mc_count, multicast_address_list);
434
435     /* The SME will take a copy of the addreses*/
436     CsrPmemFree(multicast_address_list);
437 }
438
439
440 int unifi_cfg_power(unifi_priv_t *priv, unsigned char *arg)
441 {
442     unifi_cfg_power_t cfg_power;
443     int rc;
444     int wol;
445
446     if (get_user(cfg_power, (unifi_cfg_power_t*)(((unifi_cfg_command_t*)arg) + 1))) {
447         unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
448         return -EFAULT;
449     }
450
451     switch (cfg_power) {
452         case UNIFI_CFG_POWER_OFF:
453             priv->wol_suspend = (enable_wol == UNIFI_WOL_OFF) ? FALSE : TRUE;
454             rc = sme_sys_suspend(priv);
455             if (rc) {
456                 return rc;
457             }
458             break;
459         case UNIFI_CFG_POWER_ON:
460             wol = priv->wol_suspend;
461             rc = sme_sys_resume(priv);
462             if (rc) {
463                 return rc;
464             }
465             if (wol) {
466                 /* Kick the BH to ensure pending transfers are handled when
467                  * a suspend happened with card powered.
468                  */
469                 unifi_send_signal(priv->card, NULL, 0, NULL);
470             }
471             break;
472         default:
473             unifi_error(priv, "WIFI POWER: Unknown value.\n");
474             return -EINVAL;
475     }
476
477     return 0;
478 }
479
480
481 int unifi_cfg_power_save(unifi_priv_t *priv, unsigned char *arg)
482 {
483     unifi_cfg_powersave_t cfg_power_save;
484     CsrWifiSmePowerConfig powerConfig;
485     int rc;
486
487     if (get_user(cfg_power_save, (unifi_cfg_powersave_t*)(((unifi_cfg_command_t*)arg) + 1))) {
488         unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
489         return -EFAULT;
490     }
491
492     /* Get the coex info from the SME */
493     rc = sme_mgt_power_config_get(priv, &powerConfig);
494     if (rc) {
495         unifi_error(priv, "UNIFI_CFG: Get unifi_PowerConfigValue failed.\n");
496         return rc;
497     }
498
499     switch (cfg_power_save) {
500         case UNIFI_CFG_POWERSAVE_NONE:
501             powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW;
502             break;
503         case UNIFI_CFG_POWERSAVE_FAST:
504             powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_MED;
505             break;
506         case UNIFI_CFG_POWERSAVE_FULL:
507             powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_HIGH;
508             break;
509         case UNIFI_CFG_POWERSAVE_AUTO:
510             powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_AUTO;
511             break;
512         default:
513             unifi_error(priv, "POWERSAVE: Unknown value.\n");
514             return -EINVAL;
515     }
516
517     rc = sme_mgt_power_config_set(priv, &powerConfig);
518
519     if (rc) {
520         unifi_error(priv, "UNIFI_CFG: Set unifi_PowerConfigValue failed.\n");
521     }
522
523     return rc;
524 }
525
526
527 int unifi_cfg_power_supply(unifi_priv_t *priv, unsigned char *arg)
528 {
529     unifi_cfg_powersupply_t cfg_power_supply;
530     CsrWifiSmeHostConfig hostConfig;
531     int rc;
532
533     if (get_user(cfg_power_supply, (unifi_cfg_powersupply_t*)(((unifi_cfg_command_t*)arg) + 1))) {
534         unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
535         return -EFAULT;
536     }
537
538     /* Get the coex info from the SME */
539     rc = sme_mgt_host_config_get(priv, &hostConfig);
540     if (rc) {
541         unifi_error(priv, "UNIFI_CFG: Get unifi_HostConfigValue failed.\n");
542         return rc;
543     }
544
545     switch (cfg_power_supply) {
546         case UNIFI_CFG_POWERSUPPLY_MAINS:
547             hostConfig.powerMode = CSR_WIFI_SME_HOST_POWER_MODE_ACTIVE;
548             break;
549         case UNIFI_CFG_POWERSUPPLY_BATTERIES:
550             hostConfig.powerMode = CSR_WIFI_SME_HOST_POWER_MODE_POWER_SAVE;
551             break;
552         default:
553             unifi_error(priv, "POWERSUPPLY: Unknown value.\n");
554             return -EINVAL;
555     }
556
557     rc = sme_mgt_host_config_set(priv, &hostConfig);
558     if (rc) {
559         unifi_error(priv, "UNIFI_CFG: Set unifi_HostConfigValue failed.\n");
560     }
561
562     return rc;
563 }
564
565
566 int unifi_cfg_packet_filters(unifi_priv_t *priv, unsigned char *arg)
567 {
568     unsigned char *tclas_buffer;
569     unsigned int tclas_buffer_length;
570     tclas_t *dhcp_tclas;
571     int rc;
572
573     /* Free any TCLASs previously allocated */
574     if (priv->packet_filters.tclas_ies_length) {
575         CsrPmemFree(priv->filter_tclas_ies);
576         priv->filter_tclas_ies = NULL;
577     }
578
579     tclas_buffer = ((unsigned char*)arg) + sizeof(unifi_cfg_command_t) + sizeof(unsigned int);
580     if (copy_from_user(&priv->packet_filters, (void*)tclas_buffer,
581                 sizeof(uf_cfg_bcast_packet_filter_t))) {
582         unifi_error(priv, "UNIFI_CFG: Failed to get the filter struct\n");
583         return -EFAULT;
584     }
585
586     tclas_buffer_length = priv->packet_filters.tclas_ies_length;
587
588     /* Allocate TCLASs if necessary */
589     if (priv->packet_filters.dhcp_filter) {
590         priv->packet_filters.tclas_ies_length += sizeof(tclas_t);
591     }
592     if (priv->packet_filters.tclas_ies_length > 0) {
593         priv->filter_tclas_ies = CsrPmemAlloc(priv->packet_filters.tclas_ies_length);
594         if (priv->filter_tclas_ies == NULL) {
595             return -ENOMEM;
596         }
597         if (tclas_buffer_length) {
598             tclas_buffer += sizeof(uf_cfg_bcast_packet_filter_t) - sizeof(unsigned char*);
599             if (copy_from_user(priv->filter_tclas_ies,
600                         tclas_buffer,
601                         tclas_buffer_length)) {
602                 unifi_error(priv, "UNIFI_CFG: Failed to get the TCLAS buffer\n");
603                 return -EFAULT;
604             }
605         }
606     }
607
608     if(priv->packet_filters.dhcp_filter)
609     {
610         /* Append the DHCP tclas IE */
611         dhcp_tclas = (tclas_t*)(priv->filter_tclas_ies + tclas_buffer_length);
612         memset(dhcp_tclas, 0, sizeof(tclas_t));
613         dhcp_tclas->element_id = 14;
614         dhcp_tclas->length = sizeof(tcpip_clsfr_t) + 1;
615         dhcp_tclas->user_priority = 0;
616         dhcp_tclas->tcp_ip_cls_fr.cls_fr_type = 1;
617         dhcp_tclas->tcp_ip_cls_fr.version = 4;
618         ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.source_port))[0] = 0x00;
619         ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.source_port))[1] = 0x44;
620         ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.dest_port))[0] = 0x00;
621         ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.dest_port))[1] = 0x43;
622         dhcp_tclas->tcp_ip_cls_fr.protocol = 0x11;
623         dhcp_tclas->tcp_ip_cls_fr.cls_fr_mask = 0x58; //bits: 3,4,6
624     }
625
626     rc = sme_mgt_packet_filter_set(priv);
627
628     return rc;
629 }
630
631
632 int unifi_cfg_wmm_qos_info(unifi_priv_t *priv, unsigned char *arg)
633 {
634     u8 wmm_qos_info;
635     int rc = 0;
636
637     if (get_user(wmm_qos_info, (u8*)(((unifi_cfg_command_t*)arg) + 1))) {
638         unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
639         return -EFAULT;
640     }
641
642     /* Store the value in the connection info */
643     priv->connection_config.wmmQosInfo = wmm_qos_info;
644
645     return rc;
646 }
647
648
649 int unifi_cfg_wmm_addts(unifi_priv_t *priv, unsigned char *arg)
650 {
651     u32 addts_tid;
652     u8 addts_ie_length;
653     u8 *addts_ie;
654     u8 *addts_params;
655     CsrWifiSmeDataBlock tspec;
656     CsrWifiSmeDataBlock tclas;
657     int rc;
658
659     addts_params = (u8*)(((unifi_cfg_command_t*)arg) + 1);
660     if (get_user(addts_tid, (u32*)addts_params)) {
661         unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the argument\n");
662         return -EFAULT;
663     }
664
665     addts_params += sizeof(u32);
666     if (get_user(addts_ie_length, (u8*)addts_params)) {
667         unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the argument\n");
668         return -EFAULT;
669     }
670
671     unifi_trace(priv, UDBG4, "addts: tid = 0x%x ie_length = %d\n",
672             addts_tid, addts_ie_length);
673
674     addts_ie = CsrPmemAlloc(addts_ie_length);
675     if (addts_ie == NULL) {
676         unifi_error(priv,
677                 "unifi_cfg_wmm_addts: Failed to malloc %d bytes for addts_ie buffer\n",
678                 addts_ie_length);
679         return -ENOMEM;
680     }
681
682     addts_params += sizeof(u8);
683     rc = copy_from_user(addts_ie, addts_params, addts_ie_length);
684     if (rc) {
685         unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the addts buffer\n");
686         CsrPmemFree(addts_ie);
687         return -EFAULT;
688     }
689
690     tspec.data = addts_ie;
691     tspec.length = addts_ie_length;
692     tclas.data = NULL;
693     tclas.length = 0;
694
695     rc = sme_mgt_tspec(priv, CSR_WIFI_SME_LIST_ACTION_ADD, addts_tid,
696             &tspec, &tclas);
697
698     CsrPmemFree(addts_ie);
699     return rc;
700 }
701
702
703 int unifi_cfg_wmm_delts(unifi_priv_t *priv, unsigned char *arg)
704 {
705     u32 delts_tid;
706     u8 *delts_params;
707     CsrWifiSmeDataBlock tspec;
708     CsrWifiSmeDataBlock tclas;
709     int rc;
710
711     delts_params = (u8*)(((unifi_cfg_command_t*)arg) + 1);
712     if (get_user(delts_tid, (u32*)delts_params)) {
713         unifi_error(priv, "unifi_cfg_wmm_delts: Failed to get the argument\n");
714         return -EFAULT;
715     }
716
717     unifi_trace(priv, UDBG4, "delts: tid = 0x%x\n", delts_tid);
718
719     tspec.data = tclas.data = NULL;
720     tspec.length = tclas.length = 0;
721
722     rc = sme_mgt_tspec(priv, CSR_WIFI_SME_LIST_ACTION_REMOVE, delts_tid,
723             &tspec, &tclas);
724
725     return rc;
726 }
727
728 int unifi_cfg_strict_draft_n(unifi_priv_t *priv, unsigned char *arg)
729 {
730     u8 strict_draft_n;
731     u8 *strict_draft_n_params;
732     int rc;
733
734     CsrWifiSmeStaConfig  staConfig;
735     CsrWifiSmeDeviceConfig  deviceConfig;
736
737     strict_draft_n_params = (u8*)(((unifi_cfg_command_t*)arg) + 1);
738     if (get_user(strict_draft_n, (u8*)strict_draft_n_params)) {
739         unifi_error(priv, "unifi_cfg_strict_draft_n: Failed to get the argument\n");
740         return -EFAULT;
741     }
742
743     unifi_trace(priv, UDBG4, "strict_draft_n: = %s\n", ((strict_draft_n) ? "yes":"no"));
744
745     rc = sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig);
746
747     if (rc) {
748         unifi_warning(priv, "unifi_cfg_strict_draft_n: Get unifi_SMEConfigValue failed.\n");
749         return -EFAULT;
750     }
751
752     deviceConfig.enableStrictDraftN = strict_draft_n;
753
754     rc = sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig);
755     if (rc) {
756         unifi_warning(priv, "unifi_cfg_strict_draft_n: Set unifi_SMEConfigValue failed.\n");
757         rc = -EFAULT;
758     }
759
760     return rc;
761 }
762
763
764 int unifi_cfg_enable_okc(unifi_priv_t *priv, unsigned char *arg)
765 {
766     u8 enable_okc;
767     u8 *enable_okc_params;
768     int rc;
769
770     CsrWifiSmeStaConfig staConfig;
771     CsrWifiSmeDeviceConfig deviceConfig;
772
773     enable_okc_params = (u8*)(((unifi_cfg_command_t*)arg) + 1);
774     if (get_user(enable_okc, (u8*)enable_okc_params)) {
775         unifi_error(priv, "unifi_cfg_enable_okc: Failed to get the argument\n");
776         return -EFAULT;
777     }
778
779     unifi_trace(priv, UDBG4, "enable_okc: = %s\n", ((enable_okc) ? "yes":"no"));
780
781     rc = sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig);
782     if (rc) {
783         unifi_warning(priv, "unifi_cfg_enable_okc: Get unifi_SMEConfigValue failed.\n");
784         return -EFAULT;
785     }
786
787     staConfig.enableOpportunisticKeyCaching = enable_okc;
788
789     rc = sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig);
790     if (rc) {
791         unifi_warning(priv, "unifi_cfg_enable_okc: Set unifi_SMEConfigValue failed.\n");
792         rc = -EFAULT;
793     }
794
795     return rc;
796 }
797
798
799 int unifi_cfg_get_info(unifi_priv_t *priv, unsigned char *arg)
800 {
801     unifi_cfg_get_t get_cmd;
802     char inst_name[IFNAMSIZ];
803     int rc;
804
805     if (get_user(get_cmd, (unifi_cfg_get_t*)(((unifi_cfg_command_t*)arg) + 1))) {
806         unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
807         return -EFAULT;
808     }
809
810     switch (get_cmd) {
811         case UNIFI_CFG_GET_COEX:
812             {
813                 CsrWifiSmeCoexInfo coexInfo;
814                 /* Get the coex info from the SME */
815                 rc = sme_mgt_coex_info_get(priv, &coexInfo);
816                 if (rc) {
817                     unifi_error(priv, "UNIFI_CFG: Get unifi_CoexInfoValue failed.\n");
818                     return rc;
819                 }
820
821                 /* Copy the info to the out buffer */
822                 if (copy_to_user((void*)arg,
823                             &coexInfo,
824                             sizeof(CsrWifiSmeCoexInfo))) {
825                     unifi_error(priv, "UNIFI_CFG: Failed to copy the coex info\n");
826                     return -EFAULT;
827                 }
828                 break;
829             }
830         case UNIFI_CFG_GET_POWER_MODE:
831             {
832                 CsrWifiSmePowerConfig powerConfig;
833                 rc = sme_mgt_power_config_get(priv, &powerConfig);
834                 if (rc) {
835                     unifi_error(priv, "UNIFI_CFG: Get unifi_PowerConfigValue failed.\n");
836                     return rc;
837                 }
838
839                 /* Copy the info to the out buffer */
840                 if (copy_to_user((void*)arg,
841                             &powerConfig.powerSaveLevel,
842                             sizeof(CsrWifiSmePowerSaveLevel))) {
843                     unifi_error(priv, "UNIFI_CFG: Failed to copy the power save info\n");
844                     return -EFAULT;
845                 }
846                 break;
847             }
848         case UNIFI_CFG_GET_POWER_SUPPLY:
849             {
850                 CsrWifiSmeHostConfig hostConfig;
851                 rc = sme_mgt_host_config_get(priv, &hostConfig);
852                 if (rc) {
853                     unifi_error(priv, "UNIFI_CFG: Get unifi_HostConfigValue failed.\n");
854                     return rc;
855                 }
856
857                 /* Copy the info to the out buffer */
858                 if (copy_to_user((void*)arg,
859                             &hostConfig.powerMode,
860                             sizeof(CsrWifiSmeHostPowerMode))) {
861                     unifi_error(priv, "UNIFI_CFG: Failed to copy the host power mode\n");
862                     return -EFAULT;
863                 }
864                 break;
865             }
866         case UNIFI_CFG_GET_VERSIONS:
867             break;
868         case UNIFI_CFG_GET_INSTANCE:
869             {
870                 u16 InterfaceId=0;
871                 uf_net_get_name(priv->netdev[InterfaceId], &inst_name[0], sizeof(inst_name));
872
873                 /* Copy the info to the out buffer */
874                 if (copy_to_user((void*)arg,
875                             &inst_name[0],
876                             sizeof(inst_name))) {
877                     unifi_error(priv, "UNIFI_CFG: Failed to copy the instance name\n");
878                     return -EFAULT;
879                 }
880             }
881             break;
882
883         case UNIFI_CFG_GET_AP_CONFIG:
884             {
885 #ifdef CSR_SUPPORT_WEXT_AP
886                 uf_cfg_ap_config_t cfg_ap_config;
887                 cfg_ap_config.channel = priv->ap_config.channel;
888                 cfg_ap_config.beaconInterval = priv->ap_mac_config.beaconInterval;
889                 cfg_ap_config.wmmEnabled = priv->ap_mac_config.wmmEnabled;
890                 cfg_ap_config.dtimPeriod = priv->ap_mac_config.dtimPeriod;
891                 cfg_ap_config.phySupportedBitmap = priv->ap_mac_config.phySupportedBitmap;
892                 if (copy_to_user((void*)arg,
893                             &cfg_ap_config,
894                             sizeof(uf_cfg_ap_config_t))) {
895                     unifi_error(priv, "UNIFI_CFG: Failed to copy the AP configuration\n");
896                     return -EFAULT;
897                 }
898 #else
899                    return -EPERM;
900 #endif
901             }
902             break;
903
904
905         default:
906             unifi_error(priv, "unifi_cfg_get_info: Unknown value.\n");
907             return -EINVAL;
908     }
909
910     return 0;
911 }
912 #ifdef CSR_SUPPORT_WEXT_AP
913 int
914  uf_configure_supported_rates(u8 * supportedRates, u8 phySupportedBitmap)
915 {
916     int i=0;
917     u8 b=FALSE, g = FALSE, n = FALSE;
918     b = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_B;
919     n = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_N;
920     g = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_G;
921     if(b || g) {
922         supportedRates[i++]=0x82;
923         supportedRates[i++]=0x84;
924         supportedRates[i++]=0x8b;
925         supportedRates[i++]=0x96;
926     } else if(n) {
927         /* For some strange reasons WiFi stack needs both b and g rates*/
928         supportedRates[i++]=0x02;
929         supportedRates[i++]=0x04;
930         supportedRates[i++]=0x0b;
931         supportedRates[i++]=0x16;
932         supportedRates[i++]=0x0c;
933         supportedRates[i++]=0x12;
934         supportedRates[i++]=0x18;
935         supportedRates[i++]=0x24;
936         supportedRates[i++]=0x30;
937         supportedRates[i++]=0x48;
938         supportedRates[i++]=0x60;
939         supportedRates[i++]=0x6c;
940     }
941     if(g) {
942         if(!b) {
943             supportedRates[i++]=0x8c;
944             supportedRates[i++]=0x98;
945             supportedRates[i++]=0xb0;
946         } else {
947             supportedRates[i++]=0x0c;
948             supportedRates[i++]=0x18;
949             supportedRates[i++]=0x30;
950         }
951         supportedRates[i++]=0x48;
952         supportedRates[i++]=0x12;
953         supportedRates[i++]=0x24;
954         supportedRates[i++]=0x60;
955         supportedRates[i++]=0x6c;
956     }
957     return i;
958 }
959 int unifi_cfg_set_ap_config(unifi_priv_t * priv,unsigned char* arg)
960 {
961     uf_cfg_ap_config_t cfg_ap_config;
962     char *buffer;
963
964     buffer = ((unsigned char*)arg) + sizeof(unifi_cfg_command_t) + sizeof(unsigned int);
965     if (copy_from_user(&cfg_ap_config, (void*)buffer,
966                 sizeof(uf_cfg_ap_config_t))) {
967         unifi_error(priv, "UNIFI_CFG: Failed to get the ap config struct\n");
968         return -EFAULT;
969     }
970     priv->ap_config.channel = cfg_ap_config.channel;
971     priv->ap_mac_config.dtimPeriod = cfg_ap_config.dtimPeriod;
972     priv->ap_mac_config.beaconInterval = cfg_ap_config.beaconInterval;
973     priv->group_sec_config.apGroupkeyTimeout = cfg_ap_config.groupkeyTimeout;
974     priv->group_sec_config.apStrictGtkRekey = cfg_ap_config.strictGtkRekeyEnabled;
975     priv->group_sec_config.apGmkTimeout = cfg_ap_config.gmkTimeout;
976     priv->group_sec_config.apResponseTimeout = cfg_ap_config.responseTimeout;
977     priv->group_sec_config.apRetransLimit = cfg_ap_config.retransLimit;
978
979     priv->ap_mac_config.shortSlotTimeEnabled = cfg_ap_config.shortSlotTimeEnabled;
980     priv->ap_mac_config.ctsProtectionType=cfg_ap_config.ctsProtectionType;
981
982     priv->ap_mac_config.wmmEnabled = cfg_ap_config.wmmEnabled;
983
984     priv->ap_mac_config.apHtParams.rxStbc=cfg_ap_config.rxStbc;
985     priv->ap_mac_config.apHtParams.rifsModeAllowed=cfg_ap_config.rifsModeAllowed;
986
987     priv->ap_mac_config.phySupportedBitmap = cfg_ap_config.phySupportedBitmap;
988     priv->ap_mac_config.maxListenInterval=cfg_ap_config.maxListenInterval;
989
990     priv->ap_mac_config.supportedRatesCount=     uf_configure_supported_rates(priv->ap_mac_config.supportedRates,priv->ap_mac_config.phySupportedBitmap);
991
992     return 0;
993 }
994
995 #endif
996 #ifdef CSR_SUPPORT_WEXT
997
998     void
999 uf_sme_config_wq(struct work_struct *work)
1000 {
1001     CsrWifiSmeStaConfig  staConfig;
1002     CsrWifiSmeDeviceConfig  deviceConfig;
1003     unifi_priv_t *priv = container_of(work, unifi_priv_t, sme_config_task);
1004
1005     /* Register to receive indications from the SME */
1006     CsrWifiSmeEventMaskSetReqSend(0,
1007             CSR_WIFI_SME_INDICATIONS_WIFIOFF | CSR_WIFI_SME_INDICATIONS_CONNECTIONQUALITY |
1008             CSR_WIFI_SME_INDICATIONS_MEDIASTATUS | CSR_WIFI_SME_INDICATIONS_MICFAILURE);
1009
1010     if (sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig)) {
1011         unifi_warning(priv, "uf_sme_config_wq: Get unifi_SMEConfigValue failed.\n");
1012         return;
1013     }
1014
1015     if (priv->if_index == CSR_INDEX_5G) {
1016         staConfig.ifIndex = CSR_WIFI_SME_RADIO_IF_GHZ_5_0;
1017     } else {
1018         staConfig.ifIndex = CSR_WIFI_SME_RADIO_IF_GHZ_2_4;
1019     }
1020
1021     deviceConfig.trustLevel = (CsrWifiSme80211dTrustLevel)tl_80211d;
1022     if (sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig)) {
1023         unifi_warning(priv,
1024                 "SME config for 802.11d Trust Level and Radio Band failed.\n");
1025         return;
1026     }
1027
1028 } /* uf_sme_config_wq() */
1029
1030 #endif /* CSR_SUPPORT_WEXT */
1031
1032
1033 /*
1034  * ---------------------------------------------------------------------------
1035  *  uf_ta_ind_wq
1036  *
1037  *      Deferred work queue function to send Traffic Analysis protocols
1038  *      indications to the SME.
1039  *      These are done in a deferred work queue for two reasons:
1040  *       - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context
1041  *       - we want to load the main driver data path as lightly as possible
1042  *
1043  *      The TA classifications already come from a workqueue.
1044  *
1045  *  Arguments:
1046  *      work    Pointer to work queue item.
1047  *
1048  *  Returns:
1049  *      None.
1050  * ---------------------------------------------------------------------------
1051  */
1052     void
1053 uf_ta_ind_wq(struct work_struct *work)
1054 {
1055     struct ta_ind *ind = container_of(work, struct ta_ind, task);
1056     unifi_priv_t *priv = container_of(ind, unifi_priv_t, ta_ind_work);
1057     u16 interfaceTag = 0;
1058
1059
1060     CsrWifiRouterCtrlTrafficProtocolIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,
1061             interfaceTag,
1062             ind->packet_type,
1063             ind->direction,
1064             ind->src_addr);
1065     ind->in_use = 0;
1066
1067 } /* uf_ta_ind_wq() */
1068
1069
1070 /*
1071  * ---------------------------------------------------------------------------
1072  *  uf_ta_sample_ind_wq
1073  *
1074  *      Deferred work queue function to send Traffic Analysis sample
1075  *      indications to the SME.
1076  *      These are done in a deferred work queue for two reasons:
1077  *       - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context
1078  *       - we want to load the main driver data path as lightly as possible
1079  *
1080  *      The TA classifications already come from a workqueue.
1081  *
1082  *  Arguments:
1083  *      work    Pointer to work queue item.
1084  *
1085  *  Returns:
1086  *      None.
1087  * ---------------------------------------------------------------------------
1088  */
1089     void
1090 uf_ta_sample_ind_wq(struct work_struct *work)
1091 {
1092     struct ta_sample_ind *ind = container_of(work, struct ta_sample_ind, task);
1093     unifi_priv_t *priv = container_of(ind, unifi_priv_t, ta_sample_ind_work);
1094     u16 interfaceTag = 0;
1095
1096      unifi_trace(priv, UDBG5, "rxtcp %d txtcp %d rxudp %d txudp %d prio %d\n",
1097         priv->rxTcpThroughput,
1098         priv->txTcpThroughput,
1099         priv->rxUdpThroughput,
1100         priv->txUdpThroughput,
1101         priv->bh_thread.prio);
1102
1103     if(priv->rxTcpThroughput > 1000)
1104     {
1105         if (bh_priority == -1 && priv->bh_thread.prio != 1)
1106         {
1107             struct sched_param param;
1108             priv->bh_thread.prio = 1;
1109             unifi_trace(priv, UDBG1, "%s new thread (RT) priority = %d\n",
1110                         priv->bh_thread.name, priv->bh_thread.prio);
1111             param.sched_priority = priv->bh_thread.prio;
1112             sched_setscheduler(priv->bh_thread.thread_task, SCHED_FIFO, &param);
1113         }
1114     } else
1115     {
1116         if (bh_priority == -1 && priv->bh_thread.prio != DEFAULT_PRIO)
1117         {
1118             struct sched_param param;
1119             param.sched_priority = 0;
1120             sched_setscheduler(priv->bh_thread.thread_task, SCHED_NORMAL, &param);
1121             priv->bh_thread.prio = DEFAULT_PRIO;
1122             unifi_trace(priv, UDBG1, "%s new thread priority = %d\n",
1123                         priv->bh_thread.name, priv->bh_thread.prio);
1124             set_user_nice(priv->bh_thread.thread_task, PRIO_TO_NICE(priv->bh_thread.prio));
1125         }
1126     }
1127
1128     CsrWifiRouterCtrlTrafficSampleIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, interfaceTag, ind->stats);
1129
1130     ind->in_use = 0;
1131
1132 } /* uf_ta_sample_ind_wq() */
1133
1134
1135 /*
1136  * ---------------------------------------------------------------------------
1137  *  uf_send_m4_ready_wq
1138  *
1139  *      Deferred work queue function to send M4 ReadyToSend inds to the SME.
1140  *      These are done in a deferred work queue for two reasons:
1141  *       - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context
1142  *       - we want to load the main driver data path as lightly as possible
1143  *
1144  *  Arguments:
1145  *      work    Pointer to work queue item.
1146  *
1147  *  Returns:
1148  *      None.
1149  * ---------------------------------------------------------------------------
1150  */
1151 void
1152 uf_send_m4_ready_wq(struct work_struct *work)
1153 {
1154     netInterface_priv_t *InterfacePriv = container_of(work, netInterface_priv_t, send_m4_ready_task);
1155     u16 iface = InterfacePriv->InterfaceTag;
1156     unifi_priv_t *priv = InterfacePriv->privPtr;
1157     CSR_MA_PACKET_REQUEST *req = &InterfacePriv->m4_signal.u.MaPacketRequest;
1158     CsrWifiMacAddress peer;
1159     unsigned long flags;
1160
1161     func_enter();
1162
1163     /* The peer address was stored in the signal */
1164     spin_lock_irqsave(&priv->m4_lock, flags);
1165     memcpy(peer.a, req->Ra.x, sizeof(peer.a));
1166     spin_unlock_irqrestore(&priv->m4_lock, flags);
1167
1168     /* Send a signal to SME */
1169     CsrWifiRouterCtrlM4ReadyToSendIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, iface, peer);
1170
1171         unifi_trace(priv, UDBG1, "M4ReadyToSendInd sent for peer %pMF\n",
1172                 peer.a);
1173
1174     func_exit();
1175
1176 } /* uf_send_m4_ready_wq() */
1177
1178 #if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION))
1179 /*
1180  * ---------------------------------------------------------------------------
1181  *  uf_send_pkt_to_encrypt
1182  *
1183  *      Deferred work queue function to send the WAPI data pkts to SME when unicast KeyId = 1
1184  *      These are done in a deferred work queue for two reasons:
1185  *       - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context
1186  *       - we want to load the main driver data path as lightly as possible
1187  *
1188  *  Arguments:
1189  *      work    Pointer to work queue item.
1190  *
1191  *  Returns:
1192  *      None.
1193  * ---------------------------------------------------------------------------
1194  */
1195 void uf_send_pkt_to_encrypt(struct work_struct *work)
1196 {
1197     netInterface_priv_t *interfacePriv = container_of(work, netInterface_priv_t, send_pkt_to_encrypt);
1198     u16 interfaceTag = interfacePriv->InterfaceTag;
1199     unifi_priv_t *priv = interfacePriv->privPtr;
1200
1201     u32 pktBulkDataLength;
1202     u8 *pktBulkData;
1203     unsigned long flags;
1204
1205     if (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA) {
1206
1207         func_enter();
1208
1209         pktBulkDataLength = interfacePriv->wapi_unicast_bulk_data.data_length;
1210
1211         if (pktBulkDataLength > 0) {
1212                     pktBulkData = (u8 *)CsrPmemAlloc(pktBulkDataLength);
1213                     memset(pktBulkData, 0, pktBulkDataLength);
1214             } else {
1215                     unifi_error(priv, "uf_send_pkt_to_encrypt() : invalid buffer\n");
1216                     return;
1217             }
1218
1219         spin_lock_irqsave(&priv->wapi_lock, flags);
1220         /* Copy over the MA PKT REQ bulk data */
1221         memcpy(pktBulkData, (u8*)interfacePriv->wapi_unicast_bulk_data.os_data_ptr, pktBulkDataLength);
1222         /* Free any bulk data buffers allocated for the WAPI Data pkt */
1223         unifi_net_data_free(priv, &interfacePriv->wapi_unicast_bulk_data);
1224         interfacePriv->wapi_unicast_bulk_data.net_buf_length = 0;
1225         interfacePriv->wapi_unicast_bulk_data.data_length = 0;
1226         interfacePriv->wapi_unicast_bulk_data.os_data_ptr = interfacePriv->wapi_unicast_bulk_data.os_net_buf_ptr = NULL;
1227         spin_unlock_irqrestore(&priv->wapi_lock, flags);
1228
1229         CsrWifiRouterCtrlWapiUnicastTxEncryptIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, interfaceTag, pktBulkDataLength, pktBulkData);
1230         unifi_trace(priv, UDBG1, "WapiUnicastTxEncryptInd sent to SME\n");
1231
1232         CsrPmemFree(pktBulkData); /* Would have been copied over by the SME Handler */
1233
1234         func_exit();
1235     } else {
1236             unifi_warning(priv, "uf_send_pkt_to_encrypt() is NOT applicable for interface mode - %d\n",interfacePriv->interfaceMode);
1237     }
1238 }/* uf_send_pkt_to_encrypt() */
1239 #endif