]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - drivers/net/wireless/bcmdhd/dhd_linux.c
8eb1bb9bbf7d27045292826845b0c504428d295e
[sojka/nv-tegra/linux-3.10.git] / drivers / net / wireless / bcmdhd / dhd_linux.c
1 /*
2  * Broadcom Dongle Host Driver (DHD), Linux-specific network interface
3  * Basically selected code segments from usb-cdc.c and usb-rndis.c
4  *
5  * Copyright (C) 1999-2015, Broadcom Corporation
6  * 
7  * Portions contributed by Nvidia
8  * Copyright (C) 2015 NVIDIA Corporation. All rights reserved.
9  *
10  *      Unless you and Broadcom execute a separate written software license
11  * agreement governing use of this software, this software is licensed to you
12  * under the terms of the GNU General Public License version 2 (the "GPL"),
13  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
14  * following added to such license:
15  * 
16  *      As a special exception, the copyright holders of this software give you
17  * permission to link this software with independent modules, and to copy and
18  * distribute the resulting executable under terms of your choice, provided that
19  * you also meet, for each linked independent module, the terms and conditions of
20  * the license of that module.  An independent module is a module which is not
21  * derived from this software.  The special exception does not apply to any
22  * modifications of the software.
23  * 
24  *      Notwithstanding the above, under no circumstances may you combine this
25  * software in any way with any other Broadcom software provided under a license
26  * other than the GPL, without Broadcom's express prior written consent.
27  *
28  * $Id: dhd_linux.c 531927 2015-02-04 14:00:07Z $
29  */
30
31 #include <typedefs.h>
32 #include "dynamic.h"
33 #include <linuxver.h>
34 #include <osl.h>
35 #ifdef SHOW_LOGTRACE
36 #include <linux/syscalls.h>
37 #include <event_log.h>
38 #endif /* SHOW_LOGTRACE */
39
40
41 #include <linux/init.h>
42 #include <linux/kernel.h>
43 #include <linux/slab.h>
44 #include <linux/skbuff.h>
45 #include <linux/netdevice.h>
46 #include <linux/inetdevice.h>
47 #include <linux/rtnetlink.h>
48 #include <linux/etherdevice.h>
49 #include <linux/random.h>
50 #include <linux/spinlock.h>
51 #include <linux/ethtool.h>
52 #include <linux/fcntl.h>
53 #include <linux/fs.h>
54 #include <linux/ip.h>
55 #include <linux/reboot.h>
56 #include <linux/notifier.h>
57 #include <net/addrconf.h>
58 #ifdef ENABLE_ADAPTIVE_SCHED
59 #include <linux/cpufreq.h>
60 #endif /* ENABLE_ADAPTIVE_SCHED */
61
62 #include <asm/uaccess.h>
63 #include <asm/unaligned.h>
64
65 #include <epivers.h>
66 #include <bcmutils.h>
67 #include <bcmendian.h>
68 #include <bcmdevs.h>
69
70 #include <proto/ethernet.h>
71 #include <proto/bcmevent.h>
72 #include <proto/vlan.h>
73 #ifdef DHD_L2_FILTER
74 #include <proto/bcmicmp.h>
75 #endif
76 #include <proto/802.3.h>
77
78 #include <dngl_stats.h>
79 #include <dhd_linux_wq.h>
80 #include <dhd.h>
81 #include <dhd_linux.h>
82 #ifdef PCIE_FULL_DONGLE
83 #include <dhd_flowring.h>
84 #endif
85 #include <dhd_bus.h>
86 #include <dhd_proto.h>
87 #include <dhd_dbg.h>
88 /* Used for the bottom half, so same priority as the other irqthread */
89 #define DHD_DEFAULT_RT_PRIORITY (MAX_USER_RT_PRIO / 2)
90 #ifdef CONFIG_HAS_WAKELOCK
91 #include <linux/wakelock.h>
92 #endif
93 #ifdef WL_CFG80211
94 #include <wl_cfg80211.h>
95 #endif
96 #ifdef P2PONEINT
97 #include <wl_cfgp2p.h>
98 #endif
99 #ifdef PNO_SUPPORT
100 #include <dhd_pno.h>
101 #endif
102
103 #ifdef CONFIG_COMPAT
104 #include <linux/compat.h>
105 #endif
106
107 #ifdef DHD_WMF
108 #include <dhd_wmf_linux.h>
109 #endif /* DHD_WMF */
110
111 #ifdef DHDTCPACK_SUPPRESS
112 #include <dhd_ip.h>
113 #endif /* DHDTCPACK_SUPPRESS */
114
115 #ifdef CONFIG_BCMDHD_CUSTOM_SYSFS_TEGRA
116 #include "dhd_custom_sysfs_tegra.h"
117 #include "dhd_custom_sysfs_tegra_scan.h"
118
119 #define RX_CAPTURE(skb)\
120         {\
121                 tegra_sysfs_histogram_tcpdump_rx(skb, __func__, __LINE__);\
122         }\
123
124 #define DPC_CAPTURE(void)\
125         {\
126                 tegra_sysfs_dpc_pkt();\
127         } \
128
129 #else
130
131 #define RX_CAPTURE(skb)
132
133 #define DPC_CAPTURE(void)
134
135 #endif
136
137 #ifdef WLMEDIA_HTSF
138 #include <linux/time.h>
139 #include <htsf.h>
140
141 #define HTSF_MINLEN 200    /* min. packet length to timestamp */
142 #define HTSF_BUS_DELAY 150 /* assume a fix propagation in us  */
143 #define TSMAX  1000        /* max no. of timing record kept   */
144 #define NUMBIN 34
145
146 static uint32 tsidx = 0;
147 static uint32 htsf_seqnum = 0;
148 uint32 tsfsync;
149 struct timeval tsync;
150 static uint32 tsport = 5010;
151
152 typedef struct histo_ {
153         uint32 bin[NUMBIN];
154 } histo_t;
155
156 #if !ISPOWEROF2(DHD_SDALIGN)
157 #error DHD_SDALIGN is not a power of 2!
158 #endif
159
160 static histo_t vi_d1, vi_d2, vi_d3, vi_d4;
161 #endif /* WLMEDIA_HTSF */
162
163
164
165 #if defined(SOFTAP)
166 extern bool ap_cfg_running;
167 extern bool ap_fw_loaded;
168 #endif
169
170
171 #ifdef ENABLE_ADAPTIVE_SCHED
172 #define DEFAULT_CPUFREQ_THRESH          1000000 /* threshold frequency : 1000000 = 1GHz */
173 #ifndef CUSTOM_CPUFREQ_THRESH
174 #define CUSTOM_CPUFREQ_THRESH   DEFAULT_CPUFREQ_THRESH
175 #endif /* CUSTOM_CPUFREQ_THRESH */
176 #endif /* ENABLE_ADAPTIVE_SCHED */
177
178 /* enable HOSTIP cache update from the host side when an eth0:N is up */
179 #define AOE_IP_ALIAS_SUPPORT 1
180
181 #ifdef BCM_FD_AGGR
182 #include <bcm_rpc.h>
183 #include <bcm_rpc_tp.h>
184 #endif
185 #ifdef PROP_TXSTATUS
186 #include <wlfc_proto.h>
187 #include <dhd_wlfc.h>
188 #endif
189
190 #include <wl_android.h>
191
192 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
193 #include <sdaudio.h>
194 #endif /* CUSTOMER_HW20 && WLANAUDIO */
195
196 /* Maximum STA per radio */
197 #define DHD_MAX_STA     32
198
199
200 const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 };
201 const uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
202 #define WME_PRIO2AC(prio)  wme_fifo2ac[prio2fifo[(prio)]]
203
204 #ifdef ARP_OFFLOAD_SUPPORT
205 void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx);
206 static int dhd_inetaddr_notifier_call(struct notifier_block *this,
207         unsigned long event, void *ptr);
208 static struct notifier_block dhd_inetaddr_notifier = {
209         .notifier_call = dhd_inetaddr_notifier_call
210 };
211 /* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
212  * created in kernel notifier link list (with 'next' pointing to itself)
213  */
214 static bool dhd_inetaddr_notifier_registered = FALSE;
215 #endif /* ARP_OFFLOAD_SUPPORT */
216
217 #ifdef CONFIG_IPV6
218 static int dhd_inet6addr_notifier_call(struct notifier_block *this,
219         unsigned long event, void *ptr);
220 static struct notifier_block dhd_inet6addr_notifier = {
221         .notifier_call = dhd_inet6addr_notifier_call
222 };
223 /* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
224  * created in kernel notifier link list (with 'next' pointing to itself)
225  */
226 static bool dhd_inet6addr_notifier_registered = FALSE;
227 #endif
228
229 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
230 #include <linux/suspend.h>
231 volatile bool dhd_mmc_suspend = FALSE;
232 DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
233 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
234
235 #if defined(OOB_INTR_ONLY)
236 extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable);
237 #endif 
238 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
239 static void dhd_hang_process(void *dhd_info, void *event_data, u8 event);
240 #endif 
241 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
242 MODULE_LICENSE("GPL and additional rights");
243 #endif /* LinuxVer */
244
245 #include <dhd_bus.h>
246
247 #ifdef BCM_FD_AGGR
248 #define DBUS_RX_BUFFER_SIZE_DHD(net)    (BCM_RPC_TP_DNGL_AGG_MAX_BYTE)
249 #else
250 #ifndef PROP_TXSTATUS
251 #define DBUS_RX_BUFFER_SIZE_DHD(net)    (net->mtu + net->hard_header_len + dhd->pub.hdrlen)
252 #else
253 #define DBUS_RX_BUFFER_SIZE_DHD(net)    (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128)
254 #endif
255 #endif /* BCM_FD_AGGR */
256
257 #ifdef PROP_TXSTATUS
258 extern bool dhd_wlfc_skip_fc(void);
259 extern void dhd_wlfc_plat_init(void *dhd);
260 extern void dhd_wlfc_plat_deinit(void *dhd);
261 #endif /* PROP_TXSTATUS */
262 #ifdef BCMSDIO
263 extern int dhd_slpauto_config(dhd_pub_t *dhd, s32 val);
264 #endif
265
266 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15)
267 const char *
268 print_tainted()
269 {
270         return "";
271 }
272 #endif  /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */
273
274 /* Linux wireless extension support */
275 #if defined(WL_WIRELESS_EXT)
276 #include <wl_iw.h>
277 extern wl_iw_extra_params_t  g_wl_iw_params;
278 #endif /* defined(WL_WIRELESS_EXT) */
279
280 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
281 #include <linux/earlysuspend.h>
282 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */
283
284 extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
285
286 #ifdef PKT_FILTER_SUPPORT
287 extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
288 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
289 extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id);
290 #endif
291
292
293 #ifdef READ_MACADDR
294 extern int dhd_read_macaddr(struct dhd_info *dhd);
295 #else
296 static inline int dhd_read_macaddr(struct dhd_info *dhd) { return 0; }
297 #endif
298 #ifdef WRITE_MACADDR
299 extern int dhd_write_macaddr(struct ether_addr *mac);
300 #else
301 static inline int dhd_write_macaddr(struct ether_addr *mac) { return 0; }
302 #endif
303
304
305
306
307 #if defined(DHD_DEBUG)
308 static void dhd_mem_dump(void *dhd_info, void *event_info, u8 event);
309 #endif /* DHD_DEBUG */
310
311 static int dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused);
312 static struct notifier_block dhd_reboot_notifier = {
313                 .notifier_call = dhd_reboot_callback,
314                 .priority = 1,
315 };
316
317
318 typedef struct dhd_if_event {
319         struct list_head        list;
320         wl_event_data_if_t      event;
321         char                    name[IFNAMSIZ+1];
322         uint8                   mac[ETHER_ADDR_LEN];
323 } dhd_if_event_t;
324
325 /* Interface control information */
326 typedef struct dhd_if {
327         struct dhd_info *info;                  /* back pointer to dhd_info */
328         /* OS/stack specifics */
329         struct net_device *net;
330         int                             idx;                    /* iface idx in dongle */
331         uint                    subunit;                /* subunit */
332         uint8                   mac_addr[ETHER_ADDR_LEN];       /* assigned MAC address */
333         bool                    set_macaddress;
334         bool                    set_multicast;
335         uint8                   bssidx;                 /* bsscfg index for the interface */
336         bool                    attached;               /* Delayed attachment when unset */
337         bool                    txflowcontrol;  /* Per interface flow control indicator */
338         char                    name[IFNAMSIZ+1]; /* linux interface name */
339         struct net_device_stats stats;
340 #ifdef DHD_WMF
341         dhd_wmf_t               wmf;            /* per bsscfg wmf setting */
342 #endif /* DHD_WMF */
343 #ifdef PCIE_FULL_DONGLE
344         struct list_head sta_list;              /* sll of associated stations */
345 #if !defined(BCM_GMAC3)
346         spinlock_t      sta_list_lock;          /* lock for manipulating sll */
347 #endif /* ! BCM_GMAC3 */
348 #endif /* PCIE_FULL_DONGLE */
349         uint32  ap_isolate;                     /* ap-isolation settings */
350 } dhd_if_t;
351
352 #ifdef WLMEDIA_HTSF
353 typedef struct {
354         uint32 low;
355         uint32 high;
356 } tsf_t;
357
358 typedef struct {
359         uint32 last_cycle;
360         uint32 last_sec;
361         uint32 last_tsf;
362         uint32 coef;     /* scaling factor */
363         uint32 coefdec1; /* first decimal  */
364         uint32 coefdec2; /* second decimal */
365 } htsf_t;
366
367 typedef struct {
368         uint32 t1;
369         uint32 t2;
370         uint32 t3;
371         uint32 t4;
372 } tstamp_t;
373
374 static tstamp_t ts[TSMAX];
375 static tstamp_t maxdelayts;
376 static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0;
377
378 #endif  /* WLMEDIA_HTSF */
379
380 struct ipv6_work_info_t {
381         uint8                   if_idx;
382         char                    ipv6_addr[16];
383         unsigned long           event;
384 };
385
386 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
387 #define MAX_WLANAUDIO_BLACKLIST 4
388
389 struct wlanaudio_blacklist {
390         bool is_blacklist;
391         uint32 cnt;
392         ulong txfail_jiffies;
393         struct ether_addr blacklist_addr;
394 };
395 #endif /* CUSTOMER_HW20 && WLANAUDIO */
396
397 #if defined(DHD_DEBUG)
398 typedef struct dhd_dump {
399         uint8 *buf;
400         int bufsize;
401 } dhd_dump_t;
402 #endif /* DHD_DEBUG */
403
404 /* When Perimeter locks are deployed, any blocking calls must be preceeded
405  * with a PERIM UNLOCK and followed by a PERIM LOCK.
406  * Examples of blocking calls are: schedule_timeout(), down_interruptible(),
407  * wait_event_timeout().
408  */
409
410 /* Local private structure (extension of pub) */
411 typedef struct dhd_info {
412 #if defined(WL_WIRELESS_EXT)
413         wl_iw_t         iw;             /* wireless extensions state (must be first) */
414 #endif /* defined(WL_WIRELESS_EXT) */
415         dhd_pub_t pub;
416         dhd_if_t *iflist[DHD_MAX_IFS]; /* for supporting multiple interfaces */
417         void  *p2p_del_ifp;
418
419         void *adapter;                  /* adapter information, interrupt, fw path etc. */
420         char fw_path[PATH_MAX];         /* path to firmware image */
421         char nv_path[PATH_MAX];         /* path to nvram vars file */
422
423         struct semaphore proto_sem;
424 #ifdef PROP_TXSTATUS
425         spinlock_t      wlfc_spinlock;
426
427 #endif /* PROP_TXSTATUS */
428 #ifdef WLMEDIA_HTSF
429         htsf_t  htsf;
430 #endif
431         wait_queue_head_t ioctl_resp_wait;
432         wait_queue_head_t d3ack_wait;
433         uint32  default_wd_interval;
434
435         struct timer_list timer;
436         bool wd_timer_valid;
437         struct tasklet_struct tasklet;
438         spinlock_t      sdlock;
439         spinlock_t      txqlock;
440         spinlock_t      dhd_lock;
441
442         struct semaphore sdsem;
443         tsk_ctl_t       thr_dpc_ctl;
444         tsk_ctl_t       thr_wdt_ctl;
445
446         tsk_ctl_t       thr_rxf_ctl;
447         spinlock_t      rxf_lock;
448         bool            rxthread_enabled;
449
450         /* Wakelocks */
451 #if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
452         struct wake_lock wl_wifi;   /* Wifi wakelock */
453         struct wake_lock wl_rxwake; /* Wifi rx wakelock */
454         struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */
455         struct wake_lock wl_wdwake; /* Wifi wd wakelock */
456 #ifdef BCMPCIE_OOB_HOST_WAKE
457         struct wake_lock wl_intrwake; /* Host wakeup wakelock */
458 #endif /* BCMPCIE_OOB_HOST_WAKE */
459 #endif /* CONFIG_HAS_WAKELOCK && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
460
461 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
462         /* net_device interface lock, prevent race conditions among net_dev interface
463          * calls and wifi_on or wifi_off
464          */
465         struct mutex dhd_net_if_mutex;
466         struct mutex dhd_suspend_mutex;
467 #endif
468         spinlock_t wakelock_spinlock;
469         uint32 wakelock_counter;
470         int wakelock_wd_counter;
471         int wakelock_rx_timeout_enable;
472         int wakelock_ctrl_timeout_enable;
473         bool waive_wakelock;
474         uint32 wakelock_before_waive;
475
476         /* Thread to issue ioctl for multicast */
477         wait_queue_head_t ctrl_wait;
478         atomic_t pend_8021x_cnt;
479         dhd_attach_states_t dhd_state;
480 #ifdef SHOW_LOGTRACE
481         dhd_event_log_t event_data;
482 #endif /* SHOW_LOGTRACE */
483
484 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
485         struct early_suspend early_suspend;
486 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
487
488 #ifdef ARP_OFFLOAD_SUPPORT
489         u32 pend_ipaddr;
490 #endif /* ARP_OFFLOAD_SUPPORT */
491 #ifdef BCM_FD_AGGR
492         void *rpc_th;
493         void *rpc_osh;
494         struct timer_list rpcth_timer;
495         bool rpcth_timer_active;
496         bool fdaggr;
497 #endif
498 #ifdef DHDTCPACK_SUPPRESS
499         spinlock_t      tcpack_lock;
500 #endif /* DHDTCPACK_SUPPRESS */
501         void                    *dhd_deferred_wq;
502 #ifdef DEBUG_CPU_FREQ
503         struct notifier_block freq_trans;
504         int __percpu *new_freq;
505 #endif
506         unsigned int unit;
507         struct notifier_block pm_notifier;
508 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
509         struct wlanaudio_blacklist wlanaudio_blist[MAX_WLANAUDIO_BLACKLIST];
510         bool is_wlanaudio_blist;
511 #endif /* CUSTOMER_HW20 && WLANAUDIO */
512 } dhd_info_t;
513
514 #define DHDIF_FWDER(dhdif)      FALSE
515
516 /* Flag to indicate if we should download firmware on driver load */
517 uint dhd_download_fw_on_driverload = TRUE;
518
519 /* Definitions to provide path to the firmware and nvram
520  * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt"
521  */
522 char firmware_path[MOD_PARAM_PATHLEN];
523 char nvram_path[MOD_PARAM_PATHLEN];
524
525 /* backup buffer for firmware and nvram path */
526 char fw_bak_path[MOD_PARAM_PATHLEN];
527 char nv_bak_path[MOD_PARAM_PATHLEN];
528
529 /* information string to keep firmware, chio, cheip version info visiable from log */
530 char info_string[MOD_PARAM_INFOLEN];
531 module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444);
532 int op_mode = 0;
533 int disable_proptx = 0;
534 module_param(op_mode, int, 0644);
535 extern int wl_control_wl_start(struct net_device *dev);
536 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC)
537 struct semaphore dhd_registration_sem;
538 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
539
540 /* deferred handlers */
541 static void dhd_ifadd_event_handler(void *handle, void *event_info, u8 event);
542 static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event);
543 static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event);
544 static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event);
545 #ifdef CONFIG_IPV6
546 static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event);
547 #endif
548
549 #ifdef WL_CFG80211
550 extern void dhd_netdev_free(struct net_device *ndev);
551 #endif /* WL_CFG80211 */
552
553 /* Error bits */
554 module_param(dhd_msg_level, int, 0);
555
556 #ifdef ARP_OFFLOAD_SUPPORT
557 /* ARP offload enable */
558 uint dhd_arp_enable = TRUE;
559 module_param(dhd_arp_enable, uint, 0);
560
561 /* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */
562
563 uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY;
564
565 module_param(dhd_arp_mode, uint, 0);
566 #endif /* ARP_OFFLOAD_SUPPORT */
567
568 /* Disable Prop tx */
569 module_param(disable_proptx, int, 0644);
570 /* load firmware and/or nvram values from the filesystem */
571 module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660);
572 module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660);
573
574 /* Watchdog interval */
575
576 /* extend watchdog expiration to 2 seconds when DPC is running */
577 #define WATCHDOG_EXTEND_INTERVAL (2000)
578
579 uint dhd_watchdog_ms = CUSTOM_DHD_WATCHDOG_MS;
580 module_param(dhd_watchdog_ms, uint, 0);
581
582 #if defined(DHD_DEBUG)
583 /* Console poll interval */
584 uint dhd_console_ms = 0;
585 module_param(dhd_console_ms, uint, 0644);
586 #endif /* defined(DHD_DEBUG) */
587
588
589 uint dhd_slpauto = TRUE;
590 module_param(dhd_slpauto, uint, 0);
591
592 #ifdef PKT_FILTER_SUPPORT
593 /* Global Pkt filter enable control */
594 uint dhd_pkt_filter_enable = TRUE;
595 module_param(dhd_pkt_filter_enable, uint, 0);
596 #endif
597
598 /* Pkt filter init setup */
599 uint dhd_pkt_filter_init = 0;
600 module_param(dhd_pkt_filter_init, uint, 0);
601
602 /* Pkt filter mode control */
603 uint dhd_master_mode = TRUE;
604 module_param(dhd_master_mode, uint, 0);
605
606 int dhd_watchdog_prio = 0;
607 module_param(dhd_watchdog_prio, int, 0);
608
609 /* DPC thread priority */
610 int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING;
611 module_param(dhd_dpc_prio, int, 0);
612
613 /* RX frame thread priority */
614 int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING;
615 module_param(dhd_rxf_prio, int, 0);
616
617 int passive_channel_skip = 0;
618 module_param(passive_channel_skip, int, (S_IRUSR|S_IWUSR));
619
620 #if !defined(BCMDHDUSB)
621 extern int dhd_dongle_ramsize;
622 module_param(dhd_dongle_ramsize, int, 0);
623 #endif /* BCMDHDUSB */
624
625 /* Keep track of number of instances */
626 static int dhd_found = 0;
627 static int instance_base = 0; /* Starting instance number */
628 module_param(instance_base, int, 0644);
629
630 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
631 dhd_info_t *dhd_global = NULL;
632 #endif /* CUSTOMER_HW20 && WLANAUDIO */
633
634
635
636 /* DHD Perimiter lock only used in router with bypass forwarding. */
637 #define DHD_PERIM_RADIO_INIT()              do { /* noop */ } while (0)
638 #define DHD_PERIM_LOCK_TRY(unit, flag)      do { /* noop */ } while (0)
639 #define DHD_PERIM_UNLOCK_TRY(unit, flag)    do { /* noop */ } while (0)
640 #define DHD_PERIM_LOCK_ALL()                do { /* noop */ } while (0)
641 #define DHD_PERIM_UNLOCK_ALL()              do { /* noop */ } while (0)
642
643 #ifdef PCIE_FULL_DONGLE
644 #if defined(BCM_GMAC3)
645 #define DHD_IF_STA_LIST_LOCK_INIT(ifp)      do { /* noop */ } while (0)
646 #define DHD_IF_STA_LIST_LOCK(ifp, flags)    ({ BCM_REFERENCE(flags); })
647 #define DHD_IF_STA_LIST_UNLOCK(ifp, flags)  ({ BCM_REFERENCE(flags); })
648 #else /* ! BCM_GMAC3 */
649 #define DHD_IF_STA_LIST_LOCK_INIT(ifp) spin_lock_init(&(ifp)->sta_list_lock)
650 #define DHD_IF_STA_LIST_LOCK(ifp, flags) \
651         spin_lock_irqsave(&(ifp)->sta_list_lock, (flags))
652 #define DHD_IF_STA_LIST_UNLOCK(ifp, flags) \
653         spin_unlock_irqrestore(&(ifp)->sta_list_lock, (flags))
654 #endif /* ! BCM_GMAC3 */
655 #endif /* PCIE_FULL_DONGLE */
656
657 /* Control fw roaming */
658 uint dhd_roam_disable = 0;
659
660 /* Control radio state */
661 uint dhd_radio_up = 1;
662
663 /* Network inteface name */
664 char iface_name[IFNAMSIZ] = {'\0'};
665 module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
666
667 /* The following are specific to the SDIO dongle */
668
669 /* IOCTL response timeout */
670 int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT;
671
672 /* Idle timeout for backplane clock */
673 int dhd_idletime = DHD_IDLETIME_TICKS;
674 module_param(dhd_idletime, int, 0);
675
676 /* Use polling */
677 uint dhd_poll = FALSE;
678 module_param(dhd_poll, uint, 0);
679
680 /* Use interrupts */
681 uint dhd_intr = TRUE;
682 module_param(dhd_intr, uint, 0);
683
684 /* SDIO Drive Strength (in milliamps) */
685 uint dhd_sdiod_drive_strength = 6;
686 module_param(dhd_sdiod_drive_strength, uint, 0);
687
688 #ifdef BCMSDIO
689 /* Tx/Rx bounds */
690 extern uint dhd_txbound;
691 extern uint dhd_rxbound;
692 module_param(dhd_txbound, uint, 0);
693 module_param(dhd_rxbound, uint, 0);
694
695 /* Deferred transmits */
696 extern uint dhd_deferred_tx;
697 module_param(dhd_deferred_tx, uint, 0);
698
699 #ifdef BCMDBGFS
700 extern void dhd_dbg_init(dhd_pub_t *dhdp);
701 extern void dhd_dbg_remove(void);
702 #endif /* BCMDBGFS */
703
704 #endif /* BCMSDIO */
705
706
707 #ifdef SDTEST
708 /* Echo packet generator (pkts/s) */
709 uint dhd_pktgen = 0;
710 module_param(dhd_pktgen, uint, 0);
711
712 /* Echo packet len (0 => sawtooth, max 2040) */
713 uint dhd_pktgen_len = 0;
714 module_param(dhd_pktgen_len, uint, 0);
715 #endif /* SDTEST */
716
717
718 extern char dhd_version[];
719
720 int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
721 static void dhd_net_if_lock_local(dhd_info_t *dhd);
722 static void dhd_net_if_unlock_local(dhd_info_t *dhd);
723 static void dhd_suspend_lock(dhd_pub_t *dhdp);
724 static void dhd_suspend_unlock(dhd_pub_t *dhdp);
725
726 #ifdef WLMEDIA_HTSF
727 void htsf_update(dhd_info_t *dhd, void *data);
728 tsf_t prev_tsf, cur_tsf;
729
730 uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx);
731 static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx);
732 static void dhd_dump_latency(void);
733 static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf);
734 static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf);
735 static void dhd_dump_htsfhisto(histo_t *his, char *s);
736 #endif /* WLMEDIA_HTSF */
737
738 /* Monitor interface */
739 int dhd_monitor_init(void *dhd_pub);
740 int dhd_monitor_uninit(void);
741
742
743 #if defined(WL_WIRELESS_EXT)
744 struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
745 #endif /* defined(WL_WIRELESS_EXT) */
746
747 static void dhd_dpc(ulong data);
748 /* forward decl */
749 extern int dhd_wait_pend8021x(struct net_device *dev);
750 void dhd_os_wd_timer_extend(void *bus, bool extend);
751
752 #ifdef TOE
753 #ifndef BDC
754 #error TOE requires BDC
755 #endif /* !BDC */
756 static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol);
757 static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol);
758 #endif /* TOE */
759
760 static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
761                              wl_event_msg_t *event_ptr, void **data_ptr);
762 #ifdef DHD_UNICAST_DHCP
763 static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
764 static int dhd_get_pkt_ip_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr,
765         int *len_ptr, uint8 *prot_ptr);
766 static int dhd_get_pkt_ether_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr,
767         int *len_ptr, uint16 *et_ptr, bool *snap_ptr);
768
769 static int dhd_convert_dhcp_broadcast_ack_to_unicast(dhd_pub_t *pub, void *pktbuf, int ifidx);
770 #endif /* DHD_UNICAST_DHCP */
771 #ifdef DHD_L2_FILTER
772 static int dhd_l2_filter_block_ping(dhd_pub_t *pub, void *pktbuf, int ifidx);
773 #endif
774 void dhd_enable_packet_filter(int value, dhd_pub_t *dhd);
775 #if defined(CONFIG_PM_SLEEP)
776 static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored)
777 {
778         int ret = NOTIFY_DONE;
779         bool suspend = FALSE;
780         dhd_info_t *dhdinfo = (dhd_info_t*)container_of(nfb, struct dhd_info, pm_notifier);
781
782         BCM_REFERENCE(dhdinfo);
783         switch (action) {
784         case PM_HIBERNATION_PREPARE:
785         case PM_SUSPEND_PREPARE:
786                 suspend = TRUE;
787                 break;
788         case PM_POST_HIBERNATION:
789         case PM_POST_SUSPEND:
790                 suspend = FALSE;
791                 break;
792         }
793
794         /* FIXME: dhd_wlfc_suspend acquires wd wakelock and calling
795            in this function is breaking LP0. So moving this function
796            call to dhd_set_suspend. Need to enable it after fixing
797            wd wakelock issue. */
798 #if 0
799 #if defined(SUPPORT_P2P_GO_PS)
800 #ifdef PROP_TXSTATUS
801         if (suspend) {
802                 DHD_OS_WAKE_LOCK_WAIVE(&dhdinfo->pub);
803                 dhd_wlfc_suspend(&dhdinfo->pub);
804                 DHD_OS_WAKE_LOCK_RESTORE(&dhdinfo->pub);
805         } else
806                 dhd_wlfc_resume(&dhdinfo->pub);
807 #endif
808 #endif /* defined(SUPPORT_P2P_GO_PS) */
809 #endif
810
811 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \
812         KERNEL_VERSION(2, 6, 39))
813         dhd_mmc_suspend = suspend;
814         smp_mb();
815 #endif
816
817         return ret;
818 }
819
820 static struct notifier_block dhd_pm_notifier = {
821         .notifier_call = dhd_pm_callback,
822         .priority = 10
823 };
824 /* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
825  * created in kernel notifier link list (with 'next' pointing to itself)
826  */
827 static bool dhd_pm_notifier_registered = FALSE;
828
829 extern int register_pm_notifier(struct notifier_block *nb);
830 extern int unregister_pm_notifier(struct notifier_block *nb);
831 #endif /* CONFIG_PM_SLEEP */
832
833 /* Request scheduling of the bus rx frame */
834 static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb);
835 static void dhd_os_rxflock(dhd_pub_t *pub);
836 static void dhd_os_rxfunlock(dhd_pub_t *pub);
837
838 /** priv_link is the link between netdev and the dhdif and dhd_info structs. */
839 typedef struct dhd_dev_priv {
840         dhd_info_t * dhd; /* cached pointer to dhd_info in netdevice priv */
841         dhd_if_t   * ifp; /* cached pointer to dhd_if in netdevice priv */
842         int          ifidx; /* interface index */
843 } dhd_dev_priv_t;
844
845 #define DHD_DEV_PRIV_SIZE       (sizeof(dhd_dev_priv_t))
846 #define DHD_DEV_PRIV(dev)       ((dhd_dev_priv_t *)DEV_PRIV(dev))
847 #define DHD_DEV_INFO(dev)       (((dhd_dev_priv_t *)DEV_PRIV(dev))->dhd)
848 #define DHD_DEV_IFP(dev)        (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifp)
849 #define DHD_DEV_IFIDX(dev)      (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifidx)
850
851 /** Clear the dhd net_device's private structure. */
852 static inline void
853 dhd_dev_priv_clear(struct net_device * dev)
854 {
855         dhd_dev_priv_t * dev_priv;
856         ASSERT(dev != (struct net_device *)NULL);
857         dev_priv = DHD_DEV_PRIV(dev);
858         dev_priv->dhd = (dhd_info_t *)NULL;
859         dev_priv->ifp = (dhd_if_t *)NULL;
860         dev_priv->ifidx = DHD_BAD_IF;
861 }
862
863 /** Setup the dhd net_device's private structure. */
864 static inline void
865 dhd_dev_priv_save(struct net_device * dev, dhd_info_t * dhd, dhd_if_t * ifp,
866                   int ifidx)
867 {
868         dhd_dev_priv_t * dev_priv;
869         ASSERT(dev != (struct net_device *)NULL);
870         dev_priv = DHD_DEV_PRIV(dev);
871         dev_priv->dhd = dhd;
872         dev_priv->ifp = ifp;
873         dev_priv->ifidx = ifidx;
874 }
875
876 #ifdef PCIE_FULL_DONGLE
877
878 /** Dummy objects are defined with state representing bad|down.
879  * Performance gains from reducing branch conditionals, instruction parallelism,
880  * dual issue, reducing load shadows, avail of larger pipelines.
881  * Use DHD_XXX_NULL instead of (dhd_xxx_t *)NULL, whenever an object pointer
882  * is accessed via the dhd_sta_t.
883  */
884
885 /* Dummy dhd_info object */
886 dhd_info_t dhd_info_null = {
887 #if defined(BCM_GMAC3)
888         .fwdh = FWDER_NULL,
889 #endif
890         .pub = {
891                  .info = &dhd_info_null,
892 #ifdef DHDTCPACK_SUPPRESS
893                  .tcpack_sup_mode = TCPACK_SUP_REPLACE,
894 #endif /* DHDTCPACK_SUPPRESS */
895                  .up = FALSE,
896                  .busstate = DHD_BUS_DOWN
897         }
898 };
899 #define DHD_INFO_NULL (&dhd_info_null)
900 #define DHD_PUB_NULL  (&dhd_info_null.pub)
901
902 /* Dummy netdevice object */
903 struct net_device dhd_net_dev_null = {
904         .reg_state = NETREG_UNREGISTERED
905 };
906 #define DHD_NET_DEV_NULL (&dhd_net_dev_null)
907
908 /* Dummy dhd_if object */
909 dhd_if_t dhd_if_null = {
910 #if defined(BCM_GMAC3)
911         .fwdh = FWDER_NULL,
912 #endif
913 #ifdef WMF
914         .wmf = { .wmf_enable = TRUE },
915 #endif
916         .info = DHD_INFO_NULL,
917         .net = DHD_NET_DEV_NULL,
918         .idx = DHD_BAD_IF
919 };
920 #define DHD_IF_NULL  (&dhd_if_null)
921
922 #define DHD_STA_NULL ((dhd_sta_t *)NULL)
923
924 /** Interface STA list management. */
925
926 /** Fetch the dhd_if object, given the interface index in the dhd. */
927 static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx);
928
929 /** Alloc/Free a dhd_sta object from the dhd instances' sta_pool. */
930 static void dhd_sta_free(dhd_pub_t *pub, dhd_sta_t *sta);
931 static dhd_sta_t * dhd_sta_alloc(dhd_pub_t * dhdp);
932
933 /* Delete a dhd_sta or flush all dhd_sta in an interface's sta_list. */
934 static void dhd_if_del_sta_list(dhd_if_t * ifp);
935 static void     dhd_if_flush_sta(dhd_if_t * ifp);
936
937 /* Construct/Destruct a sta pool. */
938 static int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta);
939 static void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta);
940 static void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta);
941
942
943 /* Return interface pointer */
944 static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx)
945 {
946         ASSERT(ifidx < DHD_MAX_IFS);
947
948         if (ifidx >= DHD_MAX_IFS)
949                 return NULL;
950
951         return dhdp->info->iflist[ifidx];
952 }
953
954 /** Reset a dhd_sta object and free into the dhd pool. */
955 static void
956 dhd_sta_free(dhd_pub_t * dhdp, dhd_sta_t * sta)
957 {
958         int prio;
959
960         ASSERT((sta != DHD_STA_NULL) && (sta->idx != ID16_INVALID));
961
962         ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL));
963         id16_map_free(dhdp->staid_allocator, sta->idx);
964         for (prio = 0; prio < (int)NUMPRIO; prio++)
965                 sta->flowid[prio] = FLOWID_INVALID;
966         sta->ifp = DHD_IF_NULL; /* dummy dhd_if object */
967         sta->ifidx = DHD_BAD_IF;
968         bzero(sta->ea.octet, ETHER_ADDR_LEN);
969         INIT_LIST_HEAD(&sta->list);
970         sta->idx = ID16_INVALID; /* implying free */
971 }
972
973 /** Allocate a dhd_sta object from the dhd pool. */
974 static dhd_sta_t *
975 dhd_sta_alloc(dhd_pub_t * dhdp)
976 {
977         uint16 idx;
978         dhd_sta_t * sta;
979         dhd_sta_pool_t * sta_pool;
980
981         ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL));
982
983         idx = id16_map_alloc(dhdp->staid_allocator);
984         if (idx == ID16_INVALID) {
985                 DHD_ERROR(("%s: cannot get free staid\n", __FUNCTION__));
986                 return DHD_STA_NULL;
987         }
988
989         sta_pool = (dhd_sta_pool_t *)(dhdp->sta_pool);
990         sta = &sta_pool[idx];
991
992         ASSERT((sta->idx == ID16_INVALID) &&
993                (sta->ifp == DHD_IF_NULL) && (sta->ifidx == DHD_BAD_IF));
994         sta->idx = idx; /* implying allocated */
995
996         return sta;
997 }
998
999 /** Delete all STAs in an interface's STA list. */
1000 static void
1001 dhd_if_del_sta_list(dhd_if_t *ifp)
1002 {
1003         dhd_sta_t *sta, *next;
1004         unsigned long flags;
1005
1006         DHD_IF_STA_LIST_LOCK(ifp, flags);
1007
1008         list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
1009 #if defined(BCM_GMAC3)
1010                 if (ifp->fwdh) {
1011                         /* Remove sta from WOFA forwarder. */
1012                         fwder_deassoc(ifp->fwdh, (uint16 *)(sta->ea.octet), (wofa_t)sta);
1013                 }
1014 #endif /* BCM_GMAC3 */
1015                 list_del(&sta->list);
1016                 dhd_sta_free(&ifp->info->pub, sta);
1017         }
1018
1019         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1020
1021         return;
1022 }
1023
1024 /** Router/GMAC3: Flush all station entries in the forwarder's WOFA database. */
1025 static void
1026 dhd_if_flush_sta(dhd_if_t * ifp)
1027 {
1028 #if defined(BCM_GMAC3)
1029
1030         if (ifp && (ifp->fwdh != FWDER_NULL)) {
1031                 dhd_sta_t *sta, *next;
1032                 unsigned long flags;
1033
1034                 DHD_IF_STA_LIST_LOCK(ifp, flags);
1035
1036                 list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
1037                         /* Remove any sta entry from WOFA forwarder. */
1038                         fwder_flush(ifp->fwdh, (wofa_t)sta);
1039                 }
1040
1041                 DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1042         }
1043 #endif /* BCM_GMAC3 */
1044 }
1045
1046 /** Construct a pool of dhd_sta_t objects to be used by interfaces. */
1047 static int
1048 dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta)
1049 {
1050         int idx, sta_pool_memsz;
1051         dhd_sta_t * sta;
1052         dhd_sta_pool_t * sta_pool;
1053         void * staid_allocator;
1054
1055         ASSERT(dhdp != (dhd_pub_t *)NULL);
1056         ASSERT((dhdp->staid_allocator == NULL) && (dhdp->sta_pool == NULL));
1057
1058         /* dhd_sta objects per radio are managed in a table. id#0 reserved. */
1059         staid_allocator = id16_map_init(dhdp->osh, max_sta, 1);
1060         if (staid_allocator == NULL) {
1061                 DHD_ERROR(("%s: sta id allocator init failure\n", __FUNCTION__));
1062                 return BCME_ERROR;
1063         }
1064
1065         /* Pre allocate a pool of dhd_sta objects (one extra). */
1066         sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); /* skip idx 0 */
1067         sta_pool = (dhd_sta_pool_t *)MALLOC(dhdp->osh, sta_pool_memsz);
1068         if (sta_pool == NULL) {
1069                 DHD_ERROR(("%s: sta table alloc failure\n", __FUNCTION__));
1070                 id16_map_fini(dhdp->osh, staid_allocator);
1071                 return BCME_ERROR;
1072         }
1073
1074         dhdp->sta_pool = sta_pool;
1075         dhdp->staid_allocator = staid_allocator;
1076
1077         /* Initialize all sta(s) for the pre-allocated free pool. */
1078         bzero((uchar *)sta_pool, sta_pool_memsz);
1079         for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */
1080                 sta = &sta_pool[idx];
1081                 sta->idx = id16_map_alloc(staid_allocator);
1082                 ASSERT(sta->idx <= max_sta);
1083         }
1084         /* Now place them into the pre-allocated free pool. */
1085         for (idx = 1; idx <= max_sta; idx++) {
1086                 sta = &sta_pool[idx];
1087                 dhd_sta_free(dhdp, sta);
1088         }
1089
1090         return BCME_OK;
1091 }
1092
1093 /** Destruct the pool of dhd_sta_t objects.
1094  * Caller must ensure that no STA objects are currently associated with an if.
1095  */
1096 static void
1097 dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta)
1098 {
1099         dhd_sta_pool_t * sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool;
1100
1101         if (sta_pool) {
1102                 int idx;
1103                 int sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t));
1104                 for (idx = 1; idx <= max_sta; idx++) {
1105                         ASSERT(sta_pool[idx].ifp == DHD_IF_NULL);
1106                         ASSERT(sta_pool[idx].idx == ID16_INVALID);
1107                 }
1108                 MFREE(dhdp->osh, dhdp->sta_pool, sta_pool_memsz);
1109                 dhdp->sta_pool = NULL;
1110         }
1111
1112         id16_map_fini(dhdp->osh, dhdp->staid_allocator);
1113         dhdp->staid_allocator = NULL;
1114 }
1115
1116 /* Clear the pool of dhd_sta_t objects for built-in type driver */
1117 static void
1118 dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta)
1119 {
1120         int idx, sta_pool_memsz;
1121         dhd_sta_t * sta;
1122         dhd_sta_pool_t * sta_pool;
1123         void *staid_allocator;
1124
1125         if (!dhdp) {
1126                 DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
1127                 return;
1128         }
1129
1130         sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool;
1131         staid_allocator = dhdp->staid_allocator;
1132
1133         if (!sta_pool) {
1134                 DHD_ERROR(("%s: sta_pool is NULL\n", __FUNCTION__));
1135                 return;
1136         }
1137
1138         if (!staid_allocator) {
1139                 DHD_ERROR(("%s: staid_allocator is NULL\n", __FUNCTION__));
1140                 return;
1141         }
1142
1143         /* clear free pool */
1144         sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t));
1145         bzero((uchar *)sta_pool, sta_pool_memsz);
1146
1147         /* dhd_sta objects per radio are managed in a table. id#0 reserved. */
1148         id16_map_clear(staid_allocator, max_sta, 1);
1149
1150         /* Initialize all sta(s) for the pre-allocated free pool. */
1151         for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */
1152                 sta = &sta_pool[idx];
1153                 sta->idx = id16_map_alloc(staid_allocator);
1154                 ASSERT(sta->idx <= max_sta);
1155         }
1156         /* Now place them into the pre-allocated free pool. */
1157         for (idx = 1; idx <= max_sta; idx++) {
1158                 sta = &sta_pool[idx];
1159                 dhd_sta_free(dhdp, sta);
1160         }
1161 }
1162
1163 /** Find STA with MAC address ea in an interface's STA list. */
1164 dhd_sta_t *
1165 dhd_find_sta(void *pub, int ifidx, void *ea)
1166 {
1167         dhd_sta_t *sta, *next;
1168         dhd_if_t *ifp;
1169         unsigned long flags;
1170
1171         ASSERT(ea != NULL);
1172         ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
1173         if (ifp == NULL)
1174                 return DHD_STA_NULL;
1175
1176         DHD_IF_STA_LIST_LOCK(ifp, flags);
1177
1178         list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
1179                 if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) {
1180                         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1181                         return sta;
1182                 }
1183         }
1184
1185         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1186
1187         return DHD_STA_NULL;
1188 }
1189
1190 /** Add STA into the interface's STA list. */
1191 dhd_sta_t *
1192 dhd_add_sta(void *pub, int ifidx, void *ea)
1193 {
1194         dhd_sta_t *sta;
1195         dhd_if_t *ifp;
1196         unsigned long flags;
1197
1198         ASSERT(ea != NULL);
1199         ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
1200         if (ifp == NULL)
1201                 return DHD_STA_NULL;
1202
1203         sta = dhd_sta_alloc((dhd_pub_t *)pub);
1204         if (sta == DHD_STA_NULL) {
1205                 DHD_ERROR(("%s: Alloc failed\n", __FUNCTION__));
1206                 return DHD_STA_NULL;
1207         }
1208
1209         memcpy(sta->ea.octet, ea, ETHER_ADDR_LEN);
1210
1211         /* link the sta and the dhd interface */
1212         sta->ifp = ifp;
1213         sta->ifidx = ifidx;
1214         INIT_LIST_HEAD(&sta->list);
1215
1216         DHD_IF_STA_LIST_LOCK(ifp, flags);
1217
1218         list_add_tail(&sta->list, &ifp->sta_list);
1219
1220 #if defined(BCM_GMAC3)
1221         if (ifp->fwdh) {
1222                 ASSERT(ISALIGNED(ea, 2));
1223                 /* Add sta to WOFA forwarder. */
1224                 fwder_reassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta);
1225         }
1226 #endif /* BCM_GMAC3 */
1227
1228         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1229
1230         return sta;
1231 }
1232
1233 /** Delete STA from the interface's STA list. */
1234 void
1235 dhd_del_sta(void *pub, int ifidx, void *ea)
1236 {
1237         dhd_sta_t *sta, *next;
1238         dhd_if_t *ifp;
1239         unsigned long flags;
1240
1241         ASSERT(ea != NULL);
1242         ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
1243         if (ifp == NULL)
1244                 return;
1245
1246         DHD_IF_STA_LIST_LOCK(ifp, flags);
1247
1248         list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
1249                 if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) {
1250 #if defined(BCM_GMAC3)
1251                         if (ifp->fwdh) { /* Found a sta, remove from WOFA forwarder. */
1252                                 ASSERT(ISALIGNED(ea, 2));
1253                                 fwder_deassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta);
1254                         }
1255 #endif /* BCM_GMAC3 */
1256                         list_del(&sta->list);
1257                         dhd_sta_free(&ifp->info->pub, sta);
1258                 }
1259         }
1260
1261         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1262
1263         return;
1264 }
1265
1266 /** Add STA if it doesn't exist. Not reentrant. */
1267 dhd_sta_t*
1268 dhd_findadd_sta(void *pub, int ifidx, void *ea)
1269 {
1270         dhd_sta_t *sta;
1271
1272         sta = dhd_find_sta(pub, ifidx, ea);
1273
1274         if (!sta) {
1275                 /* Add entry */
1276                 sta = dhd_add_sta(pub, ifidx, ea);
1277         }
1278
1279         return sta;
1280 }
1281 #else
1282 static inline void dhd_if_flush_sta(dhd_if_t * ifp) { }
1283 static inline void dhd_if_del_sta_list(dhd_if_t *ifp) {}
1284 static inline int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta) { return BCME_OK; }
1285 static inline void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta) {}
1286 static inline void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta) {}
1287 dhd_sta_t *dhd_findadd_sta(void *pub, int ifidx, void *ea) { return NULL; }
1288 void dhd_del_sta(void *pub, int ifidx, void *ea) {}
1289 #endif /* PCIE_FULL_DONGLE */
1290
1291
1292 /* Returns dhd iflist index correspondig the the bssidx provided by apps */
1293 int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx)
1294 {
1295         dhd_if_t *ifp;
1296         dhd_info_t *dhd = dhdp->info;
1297         int i;
1298
1299         ASSERT(bssidx < DHD_MAX_IFS);
1300         ASSERT(dhdp);
1301
1302         for (i = 0; i < DHD_MAX_IFS; i++) {
1303                 ifp = dhd->iflist[i];
1304                 if (ifp && (ifp->bssidx == bssidx)) {
1305                         DHD_TRACE(("Index manipulated for %s from %d to %d\n",
1306                                 ifp->name, bssidx, i));
1307                         break;
1308                 }
1309         }
1310         return i;
1311 }
1312
1313 static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb)
1314 {
1315         uint32 store_idx;
1316         uint32 sent_idx;
1317
1318         if (!skb) {
1319                 DHD_ERROR(("dhd_rxf_enqueue: NULL skb!!!\n"));
1320                 return BCME_ERROR;
1321         }
1322
1323         dhd_os_rxflock(dhdp);
1324         store_idx = dhdp->store_idx;
1325         sent_idx = dhdp->sent_idx;
1326         if (dhdp->skbbuf[store_idx] != NULL) {
1327                 /* Make sure the previous packets are processed */
1328                 dhd_os_rxfunlock(dhdp);
1329 #ifdef RXF_DEQUEUE_ON_BUSY
1330                 DHD_TRACE(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n",
1331                         skb, store_idx, sent_idx));
1332                 return BCME_BUSY;
1333 #else /* RXF_DEQUEUE_ON_BUSY */
1334                 DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n",
1335                         skb, store_idx, sent_idx));
1336                 /* removed msleep here, should use wait_event_timeout if we
1337                  * want to give rx frame thread a chance to run
1338                  */
1339 #if defined(WAIT_DEQUEUE)
1340                 OSL_SLEEP(1);
1341 #endif
1342                 return BCME_ERROR;
1343 #endif /* RXF_DEQUEUE_ON_BUSY */
1344         }
1345         DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n",
1346                 skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1)));
1347         dhdp->skbbuf[store_idx] = skb;
1348         dhdp->store_idx = (store_idx + 1) & (MAXSKBPEND - 1);
1349         dhd_os_rxfunlock(dhdp);
1350
1351         return BCME_OK;
1352 }
1353
1354 static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp)
1355 {
1356         uint32 store_idx;
1357         uint32 sent_idx;
1358         void *skb;
1359
1360         dhd_os_rxflock(dhdp);
1361
1362         store_idx = dhdp->store_idx;
1363         sent_idx = dhdp->sent_idx;
1364         skb = dhdp->skbbuf[sent_idx];
1365
1366         if (skb == NULL) {
1367                 dhd_os_rxfunlock(dhdp);
1368                 DHD_ERROR(("dhd_rxf_dequeue: Dequeued packet is NULL, store idx %d sent idx %d\n",
1369                         store_idx, sent_idx));
1370                 return NULL;
1371         }
1372
1373         dhdp->skbbuf[sent_idx] = NULL;
1374         dhdp->sent_idx = (sent_idx + 1) & (MAXSKBPEND - 1);
1375
1376         DHD_TRACE(("dhd_rxf_dequeue: netif_rx_ni(%p), sent idx %d\n",
1377                 skb, sent_idx));
1378
1379         dhd_os_rxfunlock(dhdp);
1380
1381         return skb;
1382 }
1383
1384 int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost)
1385 {
1386         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
1387
1388         if (prepost) { /* pre process */
1389                 dhd_read_macaddr(dhd);
1390         } else { /* post process */
1391                 dhd_write_macaddr(&dhd->pub.mac);
1392         }
1393
1394         return 0;
1395 }
1396
1397 #if defined(PKT_FILTER_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER)
1398 static bool
1399 _turn_on_arp_filter(dhd_pub_t *dhd, int op_mode)
1400 {
1401         bool _apply = FALSE;
1402         /* In case of IBSS mode, apply arp pkt filter */
1403         if (op_mode & DHD_FLAG_IBSS_MODE) {
1404                 _apply = TRUE;
1405                 goto exit;
1406         }
1407         /* In case of P2P GO or GC, apply pkt filter to pass arp pkt to host */
1408         if ((dhd->arp_version == 1) &&
1409                 (op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) {
1410                 _apply = TRUE;
1411                 goto exit;
1412         }
1413
1414 exit:
1415         return _apply;
1416 }
1417 #endif /* PKT_FILTER_SUPPORT && !GAN_LITE_NAT_KEEPALIVE_FILTER */
1418
1419 #ifdef PKT_FILTER_SUPPORT
1420 void
1421 dhd_set_packet_filter_mode(struct net_device *dev, char *command)
1422 {
1423         dhd_info_t *dhdi = *(dhd_info_t **)netdev_priv(dev);
1424         dhd_pub_t *dhdp = &dhdi->pub;
1425
1426         dhdi->pub.pkt_filter_mode = bcm_strtoul(command, &command, 0);
1427         dhd_enable_packet_filter(1, dhdp);
1428 }
1429
1430 int
1431 dhd_set_packet_filter_ports(struct net_device *dev, char *command)
1432 {
1433         int i = 0, error = BCME_OK, count = 0, get_count = 0, action = 0;
1434         uint16 portnum = 0, *ports = NULL, get_ports[WL_PKT_FILTER_PORTS_MAX];
1435         dhd_info_t *dhdi = *(dhd_info_t **)netdev_priv(dev);
1436         dhd_pub_t *dhdp = &dhdi->pub;
1437         char iovbuf[WLC_IOCTL_SMLEN];
1438
1439         /* get action */
1440         action = bcm_strtoul(command, &command, 0);
1441         if (action > PKT_FILTER_PORTS_MAX)
1442                 return BCME_BADARG;
1443
1444         if (action == PKT_FILTER_PORTS_LOOPBACK) {
1445                 /* echo the loopback value if port filter is supported else error */
1446                 bcm_mkiovar("cap", NULL, 0, iovbuf, sizeof(iovbuf));
1447                 error = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
1448                 if (error < 0) {
1449                         DHD_ERROR(("%s: Get Capability failed (error=%d)\n", __FUNCTION__, error));
1450                         return error;
1451                 }
1452
1453                 if (strstr(iovbuf, "pktfltr2"))
1454                         return bcm_strtoul(command, &command, 0);
1455                 else {
1456                         DHD_ERROR(("%s: pktfltr2 is not supported\n", __FUNCTION__));
1457                         return BCME_UNSUPPORTED;
1458                 }
1459         }
1460
1461         if (action == PKT_FILTER_PORTS_CLEAR) {
1462                 /* action 0 is clear all ports */
1463                 dhdp->pkt_filter_ports_count = 0;
1464                 bzero(dhdp->pkt_filter_ports, sizeof(dhdp->pkt_filter_ports));
1465         }
1466         else {
1467                 portnum = bcm_strtoul(command, &command, 0);
1468                 if (portnum == 0) {
1469                         /* no ports to add or remove */
1470                         return BCME_BADARG;
1471                 }
1472
1473                 /* get configured ports */
1474                 count = dhdp->pkt_filter_ports_count;
1475                 ports = dhdp->pkt_filter_ports;
1476
1477                 if (action == PKT_FILTER_PORTS_ADD) {
1478                         /* action 1 is add ports */
1479
1480                         /* copy new ports */
1481                         while ((portnum != 0) && (count < WL_PKT_FILTER_PORTS_MAX)) {
1482                                 for (i = 0; i < count; i++) {
1483                                         /* duplicate port */
1484                                         if (portnum == ports[i])
1485                                                 break;
1486                                 }
1487                                 if (portnum != ports[i])
1488                                         ports[count++] = portnum;
1489                                 portnum = bcm_strtoul(command, &command, 0);
1490                         }
1491                 } else if ((action == PKT_FILTER_PORTS_DEL) && (count > 0)) {
1492                         /* action 2 is remove ports */
1493                         bcopy(dhdp->pkt_filter_ports, get_ports, count * sizeof(uint16));
1494                         get_count = count;
1495
1496                         while (portnum != 0) {
1497                                 count = 0;
1498                                 for (i = 0; i < get_count; i++) {
1499                                         if (portnum != get_ports[i])
1500                                                 ports[count++] = get_ports[i];
1501                                 }
1502                                 get_count = count;
1503                                 bcopy(ports, get_ports, count * sizeof(uint16));
1504                                 portnum = bcm_strtoul(command, &command, 0);
1505                         }
1506                 }
1507                 dhdp->pkt_filter_ports_count = count;
1508         }
1509         return error;
1510 }
1511
1512 static void
1513 dhd_enable_packet_filter_ports(dhd_pub_t *dhd, bool enable)
1514 {
1515         int error = 0;
1516         wl_pkt_filter_ports_t *portlist = NULL;
1517         const uint pkt_filter_ports_buf_len = sizeof("pkt_filter_ports")
1518                 + WL_PKT_FILTER_PORTS_FIXED_LEN + (WL_PKT_FILTER_PORTS_MAX * sizeof(uint16));
1519         char pkt_filter_ports_buf[pkt_filter_ports_buf_len];
1520         char iovbuf[pkt_filter_ports_buf_len];
1521
1522         DHD_ERROR(("%s: enable %d, in_suspend %d, mode %d, port count %d\n", __FUNCTION__,
1523                 enable, dhd->in_suspend, dhd->pkt_filter_mode,
1524                 dhd->pkt_filter_ports_count));
1525
1526         bzero(pkt_filter_ports_buf, sizeof(pkt_filter_ports_buf));
1527         portlist = (wl_pkt_filter_ports_t*)pkt_filter_ports_buf;
1528         portlist->version = WL_PKT_FILTER_PORTS_VERSION;
1529         portlist->reserved = 0;
1530
1531         if (enable) {
1532                 if (!(dhd->pkt_filter_mode & PKT_FILTER_MODE_PORTS_ONLY)) {
1533                         /* disable port filter */
1534                         portlist->count = 0;
1535                         dhd_master_mode &= ~PKT_FILTER_MODE_PORTS_ONLY;
1536                         dhd_master_mode |= PKT_FILTER_MODE_FORWARD_ON_MATCH;
1537                 } else {
1538                         /* enable port filter */
1539                         dhd_master_mode |= PKT_FILTER_MODE_PORTS_ONLY;
1540                         if (dhd->pkt_filter_mode
1541                                 & PKT_FILTER_MODE_FORWARD_ON_MATCH)
1542                                 /* whitelist mode: FORWARD_ON_MATCH */
1543                                 dhd_master_mode |=
1544                                         PKT_FILTER_MODE_FORWARD_ON_MATCH;
1545                         else
1546                                 /* blacklist mode: DISCARD_ON_MATCH */
1547                                 dhd_master_mode &=
1548                                         ~PKT_FILTER_MODE_FORWARD_ON_MATCH;
1549                         portlist->count = dhd->pkt_filter_ports_count;
1550                         bcopy(dhd->pkt_filter_ports, portlist->ports,
1551                                 dhd->pkt_filter_ports_count * sizeof(uint16));
1552                 }
1553         } else {
1554                 /* disable port filter */
1555                 portlist->count = 0;
1556                 dhd_master_mode &= ~PKT_FILTER_MODE_PORTS_ONLY;
1557                 dhd_master_mode |= PKT_FILTER_MODE_FORWARD_ON_MATCH;
1558         }
1559
1560         DHD_INFO(("%s: update: mode %d, port count %d\n", __FUNCTION__, dhd_master_mode,
1561                 portlist->count));
1562
1563         /* update ports */
1564         bcm_mkiovar("pkt_filter_ports",
1565                 (char*)portlist,
1566                 (WL_PKT_FILTER_PORTS_FIXED_LEN + (portlist->count * sizeof(uint16))),
1567                 iovbuf, sizeof(iovbuf));
1568         error = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1569         if (error < 0)
1570                 DHD_ERROR(("%s: set pkt_filter_ports failed %d\n", __FUNCTION__, error));
1571
1572         /* update mode */
1573         bcm_mkiovar("pkt_filter_mode", (char*)&dhd_master_mode,
1574                 sizeof(dhd_master_mode), iovbuf, sizeof(iovbuf));
1575         error = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1576         if (error < 0)
1577                 DHD_ERROR(("%s: set pkt_filter_mode failed %d\n", __FUNCTION__, error));
1578
1579         return;
1580 }
1581 #endif /* PKT_FILTER_SUPPORT */
1582
1583 void dhd_set_packet_filter(dhd_pub_t *dhd)
1584 {
1585 #ifdef PKT_FILTER_SUPPORT
1586         int i;
1587
1588         DHD_TRACE(("%s: enter\n", __FUNCTION__));
1589         if (dhd_pkt_filter_enable) {
1590                 for (i = 0; i < dhd->pktfilter_count; i++) {
1591                         dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
1592                 }
1593         }
1594 #endif /* PKT_FILTER_SUPPORT */
1595 }
1596
1597 void dhd_enable_packet_filter(int value, dhd_pub_t *dhd)
1598 {
1599 #ifdef PKT_FILTER_SUPPORT
1600         int i;
1601
1602         DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value));
1603
1604         dhd_enable_packet_filter_ports(dhd, value);
1605
1606         /* 1 - Enable packet filter, only allow unicast packet to send up */
1607         /* 0 - Disable packet filter */
1608         if (dhd_pkt_filter_enable && (!value ||
1609             (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress)))
1610             {
1611                 for (i = 0; i < dhd->pktfilter_count; i++) {
1612 #ifndef GAN_LITE_NAT_KEEPALIVE_FILTER
1613                         if (value && (i == DHD_ARP_FILTER_NUM) &&
1614                                 !_turn_on_arp_filter(dhd, dhd->op_mode)) {
1615                                 DHD_TRACE(("Do not turn on ARP white list pkt filter:"
1616                                         "val %d, cnt %d, op_mode 0x%x\n",
1617                                         value, i, dhd->op_mode));
1618                                 continue;
1619                         }
1620 #endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */
1621                         dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
1622                                 value, dhd_master_mode);
1623                 }
1624         }
1625 #endif /* PKT_FILTER_SUPPORT */
1626 }
1627
1628 static int dhd_set_suspend(int value, dhd_pub_t *dhd)
1629 {
1630 #ifndef SUPPORT_PM2_ONLY
1631         int power_mode = PM_MAX;
1632 #endif /* SUPPORT_PM2_ONLY */
1633         /* wl_pkt_filter_enable_t       enable_parm; */
1634         char iovbuf[32];
1635         int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */
1636 #ifndef ENABLE_FW_ROAM_SUSPEND
1637         uint roamvar = 1;
1638 #endif /* ENABLE_FW_ROAM_SUSPEND */
1639         uint nd_ra_filter = 0;
1640         int ret = 0;
1641
1642         if (!dhd)
1643                 return -ENODEV;
1644
1645
1646         DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n",
1647                 __FUNCTION__, value, dhd->in_suspend));
1648
1649         dhd_suspend_lock(dhd);
1650
1651 #ifdef CUSTOM_SET_CPUCORE
1652         DHD_TRACE(("%s set cpucore(suspend%d)\n", __FUNCTION__, value));
1653         /* set specific cpucore */
1654         dhd_set_cpucore(dhd, TRUE);
1655 #endif /* CUSTOM_SET_CPUCORE */
1656         if (dhd->up) {
1657                 if (value && dhd->in_suspend) {
1658 #ifdef PKT_FILTER_SUPPORT
1659                                 dhd->early_suspended = 1;
1660 #endif
1661 #ifdef CONFIG_BCMDHD_CUSTOM_SYSFS_TEGRA
1662                                 tegra_sysfs_suspend();
1663 #endif
1664                                 /* Kernel suspended */
1665                                 DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__));
1666
1667 #ifndef SUPPORT_PM2_ONLY
1668                                 dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
1669                                                  sizeof(power_mode), TRUE, 0);
1670 #endif /* SUPPORT_PM2_ONLY */
1671
1672                                 /* Enable packet filter, only allow unicast packet to send up */
1673                                 dhd_enable_packet_filter(1, dhd);
1674
1675
1676                                 /* If DTIM skip is set up as default, force it to wake
1677                                  * each third DTIM for better power savings.  Note that
1678                                  * one side effect is a chance to miss BC/MC packet.
1679                                  */
1680                                 bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd);
1681                                 bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
1682                                         4, iovbuf, sizeof(iovbuf));
1683                                 if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf),
1684                                         TRUE, 0) < 0)
1685                                         DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__));
1686
1687 #ifndef ENABLE_FW_ROAM_SUSPEND
1688                                 /* Disable firmware roaming during suspend */
1689                                 bcm_mkiovar("roam_off", (char *)&roamvar, 4,
1690                                         iovbuf, sizeof(iovbuf));
1691                                 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1692 #endif /* ENABLE_FW_ROAM_SUSPEND */
1693                                 if (FW_SUPPORTED(dhd, ndoe)) {
1694                                         /* enable IPv6 RA filter in  firmware during suspend */
1695                                         nd_ra_filter = 1;
1696                                         bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4,
1697                                                 iovbuf, sizeof(iovbuf));
1698                                         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
1699                                                 sizeof(iovbuf), TRUE, 0)) < 0)
1700                                                 DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
1701                                                         ret));
1702                                 }
1703 #if defined(SUPPORT_P2P_GO_PS)
1704 if (bcmdhd_support_p2p_go_ps) {
1705 #ifdef PROP_TXSTATUS
1706                                 DHD_OS_WAKE_LOCK_WAIVE(dhd);
1707                                 dhd_wlfc_suspend(dhd);
1708                                 DHD_OS_WAKE_LOCK_RESTORE(dhd);
1709 #endif
1710 }
1711 #endif /* defined(SUPPORT_P2P_GO_PS) */
1712                         } else {
1713 #ifdef PKT_FILTER_SUPPORT
1714                                 dhd->early_suspended = 0;
1715 #endif
1716 #ifdef CONFIG_BCMDHD_CUSTOM_SYSFS_TEGRA
1717                                 tegra_sysfs_resume();
1718 #endif
1719                                 /* Kernel resumed  */
1720                                 DHD_ERROR(("%s: Remove extra suspend setting \n", __FUNCTION__));
1721
1722 #ifndef SUPPORT_PM2_ONLY
1723                                 power_mode = PM_FAST;
1724                                 dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
1725                                                  sizeof(power_mode), TRUE, 0);
1726 #endif /* SUPPORT_PM2_ONLY */
1727 #ifdef PKT_FILTER_SUPPORT
1728                                 /* disable pkt filter */
1729                                 dhd_enable_packet_filter(0, dhd);
1730 #endif /* PKT_FILTER_SUPPORT */
1731
1732                                 /* restore pre-suspend setting for dtim_skip */
1733                                 bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
1734                                         4, iovbuf, sizeof(iovbuf));
1735
1736                                 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1737 #ifndef ENABLE_FW_ROAM_SUSPEND
1738                                 roamvar = dhd_roam_disable;
1739                                 bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf,
1740                                         sizeof(iovbuf));
1741                                 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1742 #endif /* ENABLE_FW_ROAM_SUSPEND */
1743                                 if (FW_SUPPORTED(dhd, ndoe)) {
1744                                         /* disable IPv6 RA filter in  firmware during suspend */
1745                                         nd_ra_filter = 0;
1746                                         bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4,
1747                                                 iovbuf, sizeof(iovbuf));
1748                                         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
1749                                                 sizeof(iovbuf), TRUE, 0)) < 0)
1750                                                 DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
1751                                                         ret));
1752                                 }
1753 #if defined(SUPPORT_P2P_GO_PS)
1754 if (bcmdhd_support_p2p_go_ps) {
1755 #ifdef PROP_TXSTATUS
1756                                 dhd_wlfc_resume(dhd);
1757 #endif
1758 }
1759 #endif /* defined(SUPPORT_P2P_GO_PS) */
1760
1761                         }
1762         }
1763         dhd_suspend_unlock(dhd);
1764
1765         return 0;
1766 }
1767
1768 static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force)
1769 {
1770         dhd_pub_t *dhdp = &dhd->pub;
1771         int ret = 0;
1772
1773         DHD_OS_WAKE_LOCK(dhdp);
1774         DHD_PERIM_LOCK(dhdp);
1775
1776         /* Set flag when early suspend was called */
1777         dhdp->in_suspend = val;
1778         if ((force || !dhdp->suspend_disable_flag) &&
1779                 dhd_support_sta_mode(dhdp))
1780         {
1781                 ret = dhd_set_suspend(val, dhdp);
1782         }
1783
1784         DHD_PERIM_UNLOCK(dhdp);
1785         DHD_OS_WAKE_UNLOCK(dhdp);
1786         return ret;
1787 }
1788
1789 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
1790 static void dhd_early_suspend(struct early_suspend *h)
1791 {
1792         struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
1793         DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__));
1794
1795         if (dhd)
1796                 dhd_suspend_resume_helper(dhd, 1, 0);
1797 }
1798
1799 static void dhd_late_resume(struct early_suspend *h)
1800 {
1801         struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
1802         DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__));
1803
1804         if (dhd)
1805                 dhd_suspend_resume_helper(dhd, 0, 0);
1806 }
1807 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
1808
1809 /*
1810  * Generalized timeout mechanism.  Uses spin sleep with exponential back-off until
1811  * the sleep time reaches one jiffy, then switches over to task delay.  Usage:
1812  *
1813  *      dhd_timeout_start(&tmo, usec);
1814  *      while (!dhd_timeout_expired(&tmo))
1815  *              if (poll_something())
1816  *                      break;
1817  *      if (dhd_timeout_expired(&tmo))
1818  *              fatal();
1819  */
1820
1821 void
1822 dhd_timeout_start(dhd_timeout_t *tmo, uint usec)
1823 {
1824         tmo->limit = usec;
1825         tmo->increment = 0;
1826         tmo->elapsed = 0;
1827         tmo->tick = jiffies_to_usecs(1);
1828 }
1829
1830 int
1831 dhd_timeout_expired(dhd_timeout_t *tmo)
1832 {
1833         /* Does nothing the first call */
1834         if (tmo->increment == 0) {
1835                 tmo->increment = 1;
1836                 return 0;
1837         }
1838
1839         if (tmo->elapsed >= tmo->limit)
1840                 return 1;
1841
1842         /* Add the delay that's about to take place */
1843         tmo->elapsed += tmo->increment;
1844
1845         if ((!CAN_SLEEP()) || tmo->increment < tmo->tick) {
1846                 OSL_DELAY(tmo->increment);
1847                 tmo->increment *= 2;
1848                 if (tmo->increment > tmo->tick)
1849                         tmo->increment = tmo->tick;
1850         } else {
1851                 wait_queue_head_t delay_wait;
1852                 DECLARE_WAITQUEUE(wait, current);
1853                 init_waitqueue_head(&delay_wait);
1854                 add_wait_queue(&delay_wait, &wait);
1855                 set_current_state(TASK_INTERRUPTIBLE);
1856                 (void)schedule_timeout(1);
1857                 remove_wait_queue(&delay_wait, &wait);
1858                 set_current_state(TASK_RUNNING);
1859         }
1860
1861         return 0;
1862 }
1863
1864 int
1865 dhd_net2idx(dhd_info_t *dhd, struct net_device *net)
1866 {
1867         int i = 0;
1868
1869         if (!dhd) {
1870                 DHD_ERROR(("%s : DHD_BAD_IF return\n", __FUNCTION__));
1871                 return DHD_BAD_IF;
1872         }
1873         while (i < DHD_MAX_IFS) {
1874                 if (dhd->iflist[i] && dhd->iflist[i]->net && (dhd->iflist[i]->net == net))
1875                         return i;
1876                 i++;
1877         }
1878
1879         return DHD_BAD_IF;
1880 }
1881
1882 struct net_device * dhd_idx2net(void *pub, int ifidx)
1883 {
1884         struct dhd_pub *dhd_pub = (struct dhd_pub *)pub;
1885         struct dhd_info *dhd_info;
1886
1887         if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS)
1888                 return NULL;
1889         dhd_info = dhd_pub->info;
1890         if (dhd_info && dhd_info->iflist[ifidx])
1891                 return dhd_info->iflist[ifidx]->net;
1892         return NULL;
1893 }
1894
1895 int
1896 dhd_ifname2idx(dhd_info_t *dhd, char *name)
1897 {
1898         int i = DHD_MAX_IFS;
1899
1900         ASSERT(dhd);
1901
1902         if (name == NULL || *name == '\0')
1903                 return 0;
1904
1905         while (--i > 0)
1906                 if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ))
1907                                 break;
1908
1909         DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name));
1910
1911         return i;       /* default - the primary interface */
1912 }
1913
1914 int
1915 dhd_ifidx2hostidx(dhd_info_t *dhd, int ifidx)
1916 {
1917         int i = DHD_MAX_IFS;
1918
1919         ASSERT(dhd);
1920
1921         while (--i > 0)
1922                 if (dhd->iflist[i] && (dhd->iflist[i]->idx == ifidx))
1923                                 break;
1924
1925         DHD_TRACE(("%s: return hostidx %d for ifidx %d\n", __FUNCTION__, i, ifidx));
1926
1927         return i;       /* default - the primary interface */
1928 }
1929
1930 char *
1931 dhd_ifname(dhd_pub_t *dhdp, int ifidx)
1932 {
1933         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
1934
1935         ASSERT(dhd);
1936
1937         if (ifidx < 0 || ifidx >= DHD_MAX_IFS) {
1938                 DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx));
1939                 return "<if_bad>";
1940         }
1941
1942         if (dhd->iflist[ifidx] == NULL) {
1943                 DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx));
1944                 return "<if_null>";
1945         }
1946
1947         if (dhd->iflist[ifidx]->net)
1948                 return dhd->iflist[ifidx]->net->name;
1949
1950         return "<if_none>";
1951 }
1952
1953 uint8 *
1954 dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx)
1955 {
1956         int i;
1957         dhd_info_t *dhd = (dhd_info_t *)dhdp;
1958
1959         ASSERT(dhd);
1960         for (i = 0; i < DHD_MAX_IFS; i++)
1961         if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx)
1962                 return dhd->iflist[i]->mac_addr;
1963
1964         return NULL;
1965 }
1966
1967
1968 static void
1969 _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
1970 {
1971         struct net_device *dev;
1972 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
1973         struct netdev_hw_addr *ha;
1974 #else
1975         struct dev_mc_list *mclist;
1976 #endif
1977         uint32 allmulti, cnt;
1978
1979         wl_ioctl_t ioc;
1980         char *buf, *bufp;
1981         uint buflen;
1982         int ret;
1983
1984                         ASSERT(dhd && dhd->iflist[ifidx]);
1985                         if (dhd == NULL || dhd->iflist[ifidx] == NULL)
1986                                 return;
1987                         dev = dhd->iflist[ifidx]->net;
1988                         if (!dev)
1989                                 return;
1990 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1991                         netif_addr_lock_bh(dev);
1992 #endif
1993 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
1994                         cnt = netdev_mc_count(dev);
1995 #else
1996                         cnt = dev->mc_count;
1997 #endif /* LINUX_VERSION_CODE */
1998
1999 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
2000                         netif_addr_unlock_bh(dev);
2001 #endif
2002
2003                         /* Determine initial value of allmulti flag */
2004         allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE;
2005
2006         /* Send down the multicast list first. */
2007
2008
2009         buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN);
2010         if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) {
2011                 DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n",
2012                            dhd_ifname(&dhd->pub, ifidx), cnt));
2013                 return;
2014         }
2015
2016         strncpy(bufp, "mcast_list", buflen - 1);
2017         bufp[buflen - 1] = '\0';
2018         bufp += strlen("mcast_list") + 1;
2019
2020         cnt = htol32(cnt);
2021         memcpy(bufp, &cnt, sizeof(cnt));
2022         bufp += sizeof(cnt);
2023
2024
2025 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
2026                         netif_addr_lock_bh(dev);
2027 #endif
2028 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
2029                         netdev_for_each_mc_addr(ha, dev) {
2030                                 if (!cnt)
2031                                         break;
2032                                 memcpy(bufp, ha->addr, ETHER_ADDR_LEN);
2033                                 bufp += ETHER_ADDR_LEN;
2034                                 cnt--;
2035         }
2036 #else
2037         for (mclist = dev->mc_list; (mclist && (cnt > 0));
2038                 cnt--, mclist = mclist->next) {
2039                                 memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN);
2040                                 bufp += ETHER_ADDR_LEN;
2041                         }
2042 #endif /* LINUX_VERSION_CODE */
2043
2044 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
2045                         netif_addr_unlock_bh(dev);
2046 #endif
2047
2048         memset(&ioc, 0, sizeof(ioc));
2049         ioc.cmd = WLC_SET_VAR;
2050         ioc.buf = buf;
2051         ioc.len = buflen;
2052         ioc.set = TRUE;
2053
2054         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
2055         if (ret < 0) {
2056                 DHD_ERROR(("%s: set mcast_list failed, cnt %d\n",
2057                         dhd_ifname(&dhd->pub, ifidx), cnt));
2058                 allmulti = cnt ? TRUE : allmulti;
2059         }
2060
2061         MFREE(dhd->pub.osh, buf, buflen);
2062
2063         /* Now send the allmulti setting.  This is based on the setting in the
2064          * net_device flags, but might be modified above to be turned on if we
2065          * were trying to set some addresses and dongle rejected it...
2066          */
2067
2068         buflen = sizeof("allmulti") + sizeof(allmulti);
2069         if (!(buf = MALLOC(dhd->pub.osh, buflen))) {
2070                 DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx)));
2071                 return;
2072         }
2073         allmulti = htol32(allmulti);
2074
2075         if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) {
2076                 DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
2077                            dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen));
2078                 MFREE(dhd->pub.osh, buf, buflen);
2079                 return;
2080         }
2081
2082
2083         memset(&ioc, 0, sizeof(ioc));
2084         ioc.cmd = WLC_SET_VAR;
2085         ioc.buf = buf;
2086         ioc.len = buflen;
2087         ioc.set = TRUE;
2088
2089         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
2090         if (ret < 0) {
2091                 DHD_ERROR(("%s: set allmulti %d failed\n",
2092                            dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
2093         }
2094
2095         MFREE(dhd->pub.osh, buf, buflen);
2096
2097         /* Finally, pick up the PROMISC flag as well, like the NIC driver does */
2098
2099         allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE;
2100
2101         allmulti = htol32(allmulti);
2102
2103         memset(&ioc, 0, sizeof(ioc));
2104         ioc.cmd = WLC_SET_PROMISC;
2105         ioc.buf = &allmulti;
2106         ioc.len = sizeof(allmulti);
2107         ioc.set = TRUE;
2108
2109         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
2110         if (ret < 0) {
2111                 DHD_ERROR(("%s: set promisc %d failed\n",
2112                            dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
2113         }
2114 }
2115
2116 int
2117 _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr)
2118 {
2119         char buf[32];
2120         wl_ioctl_t ioc;
2121         int ret;
2122
2123         if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) {
2124                 DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx)));
2125                 return -1;
2126         }
2127         memset(&ioc, 0, sizeof(ioc));
2128         ioc.cmd = WLC_SET_VAR;
2129         ioc.buf = buf;
2130         ioc.len = 32;
2131         ioc.set = TRUE;
2132
2133         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
2134         if (ret < 0) {
2135                 DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)));
2136         } else {
2137                 memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
2138                 if (ifidx == 0)
2139                         memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN);
2140         }
2141
2142         return ret;
2143 }
2144
2145 #ifdef SOFTAP
2146 extern struct net_device *ap_net_dev;
2147 extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */
2148 #endif
2149
2150 static void
2151 dhd_ifadd_event_handler(void *handle, void *event_info, u8 event)
2152 {
2153         dhd_info_t *dhd = handle;
2154         dhd_if_event_t *if_event = event_info;
2155         struct net_device *ndev;
2156         int ifidx, bssidx;
2157         int ret;
2158 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
2159         struct wireless_dev *vwdev, *primary_wdev;
2160         struct net_device *primary_ndev;
2161 #endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
2162
2163         if (event != DHD_WQ_WORK_IF_ADD) {
2164                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
2165                 return;
2166         }
2167
2168         if (!dhd) {
2169                 DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
2170                 return;
2171         }
2172
2173         if (!if_event) {
2174                 DHD_ERROR(("%s: event data is null \n", __FUNCTION__));
2175                 return;
2176         }
2177
2178         dhd_net_if_lock_local(dhd);
2179         DHD_OS_WAKE_LOCK(&dhd->pub);
2180         DHD_PERIM_LOCK(&dhd->pub);
2181
2182         ifidx = if_event->event.ifidx;
2183         bssidx = if_event->event.bssidx;
2184         DHD_TRACE(("%s: registering if with ifidx %d\n", __FUNCTION__, ifidx));
2185
2186         ndev = dhd_allocate_if(&dhd->pub, ifidx, if_event->name,
2187                 if_event->mac, bssidx, TRUE);
2188         if (!ndev) {
2189                 DHD_ERROR(("%s: net device alloc failed  \n", __FUNCTION__));
2190                 goto done;
2191         }
2192
2193 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
2194         vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
2195         if (unlikely(!vwdev)) {
2196                 WL_ERR(("Could not allocate wireless device\n"));
2197                 goto done;
2198         }
2199         primary_ndev = dhd->pub.info->iflist[0]->net;
2200         primary_wdev = ndev_to_wdev(primary_ndev);
2201         vwdev->wiphy = primary_wdev->wiphy;
2202         vwdev->iftype = if_event->event.role;
2203         vwdev->netdev = ndev;
2204         ndev->ieee80211_ptr = vwdev;
2205         SET_NETDEV_DEV(ndev, wiphy_dev(vwdev->wiphy));
2206         DHD_ERROR(("virtual interface(%s) is created\n", if_event->name));
2207 #endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
2208
2209         DHD_PERIM_UNLOCK(&dhd->pub);
2210         ret = dhd_register_if(&dhd->pub, ifidx, TRUE);
2211         DHD_PERIM_LOCK(&dhd->pub);
2212         if (ret != BCME_OK) {
2213                 DHD_ERROR(("%s: dhd_register_if failed\n", __FUNCTION__));
2214                 dhd_remove_if(&dhd->pub, ifidx, TRUE);
2215                 goto done;
2216         }
2217 #ifdef PCIE_FULL_DONGLE
2218         /* Turn on AP isolation in the firmware for interfaces operating in AP mode */
2219         if (FW_SUPPORTED((&dhd->pub), ap) && !(DHD_IF_ROLE_STA(if_event->event.role))) {
2220                 char iovbuf[WLC_IOCTL_SMLEN];
2221                 uint32 var_int =  1;
2222
2223                 memset(iovbuf, 0, sizeof(iovbuf));
2224                 bcm_mkiovar("ap_isolate", (char *)&var_int, 4, iovbuf, sizeof(iovbuf));
2225                 ret = dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, ifidx);
2226
2227                 if (ret != BCME_OK) {
2228                         DHD_ERROR(("%s: Failed to set ap_isolate to dongle\n", __FUNCTION__));
2229                         dhd_remove_if(&dhd->pub, ifidx, TRUE);
2230                 }
2231         }
2232 #endif /* PCIE_FULL_DONGLE */
2233 done:
2234         MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
2235
2236         DHD_PERIM_UNLOCK(&dhd->pub);
2237         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2238         dhd_net_if_unlock_local(dhd);
2239 }
2240
2241 static void
2242 dhd_ifdel_event_handler(void *handle, void *event_info, u8 event)
2243 {
2244         dhd_info_t *dhd = handle;
2245         int ifidx;
2246         dhd_if_event_t *if_event = event_info;
2247
2248
2249         if (event != DHD_WQ_WORK_IF_DEL) {
2250                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
2251                 return;
2252         }
2253
2254         if (!dhd) {
2255                 DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
2256                 return;
2257         }
2258
2259         if (!if_event) {
2260                 DHD_ERROR(("%s: event data is null \n", __FUNCTION__));
2261                 return;
2262         }
2263
2264         dhd_net_if_lock_local(dhd);
2265         DHD_OS_WAKE_LOCK(&dhd->pub);
2266         DHD_PERIM_LOCK(&dhd->pub);
2267
2268         ifidx = if_event->event.ifidx;
2269         DHD_TRACE(("Removing interface with idx %d\n", ifidx));
2270
2271         dhd_remove_if(&dhd->pub, ifidx, TRUE);
2272
2273         MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
2274
2275         DHD_PERIM_UNLOCK(&dhd->pub);
2276         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2277         dhd_net_if_unlock_local(dhd);
2278 }
2279
2280 static void
2281 dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event)
2282 {
2283         dhd_info_t *dhd = handle;
2284         dhd_if_t *ifp = event_info;
2285
2286         if (event != DHD_WQ_WORK_SET_MAC) {
2287                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
2288         }
2289
2290         if (!dhd) {
2291                 DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
2292                 return;
2293         }
2294
2295         dhd_net_if_lock_local(dhd);
2296         DHD_OS_WAKE_LOCK(&dhd->pub);
2297         DHD_PERIM_LOCK(&dhd->pub);
2298
2299 #ifdef SOFTAP
2300         {
2301                 unsigned long flags;
2302                 bool in_ap = FALSE;
2303                 DHD_GENERAL_LOCK(&dhd->pub, flags);
2304                 in_ap = (ap_net_dev != NULL);
2305                 DHD_GENERAL_UNLOCK(&dhd->pub, flags);
2306
2307                 if (in_ap)  {
2308                         DHD_ERROR(("attempt to set MAC for %s in AP Mode, blocked. \n",
2309                                    ifp->net->name));
2310                         goto done;
2311                 }
2312         }
2313 #endif /* SOFTAP */
2314
2315         if (ifp == NULL || !dhd->pub.up) {
2316                 DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__));
2317                 goto done;
2318         }
2319
2320         DHD_ERROR(("%s: MACID is overwritten\n", __FUNCTION__));
2321         ifp->set_macaddress = FALSE;
2322         if (_dhd_set_mac_address(dhd, ifp->idx, ifp->mac_addr) == 0)
2323                 DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__));
2324         else
2325                 DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__));
2326
2327 done:
2328         DHD_PERIM_UNLOCK(&dhd->pub);
2329         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2330         dhd_net_if_unlock_local(dhd);
2331 }
2332
2333 static void
2334 dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event)
2335 {
2336         dhd_info_t *dhd = handle;
2337         dhd_if_t *ifp = event_info;
2338         int ifidx;
2339
2340         if (event != DHD_WQ_WORK_SET_MCAST_LIST) {
2341                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
2342                 return;
2343         }
2344
2345         if (!dhd) {
2346                 DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
2347                 return;
2348         }
2349
2350         dhd_net_if_lock_local(dhd);
2351         DHD_OS_WAKE_LOCK(&dhd->pub);
2352         DHD_PERIM_LOCK(&dhd->pub);
2353
2354 #ifdef SOFTAP
2355         {
2356                 bool in_ap = FALSE;
2357                 unsigned long flags;
2358                 DHD_GENERAL_LOCK(&dhd->pub, flags);
2359                 in_ap = (ap_net_dev != NULL);
2360                 DHD_GENERAL_UNLOCK(&dhd->pub, flags);
2361
2362                 if (in_ap)  {
2363                         DHD_ERROR(("set MULTICAST list for %s in AP Mode, blocked. \n",
2364                                    ifp->net->name));
2365                         ifp->set_multicast = FALSE;
2366                         goto done;
2367                 }
2368         }
2369 #endif /* SOFTAP */
2370
2371         if (ifp == NULL || !dhd->pub.up) {
2372                 DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__));
2373                 goto done;
2374         }
2375
2376         ifidx = ifp->idx;
2377
2378
2379         _dhd_set_multicast_list(dhd, ifidx);
2380         DHD_INFO(("%s: set multicast list for if %d\n", __FUNCTION__, ifidx));
2381
2382 done:
2383         DHD_PERIM_UNLOCK(&dhd->pub);
2384         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2385         dhd_net_if_unlock_local(dhd);
2386 }
2387
2388 static int
2389 dhd_set_mac_address(struct net_device *dev, void *addr)
2390 {
2391         int ret = 0;
2392
2393         dhd_info_t *dhd = DHD_DEV_INFO(dev);
2394         struct sockaddr *sa = (struct sockaddr *)addr;
2395         int ifidx;
2396         dhd_if_t *dhdif;
2397
2398         ifidx = dhd_net2idx(dhd, dev);
2399         if (ifidx == DHD_BAD_IF)
2400                 return -1;
2401
2402         dhdif = dhd->iflist[ifidx];
2403
2404         dhd_net_if_lock_local(dhd);
2405         memcpy(dhdif->mac_addr, sa->sa_data, ETHER_ADDR_LEN);
2406         dhdif->set_macaddress = TRUE;
2407         dhd_net_if_unlock_local(dhd);
2408         dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhdif, DHD_WQ_WORK_SET_MAC,
2409                 dhd_set_mac_addr_handler, DHD_WORK_PRIORITY_LOW);
2410         return ret;
2411 }
2412
2413 static void
2414 dhd_set_multicast_list(struct net_device *dev)
2415 {
2416         dhd_info_t *dhd = DHD_DEV_INFO(dev);
2417         int ifidx;
2418
2419         ifidx = dhd_net2idx(dhd, dev);
2420         if (ifidx == DHD_BAD_IF)
2421                 return;
2422
2423         dhd->iflist[ifidx]->set_multicast = TRUE;
2424         dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhd->iflist[ifidx],
2425                 DHD_WQ_WORK_SET_MCAST_LIST, dhd_set_mcast_list_handler, DHD_WORK_PRIORITY_LOW);
2426 }
2427
2428 #ifdef PROP_TXSTATUS
2429 int
2430 dhd_os_wlfc_block(dhd_pub_t *pub)
2431 {
2432         dhd_info_t *di = (dhd_info_t *)(pub->info);
2433         ASSERT(di != NULL);
2434         spin_lock_bh(&di->wlfc_spinlock);
2435         return 1;
2436 }
2437
2438 int
2439 dhd_os_wlfc_unblock(dhd_pub_t *pub)
2440 {
2441         dhd_info_t *di = (dhd_info_t *)(pub->info);
2442
2443         ASSERT(di != NULL);
2444         spin_unlock_bh(&di->wlfc_spinlock);
2445         return 1;
2446 }
2447
2448 #endif /* PROP_TXSTATUS */
2449
2450 #if defined(DHD_8021X_DUMP)
2451 void
2452 dhd_tx_dump(osl_t *osh, void *pkt)
2453 {
2454         uint8 *dump_data;
2455         uint16 protocol;
2456
2457         dump_data = PKTDATA(osh, pkt);
2458         protocol = (dump_data[12] << 8) | dump_data[13];
2459
2460         if (protocol == ETHER_TYPE_802_1X) {
2461                 DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n",
2462                         dump_data[14], dump_data[15], dump_data[30]));
2463         }
2464 }
2465 #endif /* DHD_8021X_DUMP */
2466
2467 int BCMFASTPATH
2468 dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
2469 {
2470         int ret = BCME_OK;
2471         dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
2472         struct ether_header *eh = NULL;
2473         int temp_prio;
2474
2475         DHD_INFO(("skb->prio = %d\n", PKTPRIO(pktbuf)));
2476
2477         /* Reject if down */
2478         if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) {
2479                 /* free the packet here since the caller won't */
2480                 PKTFREE(dhdp->osh, pktbuf, TRUE);
2481                 return -ENODEV;
2482         }
2483
2484 #ifdef PCIE_FULL_DONGLE
2485         if (dhdp->busstate == DHD_BUS_SUSPEND) {
2486                 DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__));
2487                 PKTFREE(dhdp->osh, pktbuf, TRUE);
2488                 return -EBUSY;
2489         }
2490 #endif /* PCIE_FULL_DONGLE */
2491
2492 #ifdef DHD_UNICAST_DHCP
2493         /* if dhcp_unicast is enabled, we need to convert the */
2494         /* broadcast DHCP ACK/REPLY packets to Unicast. */
2495         if (dhdp->dhcp_unicast) {
2496             dhd_convert_dhcp_broadcast_ack_to_unicast(dhdp, pktbuf, ifidx);
2497         }
2498 #endif /* DHD_UNICAST_DHCP */
2499         /* Update multicast statistic */
2500         if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) {
2501                 uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
2502                 eh = (struct ether_header *)pktdata;
2503
2504                 if (ETHER_ISMULTI(eh->ether_dhost))
2505                         dhdp->tx_multicast++;
2506                 if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X)
2507                         atomic_inc(&dhd->pend_8021x_cnt);
2508 #ifdef DHD_DHCP_DUMP
2509                 if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
2510                         uint16 dump_hex;
2511                         uint16 source_port;
2512                         uint16 dest_port;
2513                         uint16 udp_port_pos;
2514                         uint8 *ptr8 = (uint8 *)&pktdata[ETHER_HDR_LEN];
2515                         uint8 ip_header_len = (*ptr8 & 0x0f)<<2;
2516
2517                         udp_port_pos = ETHER_HDR_LEN + ip_header_len;
2518                         source_port = (pktdata[udp_port_pos] << 8) | pktdata[udp_port_pos+1];
2519                         dest_port = (pktdata[udp_port_pos+2] << 8) | pktdata[udp_port_pos+3];
2520                         if (source_port == 0x0044 || dest_port == 0x0044) {
2521                                 dump_hex = (pktdata[udp_port_pos+249] << 8) |
2522                                         pktdata[udp_port_pos+250];
2523                                 if (dump_hex == 0x0101) {
2524                                         DHD_ERROR(("DHCP - DISCOVER [TX]\n"));
2525                                 } else if (dump_hex == 0x0102) {
2526                                         DHD_ERROR(("DHCP - OFFER [TX]\n"));
2527                                 } else if (dump_hex == 0x0103) {
2528                                         DHD_ERROR(("DHCP - REQUEST [TX]\n"));
2529                                 } else if (dump_hex == 0x0105) {
2530                                         DHD_ERROR(("DHCP - ACK [TX]\n"));
2531                                 } else {
2532                                         DHD_ERROR(("DHCP - 0x%X [TX]\n", dump_hex));
2533                                 }
2534                         } else if (source_port == 0x0043 || dest_port == 0x0043) {
2535                                 DHD_ERROR(("DHCP - BOOTP [RX]\n"));
2536                         }
2537                 }
2538 #endif /* DHD_DHCP_DUMP */
2539         } else {
2540                         PKTFREE(dhd->pub.osh, pktbuf, TRUE);
2541                         return BCME_ERROR;
2542         }
2543
2544         /* Look into the packet and update the packet priority */
2545         temp_prio = PKTPRIO(pktbuf);
2546         if (temp_prio & 0x100)
2547                 PKTSETPRIO(pktbuf, temp_prio & 0xFF);
2548 #ifndef PKTPRIO_OVERRIDE
2549         if (PKTPRIO(pktbuf) == 0)
2550 #endif 
2551 #ifdef QOS_MAP_SET
2552                 pktsetprio_qms(pktbuf, wl_get_up_table(), FALSE);
2553 #else
2554                 pktsetprio(pktbuf, FALSE);
2555 #endif /* QOS_MAP_SET */
2556
2557
2558 #if defined(PCIE_FULL_DONGLE) && !defined(PCIE_TX_DEFERRAL)
2559         /*
2560          * Lkup the per interface hash table, for a matching flowring. If one is not
2561          * available, allocate a unique flowid and add a flowring entry.
2562          * The found or newly created flowid is placed into the pktbuf's tag.
2563          */
2564         ret = dhd_flowid_update(dhdp, ifidx, dhdp->flow_prio_map[(PKTPRIO(pktbuf))], pktbuf);
2565         if (ret != BCME_OK) {
2566                 PKTCFREE(dhd->pub.osh, pktbuf, TRUE);
2567                 return ret;
2568         }
2569 #endif
2570
2571 #ifdef PROP_TXSTATUS
2572         if (dhd_wlfc_is_supported(dhdp)) {
2573                 /* store the interface ID */
2574                 DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx);
2575
2576                 /* store destination MAC in the tag as well */
2577                 DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost);
2578
2579                 /* decide which FIFO this packet belongs to */
2580                 if (ETHER_ISMULTI(eh->ether_dhost))
2581                         /* one additional queue index (highest AC + 1) is used for bc/mc queue */
2582                         DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT);
2583                 else
2584                         DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf)));
2585         } else
2586 #endif /* PROP_TXSTATUS */
2587         /* If the protocol uses a data header, apply it */
2588         dhd_prot_hdrpush(dhdp, ifidx, pktbuf);
2589
2590         /* Use bus module to send data frame */
2591 #ifdef WLMEDIA_HTSF
2592         dhd_htsf_addtxts(dhdp, pktbuf);
2593 #endif
2594 #if defined(DHD_8021X_DUMP)
2595         dhd_tx_dump(dhdp->osh, pktbuf);
2596 #endif
2597 #ifdef PROP_TXSTATUS
2598         {
2599                 if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_bus_txdata,
2600                         dhdp->bus, pktbuf, TRUE) == WLFC_UNSUPPORTED) {
2601                         /* non-proptxstatus way */
2602 #ifdef BCMPCIE
2603                         ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx);
2604 #else
2605                         ret = dhd_bus_txdata(dhdp->bus, pktbuf);
2606 #endif /* BCMPCIE */
2607                 }
2608         }
2609 #else
2610 #ifdef BCMPCIE
2611         ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx);
2612 #else
2613         ret = dhd_bus_txdata(dhdp->bus, pktbuf);
2614 #endif /* BCMPCIE */
2615 #endif /* PROP_TXSTATUS */
2616
2617         return ret;
2618 }
2619
2620 int BCMFASTPATH
2621 dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
2622 {
2623         int ret;
2624         uint datalen;
2625         void *pktbuf;
2626         dhd_info_t *dhd = DHD_DEV_INFO(net);
2627         dhd_if_t *ifp = NULL;
2628         int ifidx;
2629 #ifdef WLMEDIA_HTSF
2630         uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz;
2631 #else
2632         uint8 htsfdlystat_sz = 0;
2633 #endif
2634 #ifdef DHD_WMF
2635         struct ether_header *eh;
2636         uint8 *iph;
2637 #endif /* DHD_WMF */
2638
2639         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2640
2641         DHD_OS_WAKE_LOCK(&dhd->pub);
2642         DHD_PERIM_LOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2643
2644         /* Reject if down */
2645         if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) {
2646                 DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n",
2647                         __FUNCTION__, dhd->pub.up, dhd->pub.busstate));
2648                 netif_stop_queue(net);
2649                 /* Send Event when bus down detected during data session */
2650                 if (dhd->pub.up) {
2651                         DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__));
2652                         net_os_send_hang_message(net);
2653                 }
2654                 DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2655                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2656 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
2657                 return -ENODEV;
2658 #else
2659                 return NETDEV_TX_BUSY;
2660 #endif
2661         }
2662
2663         ifp = DHD_DEV_IFP(net);
2664         ifidx = DHD_DEV_IFIDX(net);
2665
2666         ASSERT(ifidx == dhd_net2idx(dhd, net));
2667         ASSERT((ifp != NULL) && (ifp == dhd->iflist[ifidx]));
2668
2669         if (ifidx == DHD_BAD_IF) {
2670                 DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx));
2671                 netif_stop_queue(net);
2672                 DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2673                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2674 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
2675                 return -ENODEV;
2676 #else
2677                 return NETDEV_TX_BUSY;
2678 #endif
2679         }
2680
2681         /* if wifi scan is blocked waiting for tx packet, unblock it */
2682 #ifdef CONFIG_BCMDHD_CUSTOM_SYSFS_TEGRA
2683         TEGRA_SCAN_TX_PKT_CHECK(skb, ifidx)
2684 #endif
2685
2686         /* re-align socket buffer if "skb->data" is odd address */
2687         if (((unsigned long)(skb->data)) & 0x1) {
2688                 unsigned char *data = skb->data;
2689                 uint32 length = skb->len;
2690                 PKTPUSH(dhd->pub.osh, skb, 1);
2691                 memmove(skb->data, data, length);
2692                 PKTSETLEN(dhd->pub.osh, skb, length);
2693         }
2694
2695         datalen  = PKTLEN(dhd->pub.osh, skb);
2696
2697         /* Make sure there's enough room for any header */
2698
2699         if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) {
2700                 struct sk_buff *skb2;
2701
2702                 DHD_INFO(("%s: insufficient headroom\n",
2703                           dhd_ifname(&dhd->pub, ifidx)));
2704                 dhd->pub.tx_realloc++;
2705
2706                 skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz);
2707
2708                 dev_kfree_skb(skb);
2709                 if ((skb = skb2) == NULL) {
2710                         DHD_ERROR(("%s: skb_realloc_headroom failed\n",
2711                                    dhd_ifname(&dhd->pub, ifidx)));
2712                         ret = -ENOMEM;
2713                         goto done;
2714                 }
2715         }
2716
2717 #ifdef CONFIG_BCMDHD_CUSTOM_SYSFS_TEGRA
2718         tegra_sysfs_histogram_tcpdump_tx(skb, __func__, __LINE__);
2719 #endif
2720
2721         /* Convert to packet */
2722         if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) {
2723                 DHD_ERROR(("%s: PKTFRMNATIVE failed\n",
2724                            dhd_ifname(&dhd->pub, ifidx)));
2725                 dev_kfree_skb_any(skb);
2726                 ret = -ENOMEM;
2727                 goto done;
2728         }
2729 #ifdef WLMEDIA_HTSF
2730         if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) {
2731                 uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf);
2732                 struct ether_header *eh = (struct ether_header *)pktdata;
2733
2734                 if (!ETHER_ISMULTI(eh->ether_dhost) &&
2735                         (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) {
2736                         eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS);
2737                 }
2738         }
2739 #endif
2740 #ifdef DHD_WMF
2741         eh = (struct ether_header *)PKTDATA(dhd->pub.osh, pktbuf);
2742         iph = (uint8 *)eh + ETHER_HDR_LEN;
2743
2744         /* WMF processing for multicast packets
2745          * Only IPv4 packets are handled
2746          */
2747         if (ifp->wmf.wmf_enable && (ntoh16(eh->ether_type) == ETHER_TYPE_IP) &&
2748                 (IP_VER(iph) == IP_VER_4) && (ETHER_ISMULTI(eh->ether_dhost) ||
2749                 ((IPV4_PROT(iph) == IP_PROT_IGMP) && dhd->pub.wmf_ucast_igmp))) {
2750 #if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP)
2751                 void *sdu_clone;
2752                 bool ucast_convert = FALSE;
2753 #ifdef DHD_UCAST_UPNP
2754                 uint32 dest_ip;
2755
2756                 dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET)));
2757                 ucast_convert = dhd->pub.wmf_ucast_upnp && MCAST_ADDR_UPNP_SSDP(dest_ip);
2758 #endif /* DHD_UCAST_UPNP */
2759 #ifdef DHD_IGMP_UCQUERY
2760                 ucast_convert |= dhd->pub.wmf_ucast_igmp_query &&
2761                         (IPV4_PROT(iph) == IP_PROT_IGMP) &&
2762                         (*(iph + IPV4_HLEN(iph)) == IGMPV2_HOST_MEMBERSHIP_QUERY);
2763 #endif /* DHD_IGMP_UCQUERY */
2764                 if (ucast_convert) {
2765                         dhd_sta_t *sta;
2766                         unsigned long flags;
2767
2768                         DHD_IF_STA_LIST_LOCK(ifp, flags);
2769
2770                         /* Convert upnp/igmp query to unicast for each assoc STA */
2771                         list_for_each_entry(sta, &ifp->sta_list, list) {
2772                                 if ((sdu_clone = PKTDUP(dhd->pub.osh, pktbuf)) == NULL) {
2773                                         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
2774                                         DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2775                                         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2776                                         return (WMF_NOP);
2777                                 }
2778                                 dhd_wmf_forward(ifp->wmf.wmfh, sdu_clone, 0, sta, 1);
2779                         }
2780
2781                         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
2782                         DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2783                         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2784
2785                         PKTFREE(dhd->pub.osh, pktbuf, TRUE);
2786                         return NETDEV_TX_OK;
2787                 } else
2788 #endif /* defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) */
2789                 {
2790                         /* There will be no STA info if the packet is coming from LAN host
2791                          * Pass as NULL
2792                          */
2793                         ret = dhd_wmf_packets_handle(&dhd->pub, pktbuf, NULL, ifidx, 0);
2794                         switch (ret) {
2795                         case WMF_TAKEN:
2796                         case WMF_DROP:
2797                                 /* Either taken by WMF or we should drop it.
2798                                  * Exiting send path
2799                                  */
2800                                 DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2801                                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2802                                 return NETDEV_TX_OK;
2803                         default:
2804                                 /* Continue the transmit path */
2805                                 break;
2806                         }
2807                 }
2808         }
2809 #endif /* DHD_WMF */
2810
2811 #ifdef DHDTCPACK_SUPPRESS
2812         if (dhd->pub.tcpack_sup_mode == TCPACK_SUP_HOLD) {
2813                 /* If this packet has been hold or got freed, just return */
2814                 if (dhd_tcpack_hold(&dhd->pub, pktbuf, ifidx)) {
2815                         ret = 0;
2816                         goto done;
2817                 }
2818         } else {
2819                 /* If this packet has replaced another packet and got freed, just return */
2820                 if (dhd_tcpack_suppress(&dhd->pub, pktbuf)) {
2821                         ret = 0;
2822                         goto done;
2823                 }
2824         }
2825 #endif /* DHDTCPACK_SUPPRESS */
2826
2827         ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf);
2828
2829 done:
2830         if (ret) {
2831                 ifp->stats.tx_dropped++;
2832                 dhd->pub.tx_dropped++;
2833         }
2834         else {
2835
2836 #ifdef PROP_TXSTATUS
2837                 /* tx_packets counter can counted only when wlfc is disabled */
2838                 if (!dhd_wlfc_is_supported(&dhd->pub))
2839 #endif
2840                 {
2841                         dhd->pub.tx_packets++;
2842                         ifp->stats.tx_packets++;
2843                         ifp->stats.tx_bytes += datalen;
2844                 }
2845         }
2846
2847         DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2848         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2849
2850         /* Return ok: we always eat the packet */
2851 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
2852         return 0;
2853 #else
2854         return NETDEV_TX_OK;
2855 #endif
2856 }
2857
2858
2859 void
2860 dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state)
2861 {
2862         struct net_device *net;
2863         dhd_info_t *dhd = dhdp->info;
2864         int i;
2865
2866         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2867
2868         ASSERT(dhd);
2869
2870         if (ifidx == ALL_INTERFACES) {
2871                 /* Flow control on all active interfaces */
2872                 dhdp->txoff = state;
2873                 for (i = 0; i < DHD_MAX_IFS; i++) {
2874                         if (dhd->iflist[i]) {
2875                                 net = dhd->iflist[i]->net;
2876                                 if (state == ON)
2877                                         netif_stop_queue(net);
2878                                 else
2879                                         netif_wake_queue(net);
2880                         }
2881                 }
2882         }
2883         else {
2884                 if (dhd->iflist[ifidx]) {
2885                         net = dhd->iflist[ifidx]->net;
2886                         if (state == ON)
2887                                 netif_stop_queue(net);
2888                         else
2889                                 netif_wake_queue(net);
2890                 }
2891         }
2892 }
2893
2894 #ifdef DHD_RX_DUMP
2895 typedef struct {
2896         uint16 type;
2897         const char *str;
2898 } PKTTYPE_INFO;
2899
2900 static const PKTTYPE_INFO packet_type_info[] =
2901 {
2902         { ETHER_TYPE_IP, "IP" },
2903         { ETHER_TYPE_ARP, "ARP" },
2904         { ETHER_TYPE_BRCM, "BRCM" },
2905         { ETHER_TYPE_802_1X, "802.1X" },
2906         { ETHER_TYPE_WAI, "WAPI" },
2907         { 0, ""}
2908 };
2909
2910 static const char *_get_packet_type_str(uint16 type)
2911 {
2912         int i;
2913         int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1;
2914
2915         for (i = 0; i < n; i++) {
2916                 if (packet_type_info[i].type == type)
2917                         return packet_type_info[i].str;
2918         }
2919
2920         return packet_type_info[n].str;
2921 }
2922 #endif /* DHD_RX_DUMP */
2923
2924
2925 #ifdef DHD_WMF
2926 bool
2927 dhd_is_rxthread_enabled(dhd_pub_t *dhdp)
2928 {
2929         dhd_info_t *dhd = dhdp->info;
2930
2931         return dhd->rxthread_enabled;
2932 }
2933 #endif /* DHD_WMF */
2934
2935 void
2936 dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
2937 {
2938         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
2939         struct sk_buff *skb;
2940         uchar *eth;
2941         uint len;
2942         void *data, *pnext = NULL;
2943         int i;
2944         dhd_if_t *ifp;
2945         wl_event_msg_t event;
2946         int tout_rx = 0;
2947         int tout_ctrl = 0;
2948         void *skbhead = NULL;
2949         void *skbprev = NULL;
2950 #if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP)
2951         char *dump_data;
2952         uint16 protocol;
2953 #endif /* DHD_RX_DUMP || DHD_8021X_DUMP */
2954
2955         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2956
2957         for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) {
2958                 struct ether_header *eh;
2959
2960                 pnext = PKTNEXT(dhdp->osh, pktbuf);
2961                 PKTSETNEXT(dhdp->osh, pktbuf, NULL);
2962
2963                 ifp = dhd->iflist[ifidx];
2964                 if (ifp == NULL) {
2965                         DHD_ERROR(("%s: ifp is NULL. drop packet\n",
2966                                 __FUNCTION__));
2967                         PKTCFREE(dhdp->osh, pktbuf, FALSE);
2968                         continue;
2969                 }
2970
2971                 eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf);
2972
2973                 /* Dropping only data packets before registering net device to avoid kernel panic */
2974 #ifndef PROP_TXSTATUS_VSDB
2975                 if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) &&
2976                         (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) {
2977 #else
2978                 if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || (bcmdhd_prop_txstatus_vsdb && !dhd->pub.up)) &&
2979                         (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) {
2980 #endif /* PROP_TXSTATUS_VSDB */
2981                         DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n",
2982                         __FUNCTION__));
2983                         PKTCFREE(dhdp->osh, pktbuf, FALSE);
2984                         continue;
2985                 }
2986
2987
2988 #ifdef PROP_TXSTATUS
2989                 if (dhd_wlfc_is_header_only_pkt(dhdp, pktbuf)) {
2990                         /* WLFC may send header only packet when
2991                         there is an urgent message but no packet to
2992                         piggy-back on
2993                         */
2994                         PKTCFREE(dhdp->osh, pktbuf, FALSE);
2995                         continue;
2996                 }
2997 #endif
2998 #ifdef DHD_L2_FILTER
2999                 /* If block_ping is enabled drop the ping packet */
3000                 if (dhdp->block_ping) {
3001                         if (dhd_l2_filter_block_ping(dhdp, pktbuf, ifidx) == BCME_OK) {
3002                                 PKTFREE(dhdp->osh, pktbuf, FALSE);
3003                                 continue;
3004                         }
3005                 }
3006 #endif
3007 #ifdef DHD_WMF
3008                 /* WMF processing for multicast packets */
3009                 if (ifp->wmf.wmf_enable && (ETHER_ISMULTI(eh->ether_dhost))) {
3010                         dhd_sta_t *sta;
3011                         int ret;
3012
3013                         sta = dhd_find_sta(dhdp, ifidx, (void *)eh->ether_shost);
3014                         ret = dhd_wmf_packets_handle(dhdp, pktbuf, sta, ifidx, 1);
3015                         switch (ret) {
3016                                 case WMF_TAKEN:
3017                                         /* The packet is taken by WMF. Continue to next iteration */
3018                                         continue;
3019                                 case WMF_DROP:
3020                                         /* Packet DROP decision by WMF. Toss it */
3021                                         DHD_ERROR(("%s: WMF decides to drop packet\n",
3022                                                 __FUNCTION__));
3023                                         PKTCFREE(dhdp->osh, pktbuf, FALSE);
3024                                         continue;
3025                                 default:
3026                                         /* Continue the transmit path */
3027                                         break;
3028                         }
3029                 }
3030 #endif /* DHD_WMF */
3031 #ifdef DHDTCPACK_SUPPRESS
3032                 dhd_tcpdata_info_get(dhdp, pktbuf);
3033 #endif
3034                 skb = PKTTONATIVE(dhdp->osh, pktbuf);
3035
3036                 ifp = dhd->iflist[ifidx];
3037                 if (ifp == NULL)
3038                         ifp = dhd->iflist[0];
3039
3040                 ASSERT(ifp);
3041                 skb->dev = ifp->net;
3042
3043 #ifdef PCIE_FULL_DONGLE
3044                 if ((DHD_IF_ROLE_AP(dhdp, ifidx) || DHD_IF_ROLE_P2PGO(dhdp, ifidx)) &&
3045                         (!ifp->ap_isolate)) {
3046                         eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf);
3047                         if (ETHER_ISUCAST(eh->ether_dhost)) {
3048                                 if (dhd_find_sta(dhdp, ifidx, (void *)eh->ether_dhost)) {
3049                                         dhd_sendpkt(dhdp, ifidx, pktbuf);
3050                                         continue;
3051                                 }
3052                         } else {
3053                                 void *npktbuf = PKTDUP(dhdp->osh, pktbuf);
3054                                 dhd_sendpkt(dhdp, ifidx, npktbuf);
3055                         }
3056                 }
3057 #endif /* PCIE_FULL_DONGLE */
3058
3059                 /* Get the protocol, maintain skb around eth_type_trans()
3060                  * The main reason for this hack is for the limitation of
3061                  * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len'
3062                  * to perform skb_pull inside vs ETH_HLEN. Since to avoid
3063                  * coping of the packet coming from the network stack to add
3064                  * BDC, Hardware header etc, during network interface registration
3065                  * we set the 'net->hard_header_len' to ETH_HLEN + extra space required
3066                  * for BDC, Hardware header etc. and not just the ETH_HLEN
3067                  */
3068                 eth = skb->data;
3069                 len = skb->len;
3070
3071 #if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) || defined(DHD_DHCP_DUMP)
3072                 dump_data = skb->data;
3073                 protocol = (dump_data[12] << 8) | dump_data[13];
3074 #endif /* DHD_RX_DUMP || DHD_8021X_DUMP || DHD_DHCP_DUMP */
3075 #ifdef DHD_8021X_DUMP
3076                 if (protocol == ETHER_TYPE_802_1X) {
3077                         DHD_ERROR(("ETHER_TYPE_802_1X [RX]: "
3078                                 "ver %d, type %d, replay %d\n",
3079                                 dump_data[14], dump_data[15],
3080                                 dump_data[30]));
3081                 }
3082 #endif /* DHD_8021X_DUMP */
3083 #ifdef DHD_DHCP_DUMP
3084                 if (protocol != ETHER_TYPE_BRCM && protocol == ETHER_TYPE_IP) {
3085                         uint16 dump_hex;
3086                         uint16 source_port;
3087                         uint16 dest_port;
3088                         uint16 udp_port_pos;
3089                         uint8 *ptr8 = (uint8 *)&dump_data[ETHER_HDR_LEN];
3090                         uint8 ip_header_len = (*ptr8 & 0x0f)<<2;
3091
3092                         udp_port_pos = ETHER_HDR_LEN + ip_header_len;
3093                         source_port = (dump_data[udp_port_pos] << 8) | dump_data[udp_port_pos+1];
3094                         dest_port = (dump_data[udp_port_pos+2] << 8) | dump_data[udp_port_pos+3];
3095                         if (source_port == 0x0044 || dest_port == 0x0044) {
3096                                 dump_hex = (dump_data[udp_port_pos+249] << 8) |
3097                                         dump_data[udp_port_pos+250];
3098                                 if (dump_hex == 0x0101) {
3099                                         DHD_ERROR(("DHCP - DISCOVER [RX]\n"));
3100                                 } else if (dump_hex == 0x0102) {
3101                                         DHD_ERROR(("DHCP - OFFER [RX]\n"));
3102                                 } else if (dump_hex == 0x0103) {
3103                                         DHD_ERROR(("DHCP - REQUEST [RX]\n"));
3104                                 } else if (dump_hex == 0x0105) {
3105                                         DHD_ERROR(("DHCP - ACK [RX]\n"));
3106                                 } else {
3107                                         DHD_ERROR(("DHCP - 0x%X [RX]\n", dump_hex));
3108                                 }
3109                         } else if (source_port == 0x0043 || dest_port == 0x0043) {
3110                                 DHD_ERROR(("DHCP - BOOTP [RX]\n"));
3111                         }
3112                 }
3113 #endif /* DHD_DHCP_DUMP */
3114 #if defined(DHD_RX_DUMP)
3115                 DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol)));
3116                 if (protocol != ETHER_TYPE_BRCM) {
3117                         if (dump_data[0] == 0xFF) {
3118                                 DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__));
3119
3120                                 if ((dump_data[12] == 8) &&
3121                                         (dump_data[13] == 6)) {
3122                                         DHD_ERROR(("%s: ARP %d\n",
3123                                                 __FUNCTION__, dump_data[0x15]));
3124                                 }
3125                         } else if (dump_data[0] & 1) {
3126                                 DHD_ERROR(("%s: MULTICAST: " MACDBG "\n",
3127                                         __FUNCTION__, MAC2STRDBG(dump_data)));
3128                         }
3129 #ifdef DHD_RX_FULL_DUMP
3130                         {
3131                                 int k;
3132                                 for (k = 0; k < skb->len; k++) {
3133                                         DHD_ERROR(("%02X ", dump_data[k]));
3134                                         if ((k & 15) == 15)
3135                                                 DHD_ERROR(("\n"));
3136                                 }
3137                                 DHD_ERROR(("\n"));
3138                         }
3139 #endif /* DHD_RX_FULL_DUMP */
3140                 }
3141 #endif /* DHD_RX_DUMP */
3142
3143                 skb->protocol = eth_type_trans(skb, skb->dev);
3144
3145                 if (skb->pkt_type == PACKET_MULTICAST) {
3146                         dhd->pub.rx_multicast++;
3147                         ifp->stats.multicast++;
3148                 }
3149
3150                 skb->data = eth;
3151                 skb->len = len;
3152
3153 #ifdef WLMEDIA_HTSF
3154                 dhd_htsf_addrxts(dhdp, pktbuf);
3155 #endif
3156                 /* Strip header, count, deliver upward */
3157                 RX_CAPTURE(skb);
3158                 skb_pull(skb, ETH_HLEN);
3159
3160                 /* Process special event packets and then discard them */
3161                 memset(&event, 0, sizeof(event));
3162                 if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) {
3163                         dhd_wl_host_event(dhd, &ifidx,
3164 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
3165                         skb_mac_header(skb),
3166 #else
3167                         skb->mac.raw,
3168 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */
3169                         &event,
3170                         &data);
3171
3172                         wl_event_to_host_order(&event);
3173                         if (!tout_ctrl)
3174                                 tout_ctrl = DHD_PACKET_TIMEOUT_MS;
3175
3176 #if defined(PNO_SUPPORT)
3177                         if (event.event_type == WLC_E_PFN_NET_FOUND) {
3178                                 /* enforce custom wake lock to garantee that Kernel not suspended */
3179                                 tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS;
3180                         }
3181 #endif /* PNO_SUPPORT */
3182
3183 #ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT
3184                         PKTFREE(dhdp->osh, pktbuf, FALSE);
3185                         continue;
3186 #endif /* DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */
3187                 } else {
3188                         tout_rx = DHD_PACKET_TIMEOUT_MS;
3189
3190 #ifdef PROP_TXSTATUS
3191                         dhd_wlfc_save_rxpath_ac_time(dhdp, (uint8)PKTPRIO(skb));
3192 #endif /* PROP_TXSTATUS */
3193                 }
3194
3195                 ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
3196                 ifp = dhd->iflist[ifidx];
3197
3198                 if (ifp->net)
3199                         ifp->net->last_rx = jiffies;
3200
3201                 if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) {
3202                         dhdp->dstats.rx_bytes += skb->len;
3203                         dhdp->rx_packets++; /* Local count */
3204                         ifp->stats.rx_bytes += skb->len;
3205                         ifp->stats.rx_packets++;
3206                 }
3207
3208                 if (in_interrupt()) {
3209                         netif_rx(skb);
3210                 } else {
3211                         if (dhd->rxthread_enabled) {
3212                                 if (!skbhead)
3213                                         skbhead = skb;
3214                                 else
3215                                         PKTSETNEXT(dhdp->osh, skbprev, skb);
3216                                 skbprev = skb;
3217                         } else {
3218
3219                                 /* If the receive is not processed inside an ISR,
3220                                  * the softirqd must be woken explicitly to service
3221                                  * the NET_RX_SOFTIRQ.  In 2.6 kernels, this is handled
3222                                  * by netif_rx_ni(), but in earlier kernels, we need
3223                                  * to do it manually.
3224                                  */
3225 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
3226                                 netif_rx_ni(skb);
3227 #else
3228                                 ulong flags;
3229                                 netif_rx(skb);
3230                                 local_irq_save(flags);
3231                                 RAISE_RX_SOFTIRQ();
3232                                 local_irq_restore(flags);
3233 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
3234                         }
3235                 }
3236         }
3237
3238         if (dhd->rxthread_enabled && skbhead)
3239                 dhd_sched_rxf(dhdp, skbhead);
3240
3241         DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx);
3242         DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl);
3243 }
3244
3245 void
3246 dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx)
3247 {
3248         /* Linux version has nothing to do */
3249         return;
3250 }
3251
3252 void
3253 dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success)
3254 {
3255         dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
3256         struct ether_header *eh;
3257         uint16 type;
3258 #ifdef PROP_TXSTATUS
3259         dhd_if_t *ifp = dhd->iflist[DHD_PKTTAG_IF(PKTTAG(txp))];
3260 #endif
3261
3262         dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL);
3263
3264         eh = (struct ether_header *)PKTDATA(dhdp->osh, txp);
3265         type  = ntoh16(eh->ether_type);
3266
3267         if (type == ETHER_TYPE_802_1X)
3268                 atomic_dec(&dhd->pend_8021x_cnt);
3269
3270 #ifdef PROP_TXSTATUS
3271         ASSERT(ifp);
3272         if ( (ifp != NULL) && dhdp->wlfc_state && (dhdp->proptxstatus_mode != WLFC_FCMODE_NONE)) {
3273                 uint datalen  = PKTLEN(dhd->pub.osh, txp);
3274
3275                 if (success) {
3276                         dhd->pub.tx_packets++;
3277                         ifp->stats.tx_packets++;
3278                         ifp->stats.tx_bytes += datalen;
3279                 } else {
3280                         ifp->stats.tx_dropped++;
3281                 }
3282         }
3283 #endif
3284 }
3285
3286 static struct net_device_stats *
3287 dhd_get_stats(struct net_device *net)
3288 {
3289         dhd_info_t *dhd = DHD_DEV_INFO(net);
3290         dhd_if_t *ifp;
3291         int ifidx;
3292
3293         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3294
3295         ifidx = dhd_net2idx(dhd, net);
3296         if (ifidx == DHD_BAD_IF) {
3297                 DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__));
3298
3299                 memset(&net->stats, 0, sizeof(net->stats));
3300                 return &net->stats;
3301         }
3302
3303         ifp = dhd->iflist[ifidx];
3304         ASSERT(dhd && ifp);
3305
3306         if (dhd->pub.up) {
3307                 /* Use the protocol to get dongle stats */
3308                 dhd_prot_dstats(&dhd->pub);
3309         }
3310         return &ifp->stats;
3311 }
3312
3313 static int
3314 dhd_watchdog_thread(void *data)
3315 {
3316         tsk_ctl_t *tsk = (tsk_ctl_t *)data;
3317         dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
3318         /* This thread doesn't need any user-level access,
3319          * so get rid of all our resources
3320          */
3321         if (dhd_watchdog_prio > 0) {
3322                 struct sched_param param;
3323                 param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)?
3324                         dhd_watchdog_prio:(MAX_RT_PRIO-1);
3325                 setScheduler(current, SCHED_FIFO, &param);
3326         }
3327
3328         while (1)
3329                 if (down_interruptible (&tsk->sema) == 0) {
3330                         unsigned long flags;
3331                         unsigned long jiffies_at_start = jiffies;
3332                         unsigned long time_lapse;
3333
3334                         SMP_RD_BARRIER_DEPENDS();
3335                         if (tsk->terminated) {
3336                                 break;
3337                         }
3338
3339                         if (dhd->pub.dongle_reset == FALSE) {
3340                                 DHD_TIMER(("%s:\n", __FUNCTION__));
3341
3342                                 /* Call the bus module watchdog */
3343                                 dhd_bus_watchdog(&dhd->pub);
3344
3345
3346                                 DHD_GENERAL_LOCK(&dhd->pub, flags);
3347                                 /* Count the tick for reference */
3348                                 dhd->pub.tickcnt++;
3349                                 time_lapse = jiffies - jiffies_at_start;
3350
3351                                 /* Reschedule the watchdog */
3352                                 if (dhd->wd_timer_valid)
3353                                         mod_timer(&dhd->timer,
3354                                             jiffies +
3355                                             msecs_to_jiffies(dhd_watchdog_ms) -
3356                                             min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse));
3357                                         DHD_GENERAL_UNLOCK(&dhd->pub, flags);
3358                                 }
3359                 } else {
3360                         break;
3361         }
3362
3363         complete_and_exit(&tsk->completed, 0);
3364 }
3365
3366 static void dhd_watchdog(ulong data)
3367 {
3368         dhd_info_t *dhd = (dhd_info_t *)data;
3369         unsigned long flags;
3370
3371         if (dhd->pub.dongle_reset) {
3372                 return;
3373         }
3374
3375         if (dhd->thr_wdt_ctl.thr_pid >= 0) {
3376                 up(&dhd->thr_wdt_ctl.sema);
3377                 return;
3378         }
3379
3380         /* Call the bus module watchdog */
3381         dhd_bus_watchdog(&dhd->pub);
3382
3383         DHD_GENERAL_LOCK(&dhd->pub, flags);
3384         /* Count the tick for reference */
3385         dhd->pub.tickcnt++;
3386
3387         /* Reschedule the watchdog */
3388         if (dhd->wd_timer_valid)
3389                 mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms));
3390         DHD_GENERAL_UNLOCK(&dhd->pub, flags);
3391
3392 }
3393
3394 #ifdef ENABLE_ADAPTIVE_SCHED
3395 static void
3396 dhd_sched_policy(int prio)
3397 {
3398         struct sched_param param;
3399         if (cpufreq_quick_get(0) <= CUSTOM_CPUFREQ_THRESH) {
3400                 param.sched_priority = 0;
3401                 setScheduler(current, SCHED_NORMAL, &param);
3402         } else {
3403                 if (get_scheduler_policy(current) != SCHED_FIFO) {
3404                         param.sched_priority = DHD_DEFAULT_RT_PRIORITY;
3405                         setScheduler(current, SCHED_FIFO, &param);
3406                 }
3407         }
3408 }
3409 #endif /* ENABLE_ADAPTIVE_SCHED */
3410 #ifdef DEBUG_CPU_FREQ
3411 static int dhd_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
3412 {
3413         dhd_info_t *dhd = container_of(nb, struct dhd_info, freq_trans);
3414         struct cpufreq_freqs *freq = data;
3415         if (dhd) {
3416                 if (!dhd->new_freq)
3417                         goto exit;
3418                 if (val == CPUFREQ_POSTCHANGE) {
3419                         DHD_ERROR(("cpu freq is changed to %u kHZ on CPU %d\n",
3420                                 freq->new, freq->cpu));
3421                         *per_cpu_ptr(dhd->new_freq, freq->cpu) = freq->new;
3422                 }
3423         }
3424 exit:
3425         return 0;
3426 }
3427 #endif /* DEBUG_CPU_FREQ */
3428 static int
3429 dhd_dpc_thread(void *data)
3430 {
3431         unsigned long timeout;
3432         unsigned int loopcnt, count;
3433         tsk_ctl_t *tsk = (tsk_ctl_t *)data;
3434         dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
3435
3436         /* This thread doesn't need any user-level access,
3437          * so get rid of all our resources
3438          */
3439         if (dhd_dpc_prio > 0)
3440         {
3441                 struct sched_param param;
3442                 param.sched_priority = DHD_DEFAULT_RT_PRIORITY;
3443                 setScheduler(current, SCHED_FIFO, &param);
3444         }
3445
3446 #ifdef CUSTOM_DPC_CPUCORE
3447         set_cpus_allowed_ptr(current, cpumask_of(CUSTOM_DPC_CPUCORE));
3448 #endif
3449 #ifdef CUSTOM_SET_CPUCORE
3450         dhd->pub.current_dpc = current;
3451 #endif /* CUSTOM_SET_CPUCORE */
3452         /* Run until signal received */
3453         while (1) {
3454                 if (!binary_sema_down(tsk)) {
3455 #ifdef ENABLE_ADAPTIVE_SCHED
3456                         dhd_sched_policy(dhd_dpc_prio);
3457 #endif /* ENABLE_ADAPTIVE_SCHED */
3458                         SMP_RD_BARRIER_DEPENDS();
3459                         if (tsk->terminated) {
3460                                 break;
3461                         }
3462
3463                         /* Call bus dpc unless it indicated down (then clean stop) */
3464                         if (dhd->pub.busstate != DHD_BUS_DOWN) {
3465                                 dhd_os_wd_timer_extend(&dhd->pub, TRUE);
3466                                 timeout = jiffies + msecs_to_jiffies(100);
3467                                 loopcnt = 0;
3468                                 count = 0;
3469                                 /* DPC_CAPTURE(); */
3470                                 while (dhd_bus_dpc(dhd->pub.bus)) {
3471                                         ++loopcnt;
3472                                         if (time_after(jiffies, timeout) &&
3473                                                 (loopcnt % 1000 == 0)) {
3474                                                 count++;
3475                                                 timeout = jiffies +
3476                                                         msecs_to_jiffies(100);
3477                                         }
3478                                         /* process all data */
3479                                 }
3480                                 if (count)
3481                                         DHD_ERROR(("%s is consuming too much time"
3482                                                 " Looped %u times for 1000 iterations in 100ms timeout\n",
3483                                                 __func__, count));
3484                                 dhd_os_wd_timer_extend(&dhd->pub, FALSE);
3485                                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3486
3487                         } else {
3488                                 if (dhd->pub.up)
3489                                         dhd_bus_stop(dhd->pub.bus, TRUE);
3490                                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3491                         }
3492                 }
3493                 else
3494                         break;
3495         }
3496         complete_and_exit(&tsk->completed, 0);
3497 }
3498
3499 static int
3500 dhd_rxf_thread(void *data)
3501 {
3502         tsk_ctl_t *tsk = (tsk_ctl_t *)data;
3503         dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
3504 #if defined(WAIT_DEQUEUE)
3505 #define RXF_WATCHDOG_TIME 250 /* BARK_TIME(1000) /  */
3506         ulong watchdogTime = OSL_SYSUPTIME(); /* msec */
3507 #endif
3508         dhd_pub_t *pub = &dhd->pub;
3509
3510         /* This thread doesn't need any user-level access,
3511          * so get rid of all our resources
3512          */
3513         if (dhd_rxf_prio > 0)
3514         {
3515                 struct sched_param param;
3516                 param.sched_priority = DHD_DEFAULT_RT_PRIORITY;
3517                 setScheduler(current, SCHED_FIFO, &param);
3518         }
3519
3520         DAEMONIZE("dhd_rxf");
3521         /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below  */
3522
3523         /*  signal: thread has started */
3524         complete(&tsk->completed);
3525 #ifdef CUSTOM_SET_CPUCORE
3526         dhd->pub.current_rxf = current;
3527 #endif /* CUSTOM_SET_CPUCORE */
3528         /* Run until signal received */
3529         while (1) {
3530                 if (down_interruptible(&tsk->sema) == 0) {
3531                         void *skb;
3532 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
3533                         ulong flags;
3534 #endif
3535 #ifdef ENABLE_ADAPTIVE_SCHED
3536                         dhd_sched_policy(dhd_rxf_prio);
3537 #endif /* ENABLE_ADAPTIVE_SCHED */
3538
3539                         SMP_RD_BARRIER_DEPENDS();
3540
3541                         if (tsk->terminated) {
3542                                 break;
3543                         }
3544                         skb = dhd_rxf_dequeue(pub);
3545
3546                         if (skb == NULL) {
3547                                 continue;
3548                         }
3549                         while (skb) {
3550                                 void *skbnext = PKTNEXT(pub->osh, skb);
3551                                 PKTSETNEXT(pub->osh, skb, NULL);
3552
3553 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
3554                                 netif_rx_ni(skb);
3555 #else
3556                                 netif_rx(skb);
3557                                 local_irq_save(flags);
3558                                 RAISE_RX_SOFTIRQ();
3559                                 local_irq_restore(flags);
3560
3561 #endif
3562                                 skb = skbnext;
3563                         }
3564 #if defined(WAIT_DEQUEUE)
3565                         if (OSL_SYSUPTIME() - watchdogTime > RXF_WATCHDOG_TIME) {
3566                                 OSL_SLEEP(1);
3567                                 watchdogTime = OSL_SYSUPTIME();
3568                         }
3569 #endif
3570
3571                         DHD_OS_WAKE_UNLOCK(pub);
3572                 }
3573                 else
3574                         break;
3575         }
3576         complete_and_exit(&tsk->completed, 0);
3577 }
3578
3579 #ifdef BCMPCIE
3580 void dhd_dpc_kill(dhd_pub_t *dhdp)
3581 {
3582         dhd_info_t *dhd;
3583
3584         if (!dhdp)
3585                 return;
3586
3587         dhd = dhdp->info;
3588
3589         if (!dhd)
3590                 return;
3591
3592         tasklet_kill(&dhd->tasklet);
3593         DHD_ERROR(("%s: tasklet disabled\n", __FUNCTION__));
3594 }
3595 #endif /* BCMPCIE */
3596
3597 static void
3598 dhd_dpc(ulong data)
3599 {
3600         dhd_info_t *dhd;
3601
3602         dhd = (dhd_info_t *)data;
3603
3604         /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c]
3605          * down below , wake lock is set,
3606          * the tasklet is initialized in dhd_attach()
3607          */
3608         /* Call bus dpc unless it indicated down (then clean stop) */
3609         if (dhd->pub.busstate != DHD_BUS_DOWN) {
3610                 if (dhd_bus_dpc(dhd->pub.bus))
3611                         tasklet_schedule(&dhd->tasklet);
3612                 else
3613                         DHD_OS_WAKE_UNLOCK(&dhd->pub);
3614         } else {
3615                 dhd_bus_stop(dhd->pub.bus, TRUE);
3616                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3617         }
3618 }
3619
3620 void
3621 dhd_sched_dpc(dhd_pub_t *dhdp)
3622 {
3623         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
3624
3625         DHD_OS_WAKE_LOCK(dhdp);
3626         if (dhd->thr_dpc_ctl.thr_pid >= 0) {
3627                 /* If the semaphore does not get up,
3628                 * wake unlock should be done here
3629                 */
3630                 if (!binary_sema_up(&dhd->thr_dpc_ctl))
3631                         DHD_OS_WAKE_UNLOCK(dhdp);
3632                 return;
3633         } else {
3634                 tasklet_schedule(&dhd->tasklet);
3635         }
3636 }
3637
3638 static void
3639 dhd_sched_rxf(dhd_pub_t *dhdp, void *skb)
3640 {
3641         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
3642 #ifdef RXF_DEQUEUE_ON_BUSY
3643         int ret = BCME_OK;
3644         int retry = 2;
3645 #endif /* RXF_DEQUEUE_ON_BUSY */
3646
3647         DHD_OS_WAKE_LOCK(dhdp);
3648
3649         DHD_TRACE(("dhd_sched_rxf: Enter\n"));
3650 #ifdef RXF_DEQUEUE_ON_BUSY
3651         do {
3652                 ret = dhd_rxf_enqueue(dhdp, skb);
3653                 if (ret == BCME_OK || ret == BCME_ERROR)
3654                         break;
3655                 else
3656                         OSL_SLEEP(50); /* waiting for dequeueing */
3657         } while (retry-- > 0);
3658
3659         if (retry <= 0 && ret == BCME_BUSY) {
3660                 void *skbp = skb;
3661
3662                 while (skbp) {
3663                         void *skbnext = PKTNEXT(dhdp->osh, skbp);
3664                         PKTSETNEXT(dhdp->osh, skbp, NULL);
3665                         netif_rx_ni(skbp);
3666                         skbp = skbnext;
3667                 }
3668                 DHD_ERROR(("send skb to kernel backlog without rxf_thread\n"));
3669         }
3670         else {
3671                 if (dhd->thr_rxf_ctl.thr_pid >= 0) {
3672                         up(&dhd->thr_rxf_ctl.sema);
3673                 }
3674         }
3675 #else /* RXF_DEQUEUE_ON_BUSY */
3676         do {
3677                 if (dhd_rxf_enqueue(dhdp, skb) == BCME_OK)
3678                         break;
3679         } while (1);
3680         if (dhd->thr_rxf_ctl.thr_pid >= 0) {
3681                 up(&dhd->thr_rxf_ctl.sema);
3682         }
3683         return;
3684 #endif /* RXF_DEQUEUE_ON_BUSY */
3685 }
3686
3687 #ifdef TOE
3688 /* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */
3689 static int
3690 dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol)
3691 {
3692         wl_ioctl_t ioc;
3693         char buf[32];
3694         int ret;
3695
3696         memset(&ioc, 0, sizeof(ioc));
3697
3698         ioc.cmd = WLC_GET_VAR;
3699         ioc.buf = buf;
3700         ioc.len = (uint)sizeof(buf);
3701         ioc.set = FALSE;
3702
3703         strncpy(buf, "toe_ol", sizeof(buf) - 1);
3704         buf[sizeof(buf) - 1] = '\0';
3705         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
3706                 /* Check for older dongle image that doesn't support toe_ol */
3707                 if (ret == -EIO) {
3708                         DHD_ERROR(("%s: toe not supported by device\n",
3709                                 dhd_ifname(&dhd->pub, ifidx)));
3710                         return -EOPNOTSUPP;
3711                 }
3712
3713                 DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
3714                 return ret;
3715         }
3716
3717         memcpy(toe_ol, buf, sizeof(uint32));
3718         return 0;
3719 }
3720
3721 /* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */
3722 static int
3723 dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol)
3724 {
3725         wl_ioctl_t ioc;
3726         char buf[32];
3727         int toe, ret;
3728
3729         memset(&ioc, 0, sizeof(ioc));
3730
3731         ioc.cmd = WLC_SET_VAR;
3732         ioc.buf = buf;
3733         ioc.len = (uint)sizeof(buf);
3734         ioc.set = TRUE;
3735
3736         /* Set toe_ol as requested */
3737
3738         strncpy(buf, "toe_ol", sizeof(buf) - 1);
3739         buf[sizeof(buf) - 1] = '\0';
3740         memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32));
3741
3742         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
3743                 DHD_ERROR(("%s: could not set toe_ol: ret=%d\n",
3744                         dhd_ifname(&dhd->pub, ifidx), ret));
3745                 return ret;
3746         }
3747
3748         /* Enable toe globally only if any components are enabled. */
3749
3750         toe = (toe_ol != 0);
3751
3752         strcpy(buf, "toe");
3753         memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32));
3754
3755         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
3756                 DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
3757                 return ret;
3758         }
3759
3760         return 0;
3761 }
3762 #endif /* TOE */
3763
3764 #if defined(WL_CFG80211)
3765 void dhd_set_scb_probe(dhd_pub_t *dhd)
3766 {
3767 #define NUM_SCB_MAX_PROBE 3
3768         int ret = 0;
3769         wl_scb_probe_t scb_probe;
3770         char iovbuf[WL_EVENTING_MASK_LEN + 12];
3771
3772         memset(&scb_probe, 0, sizeof(wl_scb_probe_t));
3773
3774         if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)
3775                 return;
3776
3777         bcm_mkiovar("scb_probe", NULL, 0, iovbuf, sizeof(iovbuf));
3778
3779         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
3780                 DHD_ERROR(("%s: GET max_scb_probe failed\n", __FUNCTION__));
3781
3782         memcpy(&scb_probe, iovbuf, sizeof(wl_scb_probe_t));
3783
3784         scb_probe.scb_max_probe = NUM_SCB_MAX_PROBE;
3785
3786         bcm_mkiovar("scb_probe", (char *)&scb_probe,
3787                 sizeof(wl_scb_probe_t), iovbuf, sizeof(iovbuf));
3788         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
3789                 DHD_ERROR(("%s: max_scb_probe setting failed\n", __FUNCTION__));
3790 #undef NUM_SCB_MAX_PROBE
3791         return;
3792 }
3793 #endif /* WL_CFG80211 */
3794
3795 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
3796 static void
3797 dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
3798 {
3799         dhd_info_t *dhd = DHD_DEV_INFO(net);
3800
3801         snprintf(info->driver, sizeof(info->driver), "wl");
3802         snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version);
3803 }
3804
3805 struct ethtool_ops dhd_ethtool_ops = {
3806         .get_drvinfo = dhd_ethtool_get_drvinfo
3807 };
3808 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
3809
3810
3811 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
3812 static int
3813 dhd_ethtool(dhd_info_t *dhd, void *uaddr)
3814 {
3815         struct ethtool_drvinfo info;
3816         char drvname[sizeof(info.driver)];
3817         uint32 cmd;
3818 #ifdef TOE
3819         struct ethtool_value edata;
3820         uint32 toe_cmpnt, csum_dir;
3821         int ret;
3822 #endif
3823
3824         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3825
3826         /* all ethtool calls start with a cmd word */
3827         if (copy_from_user(&cmd, uaddr, sizeof (uint32)))
3828                 return -EFAULT;
3829
3830         switch (cmd) {
3831         case ETHTOOL_GDRVINFO:
3832                 /* Copy out any request driver name */
3833                 if (copy_from_user(&info, uaddr, sizeof(info)))
3834                         return -EFAULT;
3835                 strncpy(drvname, info.driver, sizeof(info.driver));
3836                 drvname[sizeof(info.driver)-1] = '\0';
3837
3838                 /* clear struct for return */
3839                 memset(&info, 0, sizeof(info));
3840                 info.cmd = cmd;
3841
3842                 /* if dhd requested, identify ourselves */
3843                 if (strcmp(drvname, "?dhd") == 0) {
3844                         snprintf(info.driver, sizeof(info.driver), "dhd");
3845                         strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1);
3846                         info.version[sizeof(info.version) - 1] = '\0';
3847                 }
3848
3849                 /* otherwise, require dongle to be up */
3850                 else if (!dhd->pub.up) {
3851                         DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__));
3852                         return -ENODEV;
3853                 }
3854
3855                 /* finally, report dongle driver type */
3856                 else if (dhd->pub.iswl)
3857                         snprintf(info.driver, sizeof(info.driver), "wl");
3858                 else
3859                         snprintf(info.driver, sizeof(info.driver), "xx");
3860
3861                 snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version);
3862                 if (copy_to_user(uaddr, &info, sizeof(info)))
3863                         return -EFAULT;
3864                 DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__,
3865                          (int)sizeof(drvname), drvname, info.driver));
3866                 break;
3867
3868 #ifdef TOE
3869         /* Get toe offload components from dongle */
3870         case ETHTOOL_GRXCSUM:
3871         case ETHTOOL_GTXCSUM:
3872                 if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
3873                         return ret;
3874
3875                 csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
3876
3877                 edata.cmd = cmd;
3878                 edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
3879
3880                 if (copy_to_user(uaddr, &edata, sizeof(edata)))
3881                         return -EFAULT;
3882                 break;
3883
3884         /* Set toe offload components in dongle */
3885         case ETHTOOL_SRXCSUM:
3886         case ETHTOOL_STXCSUM:
3887                 if (copy_from_user(&edata, uaddr, sizeof(edata)))
3888                         return -EFAULT;
3889
3890                 /* Read the current settings, update and write back */
3891                 if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
3892                         return ret;
3893
3894                 csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
3895
3896                 if (edata.data != 0)
3897                         toe_cmpnt |= csum_dir;
3898                 else
3899                         toe_cmpnt &= ~csum_dir;
3900
3901                 if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0)
3902                         return ret;
3903
3904                 /* If setting TX checksum mode, tell Linux the new mode */
3905                 if (cmd == ETHTOOL_STXCSUM) {
3906                         if (edata.data)
3907                                 dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM;
3908                         else
3909                                 dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM;
3910                 }
3911
3912                 break;
3913 #endif /* TOE */
3914
3915         default:
3916                 return -EOPNOTSUPP;
3917         }
3918
3919         return 0;
3920 }
3921 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
3922
3923 static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
3924 {
3925         dhd_info_t *dhd;
3926
3927         if (!dhdp) {
3928                 DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
3929                 return FALSE;
3930         }
3931
3932         if (!dhdp->up)
3933                 return FALSE;
3934
3935         dhd = (dhd_info_t *)dhdp->info;
3936 #if !defined(BCMPCIE)
3937         if (dhd->thr_dpc_ctl.thr_pid < 0) {
3938                 DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__));
3939                 return FALSE;
3940         }
3941 #endif 
3942
3943 #ifdef CONFIG_MACH_UNIVERSAL5433
3944         /* old revision does not send hang message */
3945         if ((check_rev() && (error == -ETIMEDOUT)) || (error == -EREMOTEIO) ||
3946 #else
3947         if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) ||
3948 #endif /* CONFIG_MACH_UNIVERSAL5433 */
3949                 ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) {
3950                 DHD_ERROR(("%s: Event HANG send up due to  re=%d te=%d e=%d s=%d\n", __FUNCTION__,
3951                         dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate));
3952                 net_os_send_hang_message(net);
3953                 return TRUE;
3954         }
3955         return FALSE;
3956 }
3957
3958 int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_buf)
3959 {
3960         int bcmerror = BCME_OK;
3961         int buflen = 0;
3962         struct net_device *net;
3963
3964         net = dhd_idx2net(pub, ifidx);
3965         if (!net) {
3966                 bcmerror = BCME_BADARG;
3967                 goto done;
3968         }
3969
3970         if (data_buf)
3971                 buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN);
3972
3973         /* check for local dhd ioctl and handle it */
3974         if (ioc->driver == DHD_IOCTL_MAGIC) {
3975                 bcmerror = dhd_ioctl((void *)pub, ioc, data_buf, buflen);
3976                 if (bcmerror)
3977                         pub->bcmerror = bcmerror;
3978                 goto done;
3979         }
3980
3981         /* send to dongle (must be up, and wl). */
3982         if (pub->busstate != DHD_BUS_DATA) {
3983                 bcmerror = BCME_DONGLE_DOWN;
3984                 goto done;
3985         }
3986
3987         if (!pub->iswl) {
3988                 bcmerror = BCME_DONGLE_DOWN;
3989                 goto done;
3990         }
3991
3992         /*
3993          * Flush the TX queue if required for proper message serialization:
3994          * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to
3995          * prevent M4 encryption and
3996          * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to
3997          * prevent disassoc frame being sent before WPS-DONE frame.
3998          */
3999         if (ioc->cmd == WLC_SET_KEY ||
4000             (ioc->cmd == WLC_SET_VAR && data_buf != NULL &&
4001              strncmp("wsec_key", data_buf, 9) == 0) ||
4002             (ioc->cmd == WLC_SET_VAR && data_buf != NULL &&
4003              strncmp("bsscfg:wsec_key", data_buf, 15) == 0) ||
4004             ioc->cmd == WLC_DISASSOC)
4005                 dhd_wait_pend8021x(net);
4006
4007 #ifdef WLMEDIA_HTSF
4008         if (data_buf) {
4009                 /*  short cut wl ioctl calls here  */
4010                 if (strcmp("htsf", data_buf) == 0) {
4011                         dhd_ioctl_htsf_get(dhd, 0);
4012                         return BCME_OK;
4013                 }
4014
4015                 if (strcmp("htsflate", data_buf) == 0) {
4016                         if (ioc->set) {
4017                                 memset(ts, 0, sizeof(tstamp_t)*TSMAX);
4018                                 memset(&maxdelayts, 0, sizeof(tstamp_t));
4019                                 maxdelay = 0;
4020                                 tspktcnt = 0;
4021                                 maxdelaypktno = 0;
4022                                 memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
4023                                 memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
4024                                 memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
4025                                 memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
4026                         } else {
4027                                 dhd_dump_latency();
4028                         }
4029                         return BCME_OK;
4030                 }
4031                 if (strcmp("htsfclear", data_buf) == 0) {
4032                         memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
4033                         memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
4034                         memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
4035                         memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
4036                         htsf_seqnum = 0;
4037                         return BCME_OK;
4038                 }
4039                 if (strcmp("htsfhis", data_buf) == 0) {
4040                         dhd_dump_htsfhisto(&vi_d1, "H to D");
4041                         dhd_dump_htsfhisto(&vi_d2, "D to D");
4042                         dhd_dump_htsfhisto(&vi_d3, "D to H");
4043                         dhd_dump_htsfhisto(&vi_d4, "H to H");
4044                         return BCME_OK;
4045                 }
4046                 if (strcmp("tsport", data_buf) == 0) {
4047                         if (ioc->set) {
4048                                 memcpy(&tsport, data_buf + 7, 4);
4049                         } else {
4050                                 DHD_ERROR(("current timestamp port: %d \n", tsport));
4051                         }
4052                         return BCME_OK;
4053                 }
4054         }
4055 #endif /* WLMEDIA_HTSF */
4056
4057         if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) &&
4058                 data_buf != NULL && strncmp("rpc_", data_buf, 4) == 0) {
4059 #ifdef BCM_FD_AGGR
4060                 bcmerror = dhd_fdaggr_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen);
4061 #else
4062                 bcmerror = BCME_UNSUPPORTED;
4063 #endif
4064                 goto done;
4065         }
4066         bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen);
4067
4068 done:
4069         dhd_check_hang(net, pub, bcmerror);
4070
4071         return bcmerror;
4072 }
4073
4074 static int
4075 dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
4076 {
4077         dhd_info_t *dhd = DHD_DEV_INFO(net);
4078         dhd_ioctl_t ioc;
4079         int bcmerror = 0;
4080         int ifidx;
4081         int ret;
4082         void *local_buf = NULL;
4083         u16 buflen = 0;
4084
4085         DHD_OS_WAKE_LOCK(&dhd->pub);
4086         DHD_PERIM_LOCK(&dhd->pub);
4087
4088         /* Interface up check for built-in type */
4089         if (!dhd_download_fw_on_driverload && dhd->pub.up == 0) {
4090                 DHD_TRACE(("%s: Interface is down \n", __FUNCTION__));
4091                 DHD_PERIM_UNLOCK(&dhd->pub);
4092                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4093                 return BCME_NOTUP;
4094         }
4095
4096         /* send to dongle only if we are not waiting for reload already */
4097         if (dhd->pub.hang_was_sent) {
4098                 DHD_TRACE(("%s: HANG was sent up earlier\n", __FUNCTION__));
4099                 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS);
4100                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4101                 return OSL_ERROR(BCME_DONGLE_DOWN);
4102         }
4103
4104         ifidx = dhd_net2idx(dhd, net);
4105         DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd));
4106
4107         if (ifidx == DHD_BAD_IF) {
4108                 DHD_ERROR(("%s: BAD IF\n", __FUNCTION__));
4109                 DHD_PERIM_UNLOCK(&dhd->pub);
4110                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4111                 return -1;
4112         }
4113
4114 #if defined(WL_WIRELESS_EXT)
4115         /* linux wireless extensions */
4116         if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {
4117                 /* may recurse, do NOT lock */
4118                 ret = wl_iw_ioctl(net, ifr, cmd);
4119                 DHD_PERIM_UNLOCK(&dhd->pub);
4120                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4121                 return ret;
4122         }
4123 #endif /* defined(WL_WIRELESS_EXT) */
4124
4125 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
4126         if (cmd == SIOCETHTOOL) {
4127                 ret = dhd_ethtool(dhd, (void*)ifr->ifr_data);
4128                 DHD_PERIM_UNLOCK(&dhd->pub);
4129                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4130                 return ret;
4131         }
4132 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
4133
4134         if (cmd == SIOCDEVPRIVATE+1) {
4135                 ret = wl_android_priv_cmd(net, ifr, cmd);
4136                 dhd_check_hang(net, &dhd->pub, ret);
4137                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4138                 return ret;
4139         }
4140
4141         if (cmd != SIOCDEVPRIVATE) {
4142                 DHD_PERIM_UNLOCK(&dhd->pub);
4143                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4144                 return -EOPNOTSUPP;
4145         }
4146
4147         memset(&ioc, 0, sizeof(ioc));
4148
4149 #ifdef CONFIG_COMPAT
4150         if (is_compat_task()) {
4151                 compat_wl_ioctl_t compat_ioc;
4152                 if (copy_from_user(&compat_ioc, ifr->ifr_data, sizeof(compat_wl_ioctl_t))) {
4153                         bcmerror = BCME_BADADDR;
4154                         goto done;
4155                 }
4156                 ioc.cmd = compat_ioc.cmd;
4157                 ioc.buf = compat_ptr(compat_ioc.buf);
4158                 ioc.len = compat_ioc.len;
4159                 ioc.set = compat_ioc.set;
4160                 ioc.used = compat_ioc.used;
4161                 ioc.needed = compat_ioc.needed;
4162                 /* To differentiate between wl and dhd read 4 more byes */
4163                 if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t),
4164                         sizeof(uint)) != 0)) {
4165                         bcmerror = BCME_BADADDR;
4166                         goto done;
4167                 }
4168         } else
4169 #endif /* CONFIG_COMPAT */
4170         {
4171                 /* Copy the ioc control structure part of ioctl request */
4172                 if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) {
4173                         bcmerror = BCME_BADADDR;
4174                         goto done;
4175                 }
4176
4177                 /* To differentiate between wl and dhd read 4 more byes */
4178                 if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t),
4179                         sizeof(uint)) != 0)) {
4180                         bcmerror = BCME_BADADDR;
4181                         goto done;
4182                 }
4183         }
4184
4185         if (!capable(CAP_NET_ADMIN)) {
4186                 bcmerror = BCME_EPERM;
4187                 goto done;
4188         }
4189
4190         if (ioc.len > 0) {
4191                 buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN);
4192                 if (!(local_buf = MALLOC(dhd->pub.osh, buflen+1))) {
4193                         bcmerror = BCME_NOMEM;
4194                         goto done;
4195                 }
4196
4197                 DHD_PERIM_UNLOCK(&dhd->pub);
4198                 if (copy_from_user(local_buf, ioc.buf, buflen)) {
4199                         DHD_PERIM_LOCK(&dhd->pub);
4200                         bcmerror = BCME_BADADDR;
4201                         goto done;
4202                 }
4203                 DHD_PERIM_LOCK(&dhd->pub);
4204
4205                 *(char *)(local_buf + buflen) = '\0';
4206         }
4207
4208         bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf);
4209
4210         if (!bcmerror && buflen && local_buf && ioc.buf) {
4211                 DHD_PERIM_UNLOCK(&dhd->pub);
4212                 if (copy_to_user(ioc.buf, local_buf, buflen))
4213                         bcmerror = -EFAULT;
4214                 DHD_PERIM_LOCK(&dhd->pub);
4215         }
4216
4217 done:
4218         if (local_buf)
4219                 MFREE(dhd->pub.osh, local_buf, buflen+1);
4220
4221         DHD_PERIM_UNLOCK(&dhd->pub);
4222         DHD_OS_WAKE_UNLOCK(&dhd->pub);
4223
4224         return OSL_ERROR(bcmerror);
4225 }
4226
4227
4228
4229 static int
4230 dhd_stop(struct net_device *net)
4231 {
4232         int ifidx = 0;
4233         dhd_info_t *dhd = DHD_DEV_INFO(net);
4234         DHD_OS_WAKE_LOCK(&dhd->pub);
4235         DHD_PERIM_LOCK(&dhd->pub);
4236         DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net));
4237         if (dhd->pub.up == 0) {
4238                 goto exit;
4239         }
4240
4241         dhd_if_flush_sta(DHD_DEV_IFP(net));
4242
4243
4244         ifidx = dhd_net2idx(dhd, net);
4245         BCM_REFERENCE(ifidx);
4246
4247         /* Set state and stop OS transmissions */
4248         netif_stop_queue(net);
4249         dhd->pub.up = 0;
4250
4251 #ifdef WL_CFG80211
4252         if (ifidx == 0) {
4253                 wl_cfg80211_down(NULL);
4254
4255                 /*
4256                  * For CFG80211: Clean up all the left over virtual interfaces
4257                  * when the primary Interface is brought down. [ifconfig wlan0 down]
4258                  */
4259                 if (!dhd_download_fw_on_driverload) {
4260                         if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) &&
4261                                 (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
4262                                 int i;
4263
4264
4265                                 dhd_net_if_lock_local(dhd);
4266                                 for (i = 1; i < DHD_MAX_IFS; i++)
4267                                         dhd_remove_if(&dhd->pub, i, FALSE);
4268 #ifdef ARP_OFFLOAD_SUPPORT
4269                                 if (dhd_inetaddr_notifier_registered) {
4270                                         dhd_inetaddr_notifier_registered = FALSE;
4271                                         unregister_inetaddr_notifier(&dhd_inetaddr_notifier);
4272                                 }
4273 #endif /* ARP_OFFLOAD_SUPPORT */
4274 #ifdef CONFIG_IPV6
4275                                 if (dhd_inet6addr_notifier_registered) {
4276                                         dhd_inet6addr_notifier_registered = FALSE;
4277                                         unregister_inet6addr_notifier(&dhd_inet6addr_notifier);
4278                                 }
4279 #endif /* CONFIG_IPV6 */
4280                                 dhd_net_if_unlock_local(dhd);
4281                         }
4282                 }
4283         }
4284 #endif /* WL_CFG80211 */
4285
4286 #ifdef PROP_TXSTATUS
4287         dhd_wlfc_cleanup(&dhd->pub, NULL, 0);
4288 #endif
4289         /* Stop the protocol module */
4290         dhd_prot_stop(&dhd->pub);
4291
4292         OLD_MOD_DEC_USE_COUNT;
4293 exit:
4294 #if defined(WL_CFG80211)
4295         if (ifidx == 0 && !dhd_download_fw_on_driverload)
4296                 wl_android_wifi_off(net);
4297 #endif 
4298         dhd->pub.rxcnt_timeout = 0;
4299         dhd->pub.txcnt_timeout = 0;
4300
4301         dhd->pub.hang_was_sent = 0;
4302
4303         /* Clear country spec for for built-in type driver */
4304         if (!dhd_download_fw_on_driverload) {
4305                 dhd->pub.dhd_cspec.country_abbrev[0] = 0x00;
4306                 dhd->pub.dhd_cspec.rev = 0;
4307                 dhd->pub.dhd_cspec.ccode[0] = 0x00;
4308         }
4309
4310         DHD_PERIM_UNLOCK(&dhd->pub);
4311         DHD_OS_WAKE_UNLOCK(&dhd->pub);
4312         return 0;
4313 }
4314
4315 #if defined(WL_CFG80211) && (defined(USE_INITIAL_2G_SCAN) || \
4316         defined(USE_INITIAL_SHORT_DWELL_TIME))
4317 extern bool g_first_broadcast_scan;
4318 #endif /* OEM_ANDROID && WL_CFG80211 && (USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME) */
4319
4320 #ifdef WL11U
4321 static int dhd_interworking_enable(dhd_pub_t *dhd)
4322 {
4323         char iovbuf[WLC_IOCTL_SMLEN];
4324         uint32 enable = true;
4325         int ret = BCME_OK;
4326
4327         bcm_mkiovar("interworking", (char *)&enable, sizeof(enable), iovbuf, sizeof(iovbuf));
4328         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
4329                 DHD_ERROR(("%s: enableing interworking failed, ret=%d\n", __FUNCTION__, ret));
4330         }
4331
4332         if (ret == BCME_OK) {
4333                 /* basic capabilities for HS20 REL2 */
4334                 uint32 cap = WL_WNM_BSSTRANS | WL_WNM_NOTIF;
4335                 bcm_mkiovar("wnm", (char *)&cap, sizeof(cap), iovbuf, sizeof(iovbuf));
4336                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
4337                         iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
4338                         DHD_ERROR(("%s: failed to set WNM info, ret=%d\n", __FUNCTION__, ret));
4339                 }
4340         }
4341
4342         return ret;
4343 }
4344 #endif /* WL11u */
4345
4346 static int
4347 dhd_open(struct net_device *net)
4348 {
4349         dhd_info_t *dhd = DHD_DEV_INFO(net);
4350 #ifdef TOE
4351         uint32 toe_ol;
4352 #endif
4353 #ifdef BCM_FD_AGGR
4354         char iovbuf[WLC_IOCTL_SMLEN];
4355         dbus_config_t config;
4356         uint32 agglimit = 0;
4357         uint32 rpc_agg = BCM_RPC_TP_DNGL_AGG_DPC; /* host aggr not enabled yet */
4358 #endif /* BCM_FD_AGGR */
4359         int ifidx;
4360         int32 ret = 0;
4361
4362
4363
4364
4365         DHD_OS_WAKE_LOCK(&dhd->pub);
4366         DHD_PERIM_LOCK(&dhd->pub);
4367         dhd->pub.dongle_trap_occured = 0;
4368         dhd->pub.hang_was_sent = 0;
4369
4370 #if !defined(WL_CFG80211)
4371         /*
4372          * Force start if ifconfig_up gets called before START command
4373          *  We keep WEXT's wl_control_wl_start to provide backward compatibility
4374          *  This should be removed in the future
4375          */
4376         ret = wl_control_wl_start(net);
4377         if (ret != 0) {
4378                 DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
4379                 ret = -1;
4380                 goto exit;
4381         }
4382
4383 #endif 
4384
4385         ifidx = dhd_net2idx(dhd, net);
4386         DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
4387
4388         if (ifidx < 0) {
4389                 DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__));
4390                 ret = -1;
4391                 goto exit;
4392         }
4393
4394         if (!dhd->iflist[ifidx]) {
4395                 DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__));
4396                 ret = -1;
4397                 goto exit;
4398         }
4399
4400         if (ifidx == 0) {
4401                 atomic_set(&dhd->pend_8021x_cnt, 0);
4402 #if defined(WL_CFG80211)
4403                 if (!dhd_download_fw_on_driverload) {
4404                         DHD_ERROR(("\n%s\n", dhd_version));
4405 #if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
4406                         g_first_broadcast_scan = TRUE;
4407 #endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
4408                         ret = wl_android_wifi_on(net);
4409                         if (ret != 0) {
4410                                 DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n",
4411                                         __FUNCTION__, ret));
4412                                 ret = -1;
4413                                 goto exit;
4414                         }
4415                 }
4416 #endif 
4417
4418                 if (dhd->pub.busstate != DHD_BUS_DATA) {
4419
4420                         /* try to bring up bus */
4421                         DHD_PERIM_UNLOCK(&dhd->pub);
4422                         ret = dhd_bus_start(&dhd->pub);
4423                         DHD_PERIM_LOCK(&dhd->pub);
4424                         if (ret) {
4425                                 DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
4426                                 ret = -1;
4427                                 goto exit;
4428                         }
4429
4430                 }
4431
4432 #ifdef BCM_FD_AGGR
4433                 config.config_id = DBUS_CONFIG_ID_AGGR_LIMIT;
4434
4435
4436                 memset(iovbuf, 0, sizeof(iovbuf));
4437                 bcm_mkiovar("rpc_dngl_agglimit", (char *)&agglimit, 4,
4438                         iovbuf, sizeof(iovbuf));
4439
4440                 if (!dhd_wl_ioctl_cmd(&dhd->pub, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) {
4441                         agglimit = *(uint32 *)iovbuf;
4442                         config.aggr_param.maxrxsf = agglimit >> BCM_RPC_TP_AGG_SF_SHIFT;
4443                         config.aggr_param.maxrxsize = agglimit & BCM_RPC_TP_AGG_BYTES_MASK;
4444                         config.aggr_param.maxrxsize *= 2; /* temporary double rx size */
4445                         DHD_ERROR(("rpc_dngl_agglimit %x : sf_limit %d bytes_limit %d\n",
4446                                 agglimit, config.aggr_param.maxrxsf, config.aggr_param.maxrxsize));
4447                         if (bcm_rpc_tp_set_config(dhd->pub.info->rpc_th, &config)) {
4448                                 DHD_ERROR(("set tx/rx queue size and buffersize failed\n"));
4449                         }
4450                 } else {
4451                         DHD_ERROR(("get rpc_dngl_agglimit failed\n"));
4452                         rpc_agg &= ~BCM_RPC_TP_DNGL_AGG_DPC;
4453                 }
4454
4455                 /* Set aggregation for TX */
4456                 bcm_rpc_tp_agg_set(dhd->pub.info->rpc_th, BCM_RPC_TP_HOST_AGG_MASK,
4457                         rpc_agg & BCM_RPC_TP_HOST_AGG_MASK);
4458
4459                 /* Set aggregation for RX */
4460                 memset(iovbuf, 0, sizeof(iovbuf));
4461                 bcm_mkiovar("rpc_agg", (char *)&rpc_agg, sizeof(rpc_agg), iovbuf, sizeof(iovbuf));
4462                 if (!dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) {
4463                         dhd->pub.info->fdaggr = (rpc_agg != 0);
4464                 } else {
4465                         DHD_ERROR(("%s(): Setting RX aggregation failed %d\n", __FUNCTION__, ret));
4466                 }
4467 #endif /* BCM_FD_AGGR */
4468
4469                 /* dhd_sync_with_dongle has been called in dhd_bus_start or wl_android_wifi_on */
4470                 memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
4471
4472 #ifdef TOE
4473                 /* Get current TOE mode from dongle */
4474                 if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0)
4475                         dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM;
4476                 else
4477                         dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM;
4478 #endif /* TOE */
4479
4480 #if defined(WL_CFG80211)
4481                 if (unlikely(wl_cfg80211_up(NULL))) {
4482                         DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
4483                         ret = -1;
4484                         goto exit;
4485                 }
4486                 if (!dhd_download_fw_on_driverload) {
4487 #ifdef ARP_OFFLOAD_SUPPORT
4488                         dhd->pend_ipaddr = 0;
4489                         if (!dhd_inetaddr_notifier_registered) {
4490                                 dhd_inetaddr_notifier_registered = TRUE;
4491                                 register_inetaddr_notifier(&dhd_inetaddr_notifier);
4492                         }
4493 #endif /* ARP_OFFLOAD_SUPPORT */
4494 #ifdef CONFIG_IPV6
4495                         if (!dhd_inet6addr_notifier_registered) {
4496                                 dhd_inet6addr_notifier_registered = TRUE;
4497                                 register_inet6addr_notifier(&dhd_inet6addr_notifier);
4498                         }
4499 #endif /* CONFIG_IPV6 */
4500                 }
4501                 dhd_set_scb_probe(&dhd->pub);
4502 #endif /* WL_CFG80211 */
4503         }
4504
4505         /* Allow transmit calls */
4506         netif_start_queue(net);
4507         dhd->pub.up = 1;
4508
4509 #ifdef BCMDBGFS
4510         dhd_dbg_init(&dhd->pub);
4511 #endif
4512
4513         OLD_MOD_INC_USE_COUNT;
4514 exit:
4515         if (ret)
4516                 dhd_stop(net);
4517
4518         DHD_PERIM_UNLOCK(&dhd->pub);
4519         DHD_OS_WAKE_UNLOCK(&dhd->pub);
4520
4521
4522         return ret;
4523 }
4524
4525 int dhd_do_driver_init(struct net_device *net)
4526 {
4527         dhd_info_t *dhd = NULL;
4528
4529         if (!net) {
4530                 DHD_ERROR(("Primary Interface not initialized \n"));
4531                 return -EINVAL;
4532         }
4533
4534
4535         /*  && defined(OEM_ANDROID) && defined(BCMSDIO) */
4536         dhd = DHD_DEV_INFO(net);
4537
4538         /* If driver is already initialized, do nothing
4539          */
4540         if (dhd->pub.busstate == DHD_BUS_DATA) {
4541                 DHD_TRACE(("Driver already Inititalized. Nothing to do"));
4542                 return 0;
4543         }
4544
4545         if (dhd_open(net) < 0) {
4546                 DHD_ERROR(("Driver Init Failed \n"));
4547                 return -1;
4548         }
4549
4550         return 0;
4551 }
4552
4553 int
4554 dhd_event_ifadd(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac)
4555 {
4556
4557 #ifdef WL_CFG80211
4558         if (wl_cfg80211_notify_ifadd(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK)
4559                 return BCME_OK;
4560 #endif
4561
4562         /* handle IF event caused by wl commands, SoftAP, WEXT and
4563          * anything else. This has to be done asynchronously otherwise
4564          * DPC will be blocked (and iovars will timeout as DPC has no chance
4565          * to read the response back)
4566          */
4567         if (ifevent->ifidx > 0) {
4568                 dhd_if_event_t *if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t));
4569
4570                 memcpy(&if_event->event, ifevent, sizeof(if_event->event));
4571                 memcpy(if_event->mac, mac, ETHER_ADDR_LEN);
4572                 strncpy(if_event->name, name, IFNAMSIZ);
4573                 if_event->name[IFNAMSIZ - 1] = '\0';
4574                 dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event,
4575                         DHD_WQ_WORK_IF_ADD, dhd_ifadd_event_handler, DHD_WORK_PRIORITY_LOW);
4576         }
4577
4578         return BCME_OK;
4579 }
4580
4581 void
4582 dhd_p2p_ifdel(dhd_pub_t *dhdpub, int ifidx)
4583 {
4584         dhd_info_t *dhdinfo = dhdpub->info;
4585         dhdinfo->p2p_del_ifp = dhdinfo->iflist[ifidx];
4586         dhdinfo->iflist[ifidx] = NULL;
4587 }
4588
4589 int
4590 dhd_event_ifdel(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac)
4591 {
4592         dhd_if_event_t *if_event;
4593
4594 #if defined(WL_CFG80211) && !defined(P2PONEINT)
4595         if (wl_cfg80211_notify_ifdel(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK)
4596                 return BCME_OK;
4597 #endif /* WL_CFG80211 */
4598
4599         /* handle IF event caused by wl commands, SoftAP, WEXT and
4600          * anything else
4601          */
4602         if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t));
4603         memcpy(&if_event->event, ifevent, sizeof(if_event->event));
4604         memcpy(if_event->mac, mac, ETHER_ADDR_LEN);
4605         strncpy(if_event->name, name, IFNAMSIZ);
4606         if_event->name[IFNAMSIZ - 1] = '\0';
4607         dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, DHD_WQ_WORK_IF_DEL,
4608                 dhd_ifdel_event_handler, DHD_WORK_PRIORITY_LOW);
4609
4610         return BCME_OK;
4611 }
4612
4613 /* unregister and free the existing net_device interface (if any) in iflist and
4614  * allocate a new one. the slot is reused. this function does NOT register the
4615  * new interface to linux kernel. dhd_register_if does the job
4616  */
4617 struct net_device*
4618 dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name,
4619         uint8 *mac, uint8 bssidx, bool need_rtnl_lock)
4620 {
4621         dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info;
4622         dhd_if_t *ifp;
4623
4624         ASSERT(dhdinfo && (ifidx < DHD_MAX_IFS));
4625         ifp = dhdinfo->iflist[ifidx];
4626
4627         if (ifp != NULL) {
4628                 if (ifp->net != NULL) {
4629                         DHD_ERROR(("%s: free existing IF %s\n", __FUNCTION__, ifp->net->name));
4630
4631                         dhd_dev_priv_clear(ifp->net); /* clear net_device private */
4632
4633                         /* in unregister_netdev case, the interface gets freed by net->destructor
4634                          * (which is set to free_netdev)
4635                          */
4636                         if (ifp->net->reg_state == NETREG_UNINITIALIZED) {
4637                                 free_netdev(ifp->net);
4638                         } else {
4639                                 netif_stop_queue(ifp->net);
4640                                 if (need_rtnl_lock)
4641                                         unregister_netdev(ifp->net);
4642                                 else
4643                                         unregister_netdevice(ifp->net);
4644                         }
4645                         ifp->net = NULL;
4646                 }
4647         } else {
4648                 ifp = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_t));
4649                 if (ifp == NULL) {
4650                         DHD_ERROR(("%s: OOM - dhd_if_t(%zu)\n", __FUNCTION__, sizeof(dhd_if_t)));
4651                         return NULL;
4652                 }
4653         }
4654
4655         memset(ifp, 0, sizeof(dhd_if_t));
4656         ifp->info = dhdinfo;
4657         ifp->idx = ifidx;
4658         ifp->bssidx = bssidx;
4659         if (mac != NULL)
4660                 memcpy(&ifp->mac_addr, mac, ETHER_ADDR_LEN);
4661
4662         /* Allocate etherdev, including space for private structure */
4663         ifp->net = alloc_etherdev(DHD_DEV_PRIV_SIZE);
4664         if (ifp->net == NULL) {
4665                 DHD_ERROR(("%s: OOM - alloc_etherdev(%zu)\n", __FUNCTION__, sizeof(dhdinfo)));
4666                 goto fail;
4667         }
4668
4669         /* Setup the dhd interface's netdevice private structure. */
4670         dhd_dev_priv_save(ifp->net, dhdinfo, ifp, ifidx);
4671
4672         if (name && name[0]) {
4673                 strncpy(ifp->net->name, name, IFNAMSIZ);
4674                 ifp->net->name[IFNAMSIZ - 1] = '\0';
4675         }
4676 #ifdef WL_CFG80211
4677         if (ifidx == 0)
4678                 ifp->net->destructor = free_netdev;
4679         else
4680                 ifp->net->destructor = dhd_netdev_free;
4681 #else
4682         ifp->net->destructor = free_netdev;
4683 #endif /* WL_CFG80211 */
4684         strncpy(ifp->name, ifp->net->name, IFNAMSIZ);
4685         ifp->name[IFNAMSIZ - 1] = '\0';
4686         dhdinfo->iflist[ifidx] = ifp;
4687
4688 #ifdef PCIE_FULL_DONGLE
4689         /* Initialize STA info list */
4690         INIT_LIST_HEAD(&ifp->sta_list);
4691         DHD_IF_STA_LIST_LOCK_INIT(ifp);
4692 #endif /* PCIE_FULL_DONGLE */
4693
4694         return ifp->net;
4695
4696 fail:
4697         if (ifp != NULL) {
4698                 if (ifp->net != NULL) {
4699                         dhd_dev_priv_clear(ifp->net);
4700                         free_netdev(ifp->net);
4701                         ifp->net = NULL;
4702                 }
4703                 MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp));
4704                 ifp = NULL;
4705         }
4706         dhdinfo->iflist[ifidx] = NULL;
4707         return NULL;
4708 }
4709
4710 /* unregister and free the the net_device interface associated with the indexed
4711  * slot, also free the slot memory and set the slot pointer to NULL
4712  */
4713 int
4714 dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock)
4715 {
4716         dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info;
4717         dhd_if_t *ifp;
4718
4719         ifp = dhdinfo->iflist[ifidx];
4720         if (ifp != NULL) {
4721                 dhdinfo->iflist[ifidx] = NULL;
4722                 if (ifp->net != NULL) {
4723                         DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx));
4724
4725                         /* in unregister_netdev case, the interface gets freed by net->destructor
4726                          * (which is set to free_netdev)
4727                          */
4728                         if (ifp->net->reg_state == NETREG_UNINITIALIZED) {
4729                                 free_netdev(ifp->net);
4730                         } else {
4731                                 netif_stop_queue(ifp->net);
4732
4733
4734
4735
4736 #ifdef SET_RPS_CPUS
4737                                 custom_rps_map_clear(ifp->net->_rx);
4738 #endif /* SET_RPS_CPUS */
4739                                 if (need_rtnl_lock)
4740                                         unregister_netdev(ifp->net);
4741                                 else
4742                                         unregister_netdevice(ifp->net);
4743                         }
4744                         ifp->net = NULL;
4745                 }
4746 #ifdef DHD_WMF
4747                 dhd_wmf_cleanup(dhdpub, ifidx);
4748 #endif /* DHD_WMF */
4749
4750                 dhd_if_del_sta_list(ifp);
4751
4752                 MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp));
4753
4754         }
4755
4756         return BCME_OK;
4757 }
4758
4759 int
4760 dhd_remove_p2p_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock)
4761 {
4762         dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info;
4763         dhd_if_t *ifp =  dhdinfo->p2p_del_ifp;
4764
4765         ifp = dhdinfo->p2p_del_ifp;
4766         dhdinfo->p2p_del_ifp=NULL;
4767
4768         if (ifp != NULL) {
4769                 if (ifp->net != NULL) {
4770                         DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx));
4771
4772                         /* in unregister_netdev case, the interface gets freed by net->destructor
4773                          * (which is set to free_netdev)
4774                          */
4775                         if (ifp->net->reg_state == NETREG_UNINITIALIZED) {
4776                                 free_netdev(ifp->net);
4777                         } else {
4778                                 netif_stop_queue(ifp->net);
4779
4780
4781
4782                                 if (need_rtnl_lock)
4783                                         unregister_netdev(ifp->net);
4784                                 else
4785                                 unregister_netdevice(ifp->net);
4786                         }
4787                         ifp->net = NULL;
4788                 }
4789 #ifdef DHD_WMF
4790         //Take care of this once WMF is enabled
4791         //dhd_wmf_cleanup(dhdpub, ifidx);
4792 #endif /* DHD_WMF */
4793
4794                 dhd_if_del_sta_list(ifp);
4795
4796                 MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp));
4797
4798         }
4799
4800         return BCME_OK;
4801 }
4802
4803
4804 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
4805 static struct net_device_ops dhd_ops_pri = {
4806         .ndo_open = dhd_open,
4807         .ndo_stop = dhd_stop,
4808         .ndo_get_stats = dhd_get_stats,
4809         .ndo_do_ioctl = dhd_ioctl_entry,
4810         .ndo_start_xmit = dhd_start_xmit,
4811         .ndo_set_mac_address = dhd_set_mac_address,
4812 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
4813         .ndo_set_rx_mode = dhd_set_multicast_list,
4814 #else
4815         .ndo_set_multicast_list = dhd_set_multicast_list,
4816 #endif
4817 };
4818
4819 static struct net_device_ops dhd_ops_virt = {
4820         .ndo_get_stats = dhd_get_stats,
4821         .ndo_do_ioctl = dhd_ioctl_entry,
4822         .ndo_start_xmit = dhd_start_xmit,
4823         .ndo_set_mac_address = dhd_set_mac_address,
4824 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
4825         .ndo_set_rx_mode = dhd_set_multicast_list,
4826 #else
4827         .ndo_set_multicast_list = dhd_set_multicast_list,
4828 #endif
4829 };
4830
4831 #ifdef P2PONEINT
4832 extern int wl_cfgp2p_if_open(struct net_device *net);
4833 extern int wl_cfgp2p_if_stop(struct net_device *net);
4834
4835 static struct net_device_ops dhd_cfgp2p_ops_virt = {
4836         .ndo_open = wl_cfgp2p_if_open,
4837         .ndo_stop = wl_cfgp2p_if_stop,
4838         .ndo_get_stats = dhd_get_stats,
4839         .ndo_do_ioctl = dhd_ioctl_entry,
4840         .ndo_start_xmit = dhd_start_xmit,
4841         .ndo_set_mac_address = dhd_set_mac_address,
4842 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
4843         .ndo_set_rx_mode = dhd_set_multicast_list,
4844 #else
4845         .ndo_set_multicast_list = dhd_set_multicast_list,
4846 #endif
4847 };
4848 #endif /* P2PONEINT */
4849 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
4850
4851 #ifdef DEBUGGER
4852 extern void debugger_init(void *bus_handle);
4853 #endif
4854
4855
4856 #ifdef SHOW_LOGTRACE
4857 static char *logstrs_path = "/root/logstrs.bin";
4858 module_param(logstrs_path, charp, S_IRUGO);
4859
4860 int
4861 dhd_init_logstrs_array(dhd_event_log_t *temp)
4862 {
4863         struct file *filep = NULL;
4864         struct kstat stat;
4865         mm_segment_t fs;
4866         char *raw_fmts =  NULL;
4867         int logstrs_size = 0;
4868
4869         logstr_header_t *hdr = NULL;
4870         uint32 *lognums = NULL;
4871         char *logstrs = NULL;
4872         int ram_index = 0;
4873         char **fmts;
4874         int num_fmts = 0;
4875         uint32 i = 0;
4876         int error = 0;
4877         set_fs(KERNEL_DS);
4878         fs = get_fs();
4879         filep = filp_open(logstrs_path, O_RDONLY, 0);
4880         if (IS_ERR(filep)) {
4881                 DHD_ERROR(("Failed to open the file logstrs.bin in %s",  __FUNCTION__));
4882                 goto fail;
4883         }
4884         error = vfs_stat(logstrs_path, &stat);
4885         if (error) {
4886                 DHD_ERROR(("Failed in %s to find file stat", __FUNCTION__));
4887                 goto fail;
4888         }
4889         logstrs_size = (int) stat.size;
4890
4891         raw_fmts = kmalloc(logstrs_size, GFP_KERNEL);
4892         if (raw_fmts == NULL) {
4893                 DHD_ERROR(("Failed to allocate raw_fmts memory"));
4894                 goto fail;
4895         }
4896         if (vfs_read(filep, raw_fmts, logstrs_size, &filep->f_pos) !=   logstrs_size) {
4897                 DHD_ERROR(("Error: Log strings file read failed"));
4898                 goto fail;
4899         }
4900
4901         /* Remember header from the logstrs.bin file */
4902         hdr = (logstr_header_t *) (raw_fmts + logstrs_size -
4903                 sizeof(logstr_header_t));
4904
4905         if (hdr->log_magic == LOGSTRS_MAGIC) {
4906                 /*
4907                 * logstrs.bin start with header.
4908                 */
4909                 num_fmts =      hdr->rom_logstrs_offset / sizeof(uint32);
4910                 ram_index = (hdr->ram_lognums_offset -
4911                         hdr->rom_lognums_offset) / sizeof(uint32);
4912                 lognums = (uint32 *) &raw_fmts[hdr->rom_lognums_offset];
4913                 logstrs = (char *)       &raw_fmts[hdr->rom_logstrs_offset];
4914         } else {
4915                 /*
4916                  * Legacy logstrs.bin format without header.
4917                  */
4918                 num_fmts = *((uint32 *) (raw_fmts)) / sizeof(uint32);
4919                 if (num_fmts == 0) {
4920                         /* Legacy ROM/RAM logstrs.bin format:
4921                           *  - ROM 'lognums' section
4922                           *   - RAM 'lognums' section
4923                           *   - ROM 'logstrs' section.
4924                           *   - RAM 'logstrs' section.
4925                           *
4926                           * 'lognums' is an array of indexes for the strings in the
4927                           * 'logstrs' section. The first uint32 is 0 (index of first
4928                           * string in ROM 'logstrs' section).
4929                           *
4930                           * The 4324b5 is the only ROM that uses this legacy format. Use the
4931                           * fixed number of ROM fmtnums to find the start of the RAM
4932                           * 'lognums' section. Use the fixed first ROM string ("Con\n") to
4933                           * find the ROM 'logstrs' section.
4934                           */
4935                         #define NUM_4324B5_ROM_FMTS     186
4936                         #define FIRST_4324B5_ROM_LOGSTR "Con\n"
4937                         ram_index = NUM_4324B5_ROM_FMTS;
4938                         lognums = (uint32 *) raw_fmts;
4939                         num_fmts =      ram_index;
4940                         logstrs = (char *) &raw_fmts[num_fmts << 2];
4941                         while (strncmp(FIRST_4324B5_ROM_LOGSTR, logstrs, 4)) {
4942                                 num_fmts++;
4943                                 logstrs = (char *) &raw_fmts[num_fmts << 2];
4944                         }
4945                 } else {
4946                                 /* Legacy RAM-only logstrs.bin format:
4947                                  *        - RAM 'lognums' section
4948                                  *        - RAM 'logstrs' section.
4949                                  *
4950                                  * 'lognums' is an array of indexes for the strings in the
4951                                  * 'logstrs' section. The first uint32 is an index to the
4952                                  * start of 'logstrs'. Therefore, if this index is divided
4953                                  * by 'sizeof(uint32)' it provides the number of logstr
4954                                  *      entries.
4955                                  */
4956                                 ram_index = 0;
4957                                 lognums = (uint32 *) raw_fmts;
4958                                 logstrs = (char *)      &raw_fmts[num_fmts << 2];
4959                         }
4960         }
4961         fmts = kmalloc(num_fmts  * sizeof(char *), GFP_KERNEL);
4962         if (fmts == NULL) {
4963                 DHD_ERROR(("Failed to allocate fmts memory"));
4964                 goto fail;
4965         }
4966
4967         for (i = 0; i < num_fmts; i++) {
4968                 /* ROM lognums index into logstrs using 'rom_logstrs_offset' as a base
4969                 * (they are 0-indexed relative to 'rom_logstrs_offset').
4970                 *
4971                 * RAM lognums are already indexed to point to the correct RAM logstrs (they
4972                 * are 0-indexed relative to the start of the logstrs.bin file).
4973                 */
4974                 if (i == ram_index) {
4975                         logstrs = raw_fmts;
4976                 }
4977                 fmts[i] = &logstrs[lognums[i]];
4978         }
4979         temp->fmts = fmts;
4980         temp->raw_fmts = raw_fmts;
4981         temp->num_fmts = num_fmts;
4982         filp_close(filep, NULL);
4983         set_fs(fs);
4984         return 0;
4985 fail:
4986         if (raw_fmts) {
4987                 kfree(raw_fmts);
4988                 raw_fmts = NULL;
4989         }
4990         if (!IS_ERR(filep))
4991                 filp_close(filep, NULL);
4992         set_fs(fs);
4993         temp->fmts = NULL;
4994         return -1;
4995 }
4996 #endif /* SHOW_LOGTRACE */
4997
4998 #ifdef CUSTOMER_HW20
4999 static char init_ccode[8] = {'\0'};
5000 module_param_string(init_ccode, init_ccode, 8, 0);
5001 static int
5002 dhd_parse_ccspec(const char *spec, char *ccode, int *regrev)
5003 {
5004         char *revstr;
5005         char *endptr = NULL;
5006         int ccode_len;
5007         int rev = -1;
5008
5009         revstr = strchr(spec, '/');
5010
5011         if (revstr) {
5012                 rev = bcm_strtoul(revstr + 1, &endptr, 10);
5013                 if (*endptr != '\0') {
5014                         /* not all the value string was parsed by strtol */
5015                         DHD_ERROR(("Could not parse \"%s\" as a regulatory revision "
5016                                    "in the country string \"%s\"\n",
5017                                    revstr + 1, spec));
5018                         return BCME_ERROR;
5019                 }
5020         }
5021
5022         if (revstr)
5023                 ccode_len = (int)(uintptr)(revstr - spec);
5024         else
5025                 ccode_len = (int)strlen(spec);
5026
5027         if (ccode_len > 3) {
5028                 DHD_ERROR(("Could not parse a 2-3 char country code "
5029                             "in the country string \"%s\"\n", spec));
5030                 return BCME_ERROR;
5031         }
5032
5033         memcpy(ccode, spec, ccode_len);
5034         ccode[ccode_len] = '\0';
5035         *regrev = rev;
5036
5037         return BCME_OK;
5038 }
5039
5040 static int
5041 dhd_init_ccode(struct net_device *ndev)
5042 {
5043         int ret = 0;
5044         wl_country_t cspec = {{0}, 0, {0}};
5045         uint band = 0;
5046
5047         if (init_ccode[0] == '\0')
5048                 return BCME_OK;
5049
5050         memset(&cspec, 0, sizeof(cspec));
5051         cspec.rev = -1;
5052
5053         DHD_ERROR(("Country Code = %s, len = %d \n", init_ccode, (int)strlen(init_ccode)));
5054
5055         if (strncmp(init_ccode, "UY/1", 4) == 0) {
5056                 band = WLC_BAND_5G;
5057                 ret = wldev_ioctl(ndev, WLC_SET_BAND, &band, sizeof(band), true);
5058                 WL_INFORM(("set BAND A \n"));
5059         }
5060
5061         ret = dhd_parse_ccspec(init_ccode, cspec.country_abbrev, &cspec.rev);
5062
5063         if (ret != BCME_OK) {
5064                 DHD_ERROR(("ERROR occured when ccode is set \n"));
5065                 return ret;
5066         }
5067
5068         if (cspec.rev != -1)
5069                 memcpy(cspec.ccode, cspec.country_abbrev, WLC_CNTRY_BUF_SZ);
5070
5071         ret = wldev_ioctl(ndev, WLC_SET_COUNTRY, &cspec, sizeof(cspec), true);
5072         if (ret != BCME_OK) {
5073                 DHD_ERROR(("%s: country code set failed %d\n", __FUNCTION__, ret));
5074                 return ret;
5075         }
5076
5077         memset(&cspec, 0, sizeof(cspec));
5078
5079         ret = wldev_ioctl(ndev, WLC_GET_COUNTRY, &cspec, sizeof(cspec), false);
5080
5081         if (ret != BCME_OK)
5082                 DHD_ERROR(("%s: country code get failed %d\n", __FUNCTION__, ret));
5083         else
5084                 DHD_ERROR(("Get Country Code = %s %d %s\n",
5085                            cspec.country_abbrev, cspec.rev, cspec.ccode));
5086
5087         return ret;
5088 }
5089 #endif /* CUSTOMER_HW20 */
5090
5091 dhd_pub_t *
5092 dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
5093 {
5094         dhd_info_t *dhd = NULL;
5095         struct net_device *net = NULL;
5096         char if_name[IFNAMSIZ] = {'\0'};
5097         uint32 bus_type = -1;
5098         uint32 bus_num = -1;
5099         uint32 slot_num = -1;
5100         wifi_adapter_info_t *adapter = NULL;
5101
5102         dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT;
5103         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5104
5105         /* will implement get_ids for DBUS later */
5106 #if defined(BCMSDIO)
5107         dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num);
5108 #endif 
5109         adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num);
5110
5111         /* Allocate primary dhd_info */
5112         dhd = wifi_platform_prealloc(adapter, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t));
5113         if (dhd == NULL) {
5114                 dhd = MALLOC(osh, sizeof(dhd_info_t));
5115                 if (dhd == NULL) {
5116                         DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__));
5117                         goto fail;
5118                 }
5119         }
5120         memset(dhd, 0, sizeof(dhd_info_t));
5121         dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC;
5122
5123         dhd->unit = dhd_found + instance_base; /* do not increment dhd_found, yet */
5124
5125         dhd->pub.osh = osh;
5126         dhd->adapter = adapter;
5127
5128 #ifdef GET_CUSTOM_MAC_ENABLE
5129         wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet);
5130 #endif /* GET_CUSTOM_MAC_ENABLE */
5131         dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID;
5132         dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID;
5133
5134         /* Initialize thread based operation and lock */
5135         sema_init(&dhd->sdsem, 1);
5136
5137         /* Some DHD modules (e.g. cfg80211) configures operation mode based on firmware name.
5138          * This is indeed a hack but we have to make it work properly before we have a better
5139          * solution
5140          */
5141         dhd_update_fw_nv_path(dhd);
5142
5143         /* Link to info module */
5144         dhd->pub.info = dhd;
5145
5146
5147         /* Link to bus module */
5148         dhd->pub.bus = bus;
5149         dhd->pub.hdrlen = bus_hdrlen;
5150
5151         /* Set network interface name if it was provided as module parameter */
5152         if (iface_name[0]) {
5153                 int len;
5154                 char ch;
5155                 strncpy(if_name, iface_name, IFNAMSIZ);
5156                 if_name[IFNAMSIZ - 1] = 0;
5157                 len = strlen(if_name);
5158                 ch = if_name[len - 1];
5159                 if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2))
5160                         strcat(if_name, "%d");
5161         }
5162         net = dhd_allocate_if(&dhd->pub, 0, if_name, NULL, 0, TRUE);
5163         if (net == NULL)
5164                 goto fail;
5165         dhd_state |= DHD_ATTACH_STATE_ADD_IF;
5166
5167 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
5168         net->open = NULL;
5169 #else
5170         net->netdev_ops = NULL;
5171 #endif
5172
5173         sema_init(&dhd->proto_sem, 1);
5174
5175 #ifdef PROP_TXSTATUS
5176         spin_lock_init(&dhd->wlfc_spinlock);
5177
5178         dhd->pub.skip_fc = dhd_wlfc_skip_fc;
5179         dhd->pub.plat_init = dhd_wlfc_plat_init;
5180         dhd->pub.plat_deinit = dhd_wlfc_plat_deinit;
5181
5182 #ifdef DHD_WLFC_THREAD
5183         init_waitqueue_head(&dhd->pub.wlfc_wqhead);
5184         dhd->pub.wlfc_thread = kthread_create(dhd_wlfc_transfer_packets, &dhd->pub, "wlfc-thread");
5185         if (IS_ERR(dhd->pub.wlfc_thread)) {
5186                 DHD_ERROR(("create wlfc thread failed\n"));
5187                 goto fail;
5188         } else {
5189                 wake_up_process(dhd->pub.wlfc_thread);
5190         }
5191 #endif /* DHD_WLFC_THREAD */
5192 #endif /* PROP_TXSTATUS */
5193
5194         /* Initialize other structure content */
5195         init_waitqueue_head(&dhd->ioctl_resp_wait);
5196         init_waitqueue_head(&dhd->d3ack_wait);
5197         init_waitqueue_head(&dhd->ctrl_wait);
5198
5199         /* Initialize the spinlocks */
5200         spin_lock_init(&dhd->sdlock);
5201         spin_lock_init(&dhd->txqlock);
5202         spin_lock_init(&dhd->dhd_lock);
5203         spin_lock_init(&dhd->rxf_lock);
5204 #if defined(RXFRAME_THREAD)
5205         dhd->rxthread_enabled = TRUE;
5206 #endif /* defined(RXFRAME_THREAD) */
5207
5208 #ifdef DHDTCPACK_SUPPRESS
5209         spin_lock_init(&dhd->tcpack_lock);
5210 #endif /* DHDTCPACK_SUPPRESS */
5211
5212         /* Initialize Wakelock stuff */
5213         spin_lock_init(&dhd->wakelock_spinlock);
5214         dhd->wakelock_counter = 0;
5215         dhd->wakelock_wd_counter = 0;
5216         dhd->wakelock_rx_timeout_enable = 0;
5217         dhd->wakelock_ctrl_timeout_enable = 0;
5218 #ifdef CONFIG_HAS_WAKELOCK
5219         wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake");
5220         wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake");
5221         wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake");
5222         wake_lock_init(&dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake");
5223 #ifdef BCMPCIE_OOB_HOST_WAKE
5224         wake_lock_init(&dhd->wl_intrwake, WAKE_LOCK_SUSPEND, "wlan_oob_irq_wake");
5225 #endif /* BCMPCIE_OOB_HOST_WAKE */
5226 #endif /* CONFIG_HAS_WAKELOCK */
5227 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
5228         mutex_init(&dhd->dhd_net_if_mutex);
5229         mutex_init(&dhd->dhd_suspend_mutex);
5230 #endif
5231         dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
5232
5233         /* Attach and link in the protocol */
5234         if (dhd_prot_attach(&dhd->pub) != 0) {
5235                 DHD_ERROR(("dhd_prot_attach failed\n"));
5236                 goto fail;
5237         }
5238         dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH;
5239
5240 #ifdef WL_CFG80211
5241         /* Attach and link in the cfg80211 */
5242         if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) {
5243                 DHD_ERROR(("wl_cfg80211_attach failed\n"));
5244                 goto fail;
5245         }
5246
5247         dhd_monitor_init(&dhd->pub);
5248         dhd_state |= DHD_ATTACH_STATE_CFG80211;
5249 #endif
5250 #if defined(WL_WIRELESS_EXT)
5251         /* Attach and link in the iw */
5252         if (!(dhd_state &  DHD_ATTACH_STATE_CFG80211)) {
5253                 if (wl_iw_attach(net, (void *)&dhd->pub) != 0) {
5254                 DHD_ERROR(("wl_iw_attach failed\n"));
5255                 goto fail;
5256         }
5257         dhd_state |= DHD_ATTACH_STATE_WL_ATTACH;
5258         }
5259 #endif /* defined(WL_WIRELESS_EXT) */
5260
5261 #ifdef SHOW_LOGTRACE
5262         dhd_init_logstrs_array(&dhd->event_data);
5263 #endif /* SHOW_LOGTRACE */
5264
5265         if (dhd_sta_pool_init(&dhd->pub, DHD_MAX_STA) != BCME_OK) {
5266                 DHD_ERROR(("%s: Initializing %u sta\n", __FUNCTION__, DHD_MAX_STA));
5267                 goto fail;
5268         }
5269
5270
5271         /* Set up the watchdog timer */
5272         init_timer(&dhd->timer);
5273         dhd->timer.data = (ulong)dhd;
5274         dhd->timer.function = dhd_watchdog;
5275         dhd->default_wd_interval = dhd_watchdog_ms;
5276
5277         if (dhd_watchdog_prio >= 0) {
5278                 /* Initialize watchdog thread */
5279                 PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread");
5280
5281         } else {
5282                 dhd->thr_wdt_ctl.thr_pid = -1;
5283         }
5284
5285 #ifdef DEBUGGER
5286         debugger_init((void *) bus);
5287 #endif
5288
5289         /* Set up the bottom half handler */
5290         if (dhd_dpc_prio >= 0) {
5291                 /* Initialize DPC thread */
5292                 PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc");
5293         } else {
5294                 /*  use tasklet for dpc */
5295                 tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd);
5296                 dhd->thr_dpc_ctl.thr_pid = -1;
5297         }
5298
5299         if (dhd->rxthread_enabled) {
5300                 bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND);
5301                 /* Initialize RXF thread */
5302                 PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf");
5303         }
5304
5305         dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
5306
5307 #if defined(CONFIG_PM_SLEEP)
5308         if (!dhd_pm_notifier_registered) {
5309                 dhd_pm_notifier_registered = TRUE;
5310                 register_pm_notifier(&dhd_pm_notifier);
5311         }
5312 #endif /* CONFIG_PM_SLEEP */
5313
5314 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
5315         dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20;
5316         dhd->early_suspend.suspend = dhd_early_suspend;
5317         dhd->early_suspend.resume = dhd_late_resume;
5318         register_early_suspend(&dhd->early_suspend);
5319         dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE;
5320 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
5321
5322 #ifdef ARP_OFFLOAD_SUPPORT
5323         dhd->pend_ipaddr = 0;
5324         if (!dhd_inetaddr_notifier_registered) {
5325                 dhd_inetaddr_notifier_registered = TRUE;
5326                 register_inetaddr_notifier(&dhd_inetaddr_notifier);
5327         }
5328 #endif /* ARP_OFFLOAD_SUPPORT */
5329 #ifdef CONFIG_IPV6
5330         if (!dhd_inet6addr_notifier_registered) {
5331                 dhd_inet6addr_notifier_registered = TRUE;
5332                 register_inet6addr_notifier(&dhd_inet6addr_notifier);
5333         }
5334 #endif
5335         dhd->dhd_deferred_wq = dhd_deferred_work_init((void *)dhd);
5336 #ifdef DEBUG_CPU_FREQ
5337         dhd->new_freq = alloc_percpu(int);
5338         dhd->freq_trans.notifier_call = dhd_cpufreq_notifier;
5339         cpufreq_register_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER);
5340 #endif
5341 #ifdef DHDTCPACK_SUPPRESS
5342 #ifdef BCMSDIO
5343         dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_REPLACE);
5344 #elif defined(BCMPCIE)
5345         dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_HOLD);
5346 #else
5347         dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF);
5348 #endif /* BCMSDIO */
5349 #endif /* DHDTCPACK_SUPPRESS */
5350
5351         dhd_state |= DHD_ATTACH_STATE_DONE;
5352         dhd->dhd_state = dhd_state;
5353
5354         dhd_found++;
5355 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
5356         dhd_global = dhd;
5357 #endif /* CUSTOMER_HW20 && WLANAUDIO */
5358         return &dhd->pub;
5359
5360 fail:
5361         if (dhd_state >= DHD_ATTACH_STATE_DHD_ALLOC) {
5362                 DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n",
5363                         __FUNCTION__, dhd_state, &dhd->pub));
5364                 dhd->dhd_state = dhd_state;
5365                 dhd_detach(&dhd->pub);
5366                 dhd_free(&dhd->pub);
5367         }
5368
5369         return NULL;
5370 }
5371
5372 int dhd_get_fw_mode(dhd_info_t *dhdinfo)
5373 {
5374         if (strstr(dhdinfo->fw_path, "_apsta") != NULL)
5375                 return DHD_FLAG_HOSTAP_MODE;
5376         if (strstr(dhdinfo->fw_path, "_p2p") != NULL)
5377                 return DHD_FLAG_P2P_MODE;
5378         if (strstr(dhdinfo->fw_path, "_ibss") != NULL)
5379                 return DHD_FLAG_IBSS_MODE;
5380         if (strstr(dhdinfo->fw_path, "_mfg") != NULL)
5381                 return DHD_FLAG_MFG_MODE;
5382
5383         return DHD_FLAG_STA_MODE;
5384 }
5385
5386 bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo)
5387 {
5388         int fw_len;
5389         int nv_len;
5390         const char *fw = NULL;
5391         const char *nv = NULL;
5392         wifi_adapter_info_t *adapter = dhdinfo->adapter;
5393
5394
5395         /* Update firmware and nvram path. The path may be from adapter info or module parameter
5396          * The path from adapter info is used for initialization only (as it won't change).
5397          *
5398          * The firmware_path/nvram_path module parameter may be changed by the system at run
5399          * time. When it changes we need to copy it to dhdinfo->fw_path. Also Android private
5400          * command may change dhdinfo->fw_path. As such we need to clear the path info in
5401          * module parameter after it is copied. We won't update the path until the module parameter
5402          * is changed again (first character is not '\0')
5403          */
5404
5405         /* set default firmware and nvram path for built-in type driver */
5406         if (!dhd_download_fw_on_driverload) {
5407 #ifdef CONFIG_BCMDHD_FW_PATH
5408                 fw = CONFIG_BCMDHD_FW_PATH;
5409 #endif /* CONFIG_BCMDHD_FW_PATH */
5410 #ifdef CONFIG_BCMDHD_NVRAM_PATH
5411                 nv = CONFIG_BCMDHD_NVRAM_PATH;
5412 #endif /* CONFIG_BCMDHD_NVRAM_PATH */
5413         }
5414
5415         /* check if we need to initialize the path */
5416         if (dhdinfo->fw_path[0] == '\0') {
5417                 if (adapter && adapter->fw_path && adapter->fw_path[0] != '\0')
5418                         fw = adapter->fw_path;
5419
5420         }
5421         if (dhdinfo->nv_path[0] == '\0') {
5422                 if (adapter && adapter->nv_path && adapter->nv_path[0] != '\0')
5423                         nv = adapter->nv_path;
5424         }
5425
5426         /* Use module parameter if it is valid, EVEN IF the path has not been initialized
5427          *
5428          * TODO: need a solution for multi-chip, can't use the same firmware for all chips
5429          */
5430         if (firmware_path[0] != '\0')
5431                 fw = firmware_path;
5432         if (nvram_path[0] != '\0')
5433                 nv = nvram_path;
5434
5435         if (fw && fw[0] != '\0') {
5436                 fw_len = strlen(fw);
5437                 if (fw_len >= sizeof(dhdinfo->fw_path)) {
5438                         DHD_ERROR(("fw path len exceeds max len of dhdinfo->fw_path\n"));
5439                         return FALSE;
5440                 }
5441                 strncpy(dhdinfo->fw_path, fw, sizeof(dhdinfo->fw_path));
5442                 if (dhdinfo->fw_path[fw_len-1] == '\n')
5443                        dhdinfo->fw_path[fw_len-1] = '\0';
5444         }
5445         if (nv && nv[0] != '\0') {
5446                 nv_len = strlen(nv);
5447                 if (nv_len >= sizeof(dhdinfo->nv_path)) {
5448                         DHD_ERROR(("nvram path len exceeds max len of dhdinfo->nv_path\n"));
5449                         return FALSE;
5450                 }
5451                 strncpy(dhdinfo->nv_path, nv, sizeof(dhdinfo->nv_path));
5452                 if (dhdinfo->nv_path[nv_len-1] == '\n')
5453                        dhdinfo->nv_path[nv_len-1] = '\0';
5454         }
5455
5456         /* clear the path in module parameter */
5457         firmware_path[0] = '\0';
5458         nvram_path[0] = '\0';
5459
5460 #ifndef BCMEMBEDIMAGE
5461         /* fw_path and nv_path are not mandatory for BCMEMBEDIMAGE */
5462         if (dhdinfo->fw_path[0] == '\0') {
5463                 DHD_ERROR(("firmware path not found\n"));
5464                 return FALSE;
5465         }
5466         if (dhdinfo->nv_path[0] == '\0') {
5467                 DHD_ERROR(("nvram path not found\n"));
5468                 return FALSE;
5469         }
5470 #endif /* BCMEMBEDIMAGE */
5471
5472         return TRUE;
5473 }
5474
5475
5476 int
5477 dhd_bus_start(dhd_pub_t *dhdp)
5478 {
5479         int ret = -1;
5480         dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
5481         unsigned long flags;
5482
5483         ASSERT(dhd);
5484
5485         DHD_TRACE(("Enter %s:\n", __FUNCTION__));
5486
5487         DHD_PERIM_LOCK(dhdp);
5488
5489         /* try to download image and nvram to the dongle */
5490         if  (dhd->pub.busstate == DHD_BUS_DOWN && dhd_update_fw_nv_path(dhd)) {
5491                 DHD_INFO(("%s download fw %s, nv %s\n", __FUNCTION__, dhd->fw_path, dhd->nv_path));
5492                 ret = dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh,
5493                                                 dhd->fw_path, dhd->nv_path);
5494                 if (ret < 0) {
5495                         DHD_ERROR(("%s: failed to download firmware %s\n",
5496                                   __FUNCTION__, dhd->fw_path));
5497                         DHD_PERIM_UNLOCK(dhdp);
5498                         return ret;
5499                 }
5500         }
5501         if (dhd->pub.busstate != DHD_BUS_LOAD) {
5502                 DHD_PERIM_UNLOCK(dhdp);
5503                 return -ENETDOWN;
5504         }
5505
5506         dhd_os_sdlock(dhdp);
5507
5508         /* Start the watchdog timer */
5509         dhd->pub.tickcnt = 0;
5510         dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms);
5511
5512         /* Bring up the bus */
5513         if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) {
5514
5515                 DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
5516                 dhd_os_sdunlock(dhdp);
5517                 DHD_PERIM_UNLOCK(dhdp);
5518                 return ret;
5519         }
5520 #if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE)
5521 #if defined(BCMPCIE_OOB_HOST_WAKE)
5522         dhd_os_sdunlock(dhdp);
5523 #endif /* BCMPCIE_OOB_HOST_WAKE */
5524         /* Host registration for OOB interrupt */
5525         if (dhd_bus_oob_intr_register(dhdp)) {
5526                 /* deactivate timer and wait for the handler to finish */
5527 #if !defined(BCMPCIE_OOB_HOST_WAKE)
5528                 DHD_GENERAL_LOCK(&dhd->pub, flags);
5529                 dhd->wd_timer_valid = FALSE;
5530                 DHD_GENERAL_UNLOCK(&dhd->pub, flags);
5531                 dhd_os_sdunlock(dhdp);
5532                 del_timer_sync(&dhd->timer);
5533 #endif /* BCMPCIE_OOB_HOST_WAKE */
5534                 DHD_PERIM_UNLOCK(dhdp);
5535                 DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
5536                 DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
5537                 return -ENODEV;
5538         }
5539
5540 #if defined(BCMPCIE_OOB_HOST_WAKE)
5541         dhd_os_sdlock(dhdp);
5542         dhd_bus_oob_intr_set(dhdp, TRUE);
5543 #else
5544         /* Enable oob at firmware */
5545         dhd_enable_oob_intr(dhd->pub.bus, TRUE);
5546 #endif /* BCMPCIE_OOB_HOST_WAKE */
5547 #endif 
5548 #ifdef PCIE_FULL_DONGLE
5549         {
5550                 uint8 txpush = 0;
5551                 uint32 num_flowrings; /* includes H2D common rings */
5552                 num_flowrings = dhd_bus_max_h2d_queues(dhd->pub.bus, &txpush);
5553                 DHD_ERROR(("%s: Initializing %u flowrings\n", __FUNCTION__,
5554                         num_flowrings));
5555                 if ((ret = dhd_flow_rings_init(&dhd->pub, num_flowrings)) != BCME_OK) {
5556                         dhd_os_sdunlock(dhdp);
5557                         DHD_PERIM_UNLOCK(dhdp);
5558                         return ret;
5559                 }
5560         }
5561 #endif /* PCIE_FULL_DONGLE */
5562
5563         /* Do protocol initialization necessary for IOCTL/IOVAR */
5564         dhd_prot_init(&dhd->pub);
5565
5566         /* If bus is not ready, can't come up */
5567         if (dhd->pub.busstate != DHD_BUS_DATA) {
5568                 DHD_GENERAL_LOCK(&dhd->pub, flags);
5569                 dhd->wd_timer_valid = FALSE;
5570                 DHD_GENERAL_UNLOCK(&dhd->pub, flags);
5571                 dhd_os_sdunlock(dhdp);
5572                 del_timer_sync(&dhd->timer);
5573                 DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
5574                 DHD_PERIM_UNLOCK(dhdp);
5575                 DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
5576                 return -ENODEV;
5577         }
5578
5579         dhd_os_sdunlock(dhdp);
5580
5581         /* Bus is ready, query any dongle information */
5582         if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) {
5583                 DHD_PERIM_UNLOCK(dhdp);
5584                 return ret;
5585         }
5586
5587 #ifdef ARP_OFFLOAD_SUPPORT
5588         if (dhd->pend_ipaddr) {
5589 #ifdef AOE_IP_ALIAS_SUPPORT
5590                 aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0);
5591 #endif /* AOE_IP_ALIAS_SUPPORT */
5592                 dhd->pend_ipaddr = 0;
5593         }
5594 #endif /* ARP_OFFLOAD_SUPPORT */
5595
5596         DHD_PERIM_UNLOCK(dhdp);
5597         return 0;
5598 }
5599 #ifdef WLTDLS
5600 int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac)
5601 {
5602         char iovbuf[WLC_IOCTL_SMLEN];
5603         uint32 tdls = tdls_on;
5604         int ret = 0;
5605         uint32 tdls_auto_op = 0;
5606         uint32 tdls_idle_time = CUSTOM_TDLS_IDLE_MODE_SETTING;
5607         int32 tdls_rssi_high = CUSTOM_TDLS_RSSI_THRESHOLD_HIGH;
5608         int32 tdls_rssi_low = CUSTOM_TDLS_RSSI_THRESHOLD_LOW;
5609         BCM_REFERENCE(mac);
5610         if (!FW_SUPPORTED(dhd, tdls))
5611                 return BCME_ERROR;
5612
5613         if (dhd->tdls_enable == tdls_on)
5614                 goto auto_mode;
5615         bcm_mkiovar("tdls_enable", (char *)&tdls, sizeof(tdls), iovbuf, sizeof(iovbuf));
5616         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
5617                 DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret));
5618                 goto exit;
5619         }
5620         dhd->tdls_enable = tdls_on;
5621 auto_mode:
5622
5623         tdls_auto_op = auto_on;
5624         bcm_mkiovar("tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op),
5625                 iovbuf, sizeof(iovbuf));
5626         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5627                 sizeof(iovbuf), TRUE, 0)) < 0) {
5628                 DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret));
5629                 goto exit;
5630         }
5631
5632         if (tdls_auto_op) {
5633                 bcm_mkiovar("tdls_idle_time", (char *)&tdls_idle_time,
5634                         sizeof(tdls_idle_time), iovbuf, sizeof(iovbuf));
5635                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5636                         sizeof(iovbuf), TRUE, 0)) < 0) {
5637                         DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret));
5638                         goto exit;
5639                 }
5640                 bcm_mkiovar("tdls_rssi_high", (char *)&tdls_rssi_high, 4, iovbuf, sizeof(iovbuf));
5641                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5642                         sizeof(iovbuf), TRUE, 0)) < 0) {
5643                         DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret));
5644                         goto exit;
5645                 }
5646                 bcm_mkiovar("tdls_rssi_low", (char *)&tdls_rssi_low, 4, iovbuf, sizeof(iovbuf));
5647                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5648                         sizeof(iovbuf), TRUE, 0)) < 0) {
5649                         DHD_ERROR(("%s: tdls_rssi_low failed %d\n", __FUNCTION__, ret));
5650                         goto exit;
5651                 }
5652         }
5653
5654 exit:
5655         return ret;
5656 }
5657 int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac)
5658 {
5659         dhd_info_t *dhd = DHD_DEV_INFO(dev);
5660         int ret = 0;
5661         if (dhd)
5662                 ret = _dhd_tdls_enable(&dhd->pub, tdls_on, auto_on, mac);
5663         else
5664                 ret = BCME_ERROR;
5665         return ret;
5666 }
5667 #ifdef PCIE_FULL_DONGLE
5668 void dhd_tdls_update_peer_info(struct net_device *dev, bool connect, uint8 *da)
5669 {
5670         dhd_info_t *dhd = DHD_DEV_INFO(dev);
5671         dhd_pub_t *dhdp =  (dhd_pub_t *)&dhd->pub;
5672         tdls_peer_node_t *cur = dhdp->peer_tbl.node;
5673         tdls_peer_node_t *new = NULL, *prev = NULL;
5674         dhd_if_t *dhdif;
5675         uint8 sa[ETHER_ADDR_LEN];
5676         int ifidx = dhd_net2idx(dhd, dev);
5677
5678         if (ifidx == DHD_BAD_IF)
5679                 return;
5680
5681         dhdif = dhd->iflist[ifidx];
5682         memcpy(sa, dhdif->mac_addr, ETHER_ADDR_LEN);
5683
5684         if (connect) {
5685                 while (cur != NULL) {
5686                         if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
5687                                 DHD_ERROR(("%s: TDLS Peer exist already %d\n",
5688                                         __FUNCTION__, __LINE__));
5689                                 return;
5690                         }
5691                         cur = cur->next;
5692                 }
5693
5694                 new = MALLOC(dhdp->osh, sizeof(tdls_peer_node_t));
5695                 if (new == NULL) {
5696                         DHD_ERROR(("%s: Failed to allocate memory\n", __FUNCTION__));
5697                         return;
5698                 }
5699                 memcpy(new->addr, da, ETHER_ADDR_LEN);
5700                 new->next = dhdp->peer_tbl.node;
5701                 dhdp->peer_tbl.node = new;
5702                 dhdp->peer_tbl.tdls_peer_count++;
5703
5704         } else {
5705                 while (cur != NULL) {
5706                         if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
5707                                 dhd_flow_rings_delete_for_peer(dhdp, ifidx, da);
5708                                 if (prev)
5709                                         prev->next = cur->next;
5710                                 else
5711                                         dhdp->peer_tbl.node = cur->next;
5712                                 MFREE(dhdp->osh, cur, sizeof(tdls_peer_node_t));
5713                                 dhdp->peer_tbl.tdls_peer_count--;
5714                                 return;
5715                         }
5716                         prev = cur;
5717                         cur = cur->next;
5718                 }
5719                 DHD_ERROR(("%s: TDLS Peer Entry Not found\n", __FUNCTION__));
5720         }
5721 }
5722 #endif /* PCIE_FULL_DONGLE */
5723 #endif 
5724
5725 bool dhd_is_concurrent_mode(dhd_pub_t *dhd)
5726 {
5727         if (!dhd)
5728                 return FALSE;
5729
5730         if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE)
5731                 return TRUE;
5732         else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) ==
5733                 DHD_FLAG_CONCURR_SINGLE_CHAN_MODE)
5734                 return TRUE;
5735         else
5736                 return FALSE;
5737 }
5738 #if !defined(AP) && defined(WLP2P)
5739 /* From Android JerryBean release, the concurrent mode is enabled by default and the firmware
5740  * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA
5741  * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware
5742  * would still be named as fw_bcmdhd_apsta.
5743  */
5744 uint32
5745 dhd_get_concurrent_capabilites(dhd_pub_t *dhd)
5746 {
5747         int32 ret = 0;
5748         char buf[WLC_IOCTL_SMLEN];
5749         bool mchan_supported = FALSE;
5750         /* if dhd->op_mode is already set for HOSTAP and Manufacturing
5751          * test mode, that means we only will use the mode as it is
5752          */
5753         if (dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))
5754                 return 0;
5755         if (FW_SUPPORTED(dhd, vsdb)) {
5756                 mchan_supported = TRUE;
5757         }
5758         if (!FW_SUPPORTED(dhd, p2p)) {
5759                 DHD_TRACE(("Chip does not support p2p\n"));
5760                 return 0;
5761         }
5762         else {
5763                 /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */
5764                 memset(buf, 0, sizeof(buf));
5765                 bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf));
5766                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
5767                         FALSE, 0)) < 0) {
5768                         DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret));
5769                         return 0;
5770                 }
5771                 else {
5772                         if (buf[0] == 1) {
5773                                 /* By default, chip supports single chan concurrency,
5774                                 * now lets check for mchan
5775                                 */
5776                                 ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE;
5777                                 if (mchan_supported)
5778                                         ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE;
5779 #if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
5780                                 /* For customer_hw4, although ICS,
5781                                 * we still support concurrent mode
5782                                 */
5783                                 return ret;
5784 #else
5785                                 return 0;
5786 #endif 
5787                         }
5788                 }
5789         }
5790         return 0;
5791 }
5792 #endif 
5793
5794 #ifdef SUPPORT_AP_POWERSAVE
5795 #define RXCHAIN_PWRSAVE_PPS                     10
5796 #define RXCHAIN_PWRSAVE_QUIET_TIME              10
5797 #define RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK        0
5798 int dhd_set_ap_powersave(dhd_pub_t *dhdp, int ifidx, int enable)
5799 {
5800         char iovbuf[128];
5801         int32 pps = RXCHAIN_PWRSAVE_PPS;
5802         int32 quiet_time = RXCHAIN_PWRSAVE_QUIET_TIME;
5803         int32 stas_assoc_check = RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK;
5804
5805         if (enable) {
5806                 bcm_mkiovar("rxchain_pwrsave_enable", (char *)&enable, 4, iovbuf, sizeof(iovbuf));
5807                 if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
5808                     iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
5809                         DHD_ERROR(("Failed to enable AP power save"));
5810                 }
5811                 bcm_mkiovar("rxchain_pwrsave_pps", (char *)&pps, 4, iovbuf, sizeof(iovbuf));
5812                 if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
5813                     iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
5814                         DHD_ERROR(("Failed to set pps"));
5815                 }
5816                 bcm_mkiovar("rxchain_pwrsave_quiet_time", (char *)&quiet_time,
5817                 4, iovbuf, sizeof(iovbuf));
5818                 if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
5819                     iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
5820                         DHD_ERROR(("Failed to set quiet time"));
5821                 }
5822                 bcm_mkiovar("rxchain_pwrsave_stas_assoc_check", (char *)&stas_assoc_check,
5823                 4, iovbuf, sizeof(iovbuf));
5824                 if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
5825                     iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
5826                         DHD_ERROR(("Failed to set stas assoc check"));
5827                 }
5828         } else {
5829                 bcm_mkiovar("rxchain_pwrsave_enable", (char *)&enable, 4, iovbuf, sizeof(iovbuf));
5830                 if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
5831                     iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
5832                         DHD_ERROR(("Failed to disable AP power save"));
5833                 }
5834         }
5835
5836         return 0;
5837 }
5838 #endif /* SUPPORT_AP_POWERSAVE */
5839
5840
5841
5842 int
5843 dhd_preinit_ioctls(dhd_pub_t *dhd)
5844 {
5845         int ret = 0;
5846         char eventmask[WL_EVENTING_MASK_LEN];
5847         char iovbuf[WL_EVENTING_MASK_LEN + 12]; /*  Room for "event_msgs" + '\0' + bitvec  */
5848         uint32 buf_key_b4_m4 = 1;
5849         uint32 rpt_hitxrate = 1;
5850         uint8 msglen;
5851         eventmsgs_ext_t *eventmask_msg = NULL;
5852         char* iov_buf = NULL;
5853         int ret2 = 0;
5854 #if defined(CUSTOM_AMPDU_BA_WSIZE)
5855         uint32 ampdu_ba_wsize = 0;
5856 #endif 
5857 #if defined(CUSTOM_AMPDU_MPDU)
5858         int32 ampdu_mpdu = 0;
5859 #endif
5860 #if defined(CUSTOM_AMPDU_RELEASE)
5861         int32 ampdu_release = 0;
5862 #endif
5863 #if defined(CUSTOM_AMSDU_AGGSF)
5864         int32 amsdu_aggsf = 0;
5865 #endif
5866
5867 #if defined(BCMSDIO)
5868 #ifdef PROP_TXSTATUS
5869         int wlfc_enable = TRUE;
5870 #ifndef DISABLE_11N
5871         uint32 hostreorder = 1;
5872 #endif /* DISABLE_11N */
5873 #endif /* PROP_TXSTATUS */
5874 #endif 
5875 #ifdef PCIE_FULL_DONGLE
5876         uint32 wl_ap_isolate;
5877 #endif /* PCIE_FULL_DONGLE */
5878
5879 #ifdef DHD_ENABLE_LPC
5880         uint32 lpc = 1;
5881 #endif /* DHD_ENABLE_LPC */
5882         uint power_mode = PM_FAST;
5883         uint32 dongle_align = DHD_SDALIGN;
5884 #if defined(BCMSDIO)
5885         uint32 glom = CUSTOM_GLOM_SETTING;
5886 #endif /* defined(BCMSDIO) */
5887 #if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
5888         uint32 credall = 1;
5889 #endif
5890 #if defined(VSDB) || defined(ROAM_ENABLE)
5891         uint bcn_timeout = CUSTOM_BCN_TIMEOUT;
5892 #else
5893         uint bcn_timeout = 4;
5894 #endif 
5895         uint retry_max = 3;
5896 #if defined(ARP_OFFLOAD_SUPPORT)
5897         int arpoe = 1;
5898 #endif
5899         int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME;
5900         int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME;
5901         int scan_passive_time = DHD_SCAN_PASSIVE_TIME;
5902         char buf[WLC_IOCTL_SMLEN];
5903         char *ptr;
5904         uint32 listen_interval = CUSTOM_LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
5905 #ifdef ROAM_ENABLE
5906         uint roamvar = 0;
5907         int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL};
5908         int roam_scan_period[2] = {10, WLC_BAND_ALL};
5909         int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL};
5910 #ifdef ROAM_AP_ENV_DETECTION
5911         int roam_env_mode = AP_ENV_INDETERMINATE;
5912 #endif /* ROAM_AP_ENV_DETECTION */
5913 #ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC
5914         int roam_fullscan_period = 60;
5915 #else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */
5916         int roam_fullscan_period = 120;
5917 #endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */
5918 #else
5919 #ifdef DISABLE_BUILTIN_ROAM
5920         uint roamvar = 1;
5921 #endif /* DISABLE_BUILTIN_ROAM */
5922 #endif /* ROAM_ENABLE */
5923
5924 #if defined(SOFTAP)
5925         uint dtim = 1;
5926 #endif
5927 #if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
5928         uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
5929         struct ether_addr p2p_ea;
5930 #endif
5931 #ifdef SOFTAP_UAPSD_OFF
5932         uint32 wme_apsd = 0;
5933 #endif /* SOFTAP_UAPSD_OFF */
5934 #if (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC)
5935         uint32 apsta = 1; /* Enable APSTA mode */
5936 #elif defined(SOFTAP_AND_GC)
5937         uint32 apsta = 0;
5938         int ap_mode = 1;
5939 #endif /* (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC) */
5940 #ifdef GET_CUSTOM_MAC_ENABLE
5941         struct ether_addr ea_addr;
5942 #endif /* GET_CUSTOM_MAC_ENABLE */
5943
5944 #ifdef CUSTOM_AMPDU_BA_WSIZE
5945         struct ampdu_tid_control atc;
5946 #endif
5947 #ifdef DISABLE_11N
5948         uint32 nmode = 0;
5949 #endif /* DISABLE_11N */
5950
5951 #ifdef USE_WL_TXBF
5952         uint32 txbf = 1;
5953 #endif /* USE_WL_TXBF */
5954 #ifdef USE_WL_FRAMEBURST
5955         uint32 frameburst = 1;
5956 #endif /* USE_WL_FRAMEBURST */
5957 #ifdef CUSTOM_PSPRETEND_THR
5958         uint32 pspretend_thr = CUSTOM_PSPRETEND_THR;
5959 #endif
5960 #ifdef RXCB
5961         uint32 rxcb = 1;
5962 #endif
5963 #ifdef PKT_FILTER_SUPPORT
5964         dhd_pkt_filter_enable = TRUE;
5965 #endif /* PKT_FILTER_SUPPORT */
5966 #ifdef WLTDLS
5967         dhd->tdls_enable = FALSE;
5968 #endif /* WLTDLS */
5969         dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM;
5970         DHD_TRACE(("Enter %s\n", __FUNCTION__));
5971         dhd->op_mode = 0;
5972         if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) ||
5973                 (op_mode == DHD_FLAG_MFG_MODE)) {
5974                 /* Check and adjust IOCTL response timeout for Manufactring firmware */
5975                 dhd_os_set_ioctl_resp_timeout(MFG_IOCTL_RESP_TIMEOUT);
5976                 DHD_ERROR(("%s : Set IOCTL response time for Manufactring Firmware\n",
5977                         __FUNCTION__));
5978         }
5979         else {
5980                 dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT);
5981                 DHD_INFO(("%s : Set IOCTL response time.\n", __FUNCTION__));
5982         }
5983 #ifdef GET_CUSTOM_MAC_ENABLE
5984         ret = wifi_platform_get_mac_addr(dhd->info->adapter, ea_addr.octet);
5985         if (!ret) {
5986                 memset(buf, 0, sizeof(buf));
5987                 bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
5988                 ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
5989                 if (ret < 0) {
5990                         DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
5991                         ret = BCME_NOTUP;
5992                         goto done;
5993                 }
5994                 memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN);
5995         } else {
5996 #endif /* GET_CUSTOM_MAC_ENABLE */
5997                 /* Get the default device MAC address directly from firmware */
5998                 memset(buf, 0, sizeof(buf));
5999                 bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf));
6000                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
6001                         FALSE, 0)) < 0) {
6002                         DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret));
6003                         ret = BCME_NOTUP;
6004                         goto done;
6005                 }
6006                 /* Update public MAC address after reading from Firmware */
6007                 memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
6008
6009 #ifdef GET_CUSTOM_MAC_ENABLE
6010         }
6011 #endif /* GET_CUSTOM_MAC_ENABLE */
6012
6013         /* get a capabilities from firmware */
6014         memset(dhd->fw_capabilities, 0, sizeof(dhd->fw_capabilities));
6015         bcm_mkiovar("cap", 0, 0, dhd->fw_capabilities, sizeof(dhd->fw_capabilities));
6016         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, dhd->fw_capabilities,
6017                 sizeof(dhd->fw_capabilities), FALSE, 0)) < 0) {
6018                 DHD_ERROR(("%s: Get Capability failed (error=%d)\n",
6019                         __FUNCTION__, ret));
6020                 goto done;
6021         }
6022         if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) ||
6023                 (op_mode == DHD_FLAG_HOSTAP_MODE)) {
6024 #ifdef SET_RANDOM_MAC_SOFTAP
6025                 uint rand_mac;
6026 #endif
6027                 dhd->op_mode = DHD_FLAG_HOSTAP_MODE;
6028 #if defined(ARP_OFFLOAD_SUPPORT)
6029                         arpoe = 0;
6030 #endif
6031 #ifdef PKT_FILTER_SUPPORT
6032                         dhd_pkt_filter_enable = FALSE;
6033 #endif
6034 #ifdef SET_RANDOM_MAC_SOFTAP
6035                 SRANDOM32((uint)jiffies);
6036                 rand_mac = RANDOM32();
6037                 iovbuf[0] = 0x02;                          /* locally administered bit */
6038                 iovbuf[1] = 0x1A;
6039                 iovbuf[2] = 0x11;
6040                 iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0;
6041                 iovbuf[4] = (unsigned char)(rand_mac >> 8);
6042                 iovbuf[5] = (unsigned char)(rand_mac >> 16);
6043
6044                 bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf));
6045                 ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
6046                 if (ret < 0) {
6047                         DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
6048                 } else
6049                         memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
6050 #endif /* SET_RANDOM_MAC_SOFTAP */
6051 #if !defined(AP) && defined(WL_CFG80211)
6052                 /* Turn off MPC in AP mode */
6053                 bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
6054                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6055                         sizeof(iovbuf), TRUE, 0)) < 0) {
6056                         DHD_ERROR(("%s mpc for HostAPD failed  %d\n", __FUNCTION__, ret));
6057                 }
6058 #endif
6059 #ifdef SUPPORT_AP_POWERSAVE
6060                 dhd_set_ap_powersave(dhd, 0, TRUE);
6061 #endif
6062 #ifdef SOFTAP_UAPSD_OFF
6063         bcm_mkiovar("wme_apsd", (char *)&wme_apsd, 4, iovbuf, sizeof(iovbuf));
6064         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
6065                 DHD_ERROR(("%s: set wme_apsd 0 fail (error=%d)\n", __FUNCTION__, ret));
6066 #endif /* SOFTAP_UAPSD_OFF */
6067         } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) ||
6068                 (op_mode == DHD_FLAG_MFG_MODE)) {
6069 #if defined(ARP_OFFLOAD_SUPPORT)
6070                 arpoe = 0;
6071 #endif /* ARP_OFFLOAD_SUPPORT */
6072 #ifdef PKT_FILTER_SUPPORT
6073                 dhd_pkt_filter_enable = FALSE;
6074 #endif /* PKT_FILTER_SUPPORT */
6075                 dhd->op_mode = DHD_FLAG_MFG_MODE;
6076         } else {
6077                 uint32 concurrent_mode = 0;
6078                 if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_P2P_MODE) ||
6079                         (op_mode == DHD_FLAG_P2P_MODE)) {
6080 #if defined(ARP_OFFLOAD_SUPPORT)
6081                         arpoe = 0;
6082 #endif
6083 #ifdef PKT_FILTER_SUPPORT
6084                         dhd_pkt_filter_enable = FALSE;
6085 #endif
6086                         dhd->op_mode = DHD_FLAG_P2P_MODE;
6087                 } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_IBSS_MODE) ||
6088                         (op_mode == DHD_FLAG_IBSS_MODE)) {
6089                         dhd->op_mode = DHD_FLAG_IBSS_MODE;
6090                 } else
6091                         dhd->op_mode = DHD_FLAG_STA_MODE;
6092 #if !defined(AP) && defined(WLP2P)
6093                 if (dhd->op_mode != DHD_FLAG_IBSS_MODE &&
6094                         (concurrent_mode = dhd_get_concurrent_capabilites(dhd))) {
6095 #if defined(ARP_OFFLOAD_SUPPORT)
6096                         arpoe = 1;
6097 #endif
6098                         dhd->op_mode |= concurrent_mode;
6099                 }
6100
6101                 /* Check if we are enabling p2p */
6102                 if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
6103                         bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
6104                         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
6105                                 iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
6106                                 DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret));
6107                         }
6108
6109 #if defined(SOFTAP_AND_GC)
6110                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_AP,
6111                         (char *)&ap_mode, sizeof(ap_mode), TRUE, 0)) < 0) {
6112                                 DHD_ERROR(("%s WLC_SET_AP failed %d\n", __FUNCTION__, ret));
6113                 }
6114 #endif
6115                         memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN);
6116                         ETHER_SET_LOCALADDR(&p2p_ea);
6117                         bcm_mkiovar("p2p_da_override", (char *)&p2p_ea,
6118                                 ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf));
6119                         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
6120                                 iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
6121                                 DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret));
6122                         } else {
6123                                 DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n"));
6124                         }
6125                 }
6126 #else
6127         (void)concurrent_mode;
6128 #endif 
6129         }
6130
6131         DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n",
6132                 dhd->op_mode, MAC2STRDBG(dhd->mac.octet)));
6133         /* Set Country code  */
6134         if (dhd->dhd_cspec.ccode[0] != 0) {
6135                 bcm_mkiovar("country", (char *)&dhd->dhd_cspec,
6136                         sizeof(wl_country_t), iovbuf, sizeof(iovbuf));
6137                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
6138                         DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
6139         }
6140
6141
6142         /* Set Listen Interval */
6143         bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf));
6144         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
6145                 DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret));
6146
6147 #if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM)
6148         /* Disable built-in roaming to allowed ext supplicant to take care of roaming */
6149         bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
6150         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6151 #endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */
6152 #if defined(ROAM_ENABLE)
6153         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger,
6154                 sizeof(roam_trigger), TRUE, 0)) < 0)
6155                 DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret));
6156         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period,
6157                 sizeof(roam_scan_period), TRUE, 0)) < 0)
6158                 DHD_ERROR(("%s: roam scan period set failed %d\n", __FUNCTION__, ret));
6159         if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta,
6160                 sizeof(roam_delta), TRUE, 0)) < 0)
6161                 DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret));
6162         bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf));
6163         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
6164                 DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret));
6165 #ifdef ROAM_AP_ENV_DETECTION
6166         if (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER) {
6167                 bcm_mkiovar("roam_env_detection", (char *)&roam_env_mode,
6168                         4, iovbuf, sizeof(iovbuf));
6169                 if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) == BCME_OK)
6170                         dhd->roam_env_detection = TRUE;
6171                 else {
6172                         dhd->roam_env_detection = FALSE;
6173                 }
6174         }
6175 #endif /* ROAM_AP_ENV_DETECTION */
6176 #endif /* ROAM_ENABLE */
6177
6178 #ifdef WLTDLS
6179         /* by default TDLS on and auto mode off */
6180         _dhd_tdls_enable(dhd, true, false, NULL);
6181 #endif /* WLTDLS */
6182
6183 #ifdef DHD_ENABLE_LPC
6184 if (bcmdhd_dhd_enable_lpc) {
6185         /* Set lpc 1 */
6186         bcm_mkiovar("lpc", (char *)&lpc, 4, iovbuf, sizeof(iovbuf));
6187         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6188                 sizeof(iovbuf), TRUE, 0)) < 0) {
6189                 DHD_ERROR(("%s Set lpc failed  %d\n", __FUNCTION__, ret));
6190         }
6191 }
6192 #endif /* DHD_ENABLE_LPC */
6193
6194         /* Set PowerSave mode */
6195         dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0);
6196
6197         /* Match Host and Dongle rx alignment */
6198         bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
6199         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6200
6201 #if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
6202         /* enable credall to reduce the chance of no bus credit happened. */
6203         bcm_mkiovar("bus:credall", (char *)&credall, 4, iovbuf, sizeof(iovbuf));
6204         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6205 #endif
6206
6207 #if defined(BCMSDIO)
6208         if (glom != DEFAULT_GLOM_VALUE) {
6209                 DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom));
6210                 bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
6211                 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6212         }
6213 #endif /* defined(BCMSDIO) */
6214
6215         /* Setup timeout if Beacons are lost and roam is off to report link down */
6216         bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
6217         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6218         /* Setup assoc_retry_max count to reconnect target AP in dongle */
6219         bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
6220         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6221 #if defined(AP) && !defined(WLP2P)
6222         /* Turn off MPC in AP mode */
6223         bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
6224         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6225         bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
6226         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6227 #endif /* defined(AP) && !defined(WLP2P) */
6228
6229
6230 #if defined(SOFTAP)
6231         if (ap_fw_loaded == TRUE) {
6232                 dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0);
6233         }
6234 #endif 
6235
6236 #if defined(KEEP_ALIVE)
6237         {
6238         /* Set Keep Alive : be sure to use FW with -keepalive */
6239         int res;
6240
6241 #if defined(SOFTAP)
6242         if (ap_fw_loaded == FALSE)
6243 #endif 
6244                 if (!(dhd->op_mode &
6245                         (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))) {
6246                         if ((res = dhd_keep_alive_onoff(dhd)) < 0)
6247                                 DHD_ERROR(("%s set keeplive failed %d\n",
6248                                 __FUNCTION__, res));
6249                 }
6250         }
6251 #endif /* defined(KEEP_ALIVE) */
6252
6253 #ifdef USE_WL_TXBF
6254 if (bcmdhd_use_wl_txbf) {
6255         bcm_mkiovar("txbf", (char *)&txbf, 4, iovbuf, sizeof(iovbuf));
6256         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6257                 sizeof(iovbuf), TRUE, 0)) < 0) {
6258                 DHD_ERROR(("%s Set txbf failed  %d\n", __FUNCTION__, ret));
6259         }
6260 }
6261 #endif /* USE_WL_TXBF */
6262 #ifdef USE_WL_FRAMEBURST
6263 if (bcmdhd_use_wl_frameburst) {
6264         /* Set frameburst to value */
6265         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_FAKEFRAG, (char *)&frameburst,
6266                 sizeof(frameburst), TRUE, 0)) < 0) {
6267                 DHD_ERROR(("%s Set frameburst failed  %d\n", __FUNCTION__, ret));
6268         }
6269 }
6270 #endif /* USE_WL_FRAMEBURST */
6271 #if defined(CUSTOM_AMPDU_BA_WSIZE)
6272         /* Set ampdu ba wsize to 64 or 16 */
6273 #ifdef CUSTOM_AMPDU_BA_WSIZE
6274         ampdu_ba_wsize = CUSTOM_AMPDU_BA_WSIZE;
6275 #endif
6276         if (ampdu_ba_wsize != 0) {
6277                 bcm_mkiovar("ampdu_ba_wsize", (char *)&ampdu_ba_wsize, 4, iovbuf, sizeof(iovbuf));
6278                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6279                         sizeof(iovbuf), TRUE, 0)) < 0) {
6280                         DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed  %d\n",
6281                                 __FUNCTION__, ampdu_ba_wsize, ret));
6282                 }
6283         }
6284         atc.tid = 7;
6285         atc.enable = 0;
6286         bcm_mkiovar("ampdu_rx_tid", (char *)&atc, sizeof(atc), iovbuf, sizeof(iovbuf));
6287         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6288 #endif 
6289
6290         iov_buf = (char*)kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
6291         if (iov_buf == NULL) {
6292                 DHD_ERROR(("failed to allocate %d bytes for iov_buf\n", WLC_IOCTL_SMLEN));
6293                 ret = BCME_NOMEM;
6294                 goto done;
6295         }
6296
6297 #if defined(CUSTOM_AMPDU_MPDU)
6298 if (bcmdhd_use_custom_ampdu_mpdu) {
6299         ampdu_mpdu = CUSTOM_AMPDU_MPDU;
6300         if (ampdu_mpdu != 0 && (ampdu_mpdu <= ampdu_ba_wsize)) {
6301                 bcm_mkiovar("ampdu_mpdu", (char *)&ampdu_mpdu, 4, iovbuf, sizeof(iovbuf));
6302                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6303                         sizeof(iovbuf), TRUE, 0)) < 0) {
6304                         DHD_ERROR(("%s Set ampdu_mpdu to %d failed  %d\n",
6305                                 __FUNCTION__, CUSTOM_AMPDU_MPDU, ret));
6306                 }
6307         }
6308 }
6309 #endif /* CUSTOM_AMPDU_MPDU */
6310
6311 #if defined(CUSTOM_AMPDU_RELEASE)
6312         ampdu_release = CUSTOM_AMPDU_RELEASE;
6313         if (ampdu_release != 0 && (ampdu_release <= ampdu_ba_wsize)) {
6314                 bcm_mkiovar("ampdu_release", (char *)&ampdu_release, 4, iovbuf, sizeof(iovbuf));
6315                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6316                         sizeof(iovbuf), TRUE, 0)) < 0) {
6317                         DHD_ERROR(("%s Set ampdu_release to %d failed  %d\n",
6318                                 __FUNCTION__, CUSTOM_AMPDU_RELEASE, ret));
6319                 }
6320         }
6321 #endif /* CUSTOM_AMPDU_RELEASE */
6322
6323 #if defined(CUSTOM_AMSDU_AGGSF)
6324         amsdu_aggsf = CUSTOM_AMSDU_AGGSF;
6325         if (amsdu_aggsf != 0) {
6326                 bcm_mkiovar("amsdu_aggsf", (char *)&amsdu_aggsf, 4, iovbuf, sizeof(iovbuf));
6327                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6328                         sizeof(iovbuf), TRUE, 0)) < 0) {
6329                         DHD_ERROR(("%s Set amsdu_aggsf to %d failed  %d\n",
6330                                 __FUNCTION__, CUSTOM_AMSDU_AGGSF, ret));
6331                 }
6332         }
6333 #endif /* CUSTOM_AMSDU_AGGSF */
6334
6335 #ifdef CUSTOM_PSPRETEND_THR
6336 if (bcmdhd_use_custom_pspretend_thr) {
6337         /* Turn off MPC in AP mode */
6338         bcm_mkiovar("pspretend_threshold", (char *)&pspretend_thr, 4,
6339                 iovbuf, sizeof(iovbuf));
6340         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6341                 sizeof(iovbuf), TRUE, 0)) < 0) {
6342                 DHD_ERROR(("%s pspretend_threshold for HostAPD failed  %d\n",
6343                         __FUNCTION__, ret));
6344         }
6345 }
6346 #endif
6347
6348         /* Set the rpt_hitxrate to 1 so that link speed updated by WLC_GET_RATE
6349         *  is the maximum trasnmit rate
6350         *  rpt_hitxrate 0 : Here the rate reported is the most used rate in
6351         *                       the link.
6352         *  rpt_hitxrate 1 : Here the rate reported is the highest used rate
6353         *                       in the link.
6354         */
6355         bcm_mkiovar("rpt_hitxrate", (char *)&rpt_hitxrate, 4, iovbuf,
6356                         sizeof(iovbuf));
6357         ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6358                                 sizeof(iovbuf), TRUE, 0);
6359         if (ret < 0) {
6360                 DHD_ERROR(("%s Set rpt_hitxrate failed  %d\n", __FUNCTION__, ret));
6361         }
6362
6363         bcm_mkiovar("buf_key_b4_m4", (char *)&buf_key_b4_m4, 4, iovbuf, sizeof(iovbuf));
6364         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6365                 sizeof(iovbuf), TRUE, 0)) < 0) {
6366                 DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret));
6367         }
6368
6369         /* Read event_msgs mask */
6370         bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
6371         if ((ret  = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) {
6372                 DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret));
6373                 goto done;
6374         }
6375         bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
6376
6377         /* Setup event_msgs */
6378         setbit(eventmask, WLC_E_SET_SSID);
6379         setbit(eventmask, WLC_E_PRUNE);
6380         setbit(eventmask, WLC_E_AUTH);
6381         setbit(eventmask, WLC_E_AUTH_IND);
6382         setbit(eventmask, WLC_E_ASSOC);
6383         setbit(eventmask, WLC_E_REASSOC);
6384         setbit(eventmask, WLC_E_REASSOC_IND);
6385         setbit(eventmask, WLC_E_DEAUTH);
6386         setbit(eventmask, WLC_E_DEAUTH_IND);
6387         setbit(eventmask, WLC_E_DISASSOC_IND);
6388         setbit(eventmask, WLC_E_DISASSOC);
6389         setbit(eventmask, WLC_E_JOIN);
6390         setbit(eventmask, WLC_E_START);
6391         setbit(eventmask, WLC_E_ASSOC_IND);
6392         setbit(eventmask, WLC_E_PSK_SUP);
6393         setbit(eventmask, WLC_E_LINK);
6394         setbit(eventmask, WLC_E_NDIS_LINK);
6395         setbit(eventmask, WLC_E_MIC_ERROR);
6396         setbit(eventmask, WLC_E_ASSOC_REQ_IE);
6397         setbit(eventmask, WLC_E_ASSOC_RESP_IE);
6398 #ifndef WL_CFG80211
6399         setbit(eventmask, WLC_E_PMKID_CACHE);
6400         setbit(eventmask, WLC_E_TXFAIL);
6401 #endif
6402         setbit(eventmask, WLC_E_JOIN_START);
6403         setbit(eventmask, WLC_E_SCAN_COMPLETE);
6404 #ifdef WLMEDIA_HTSF
6405         setbit(eventmask, WLC_E_HTSFSYNC);
6406 #endif /* WLMEDIA_HTSF */
6407 #ifdef PNO_SUPPORT
6408         setbit(eventmask, WLC_E_PFN_NET_FOUND);
6409         setbit(eventmask, WLC_E_PFN_BEST_BATCHING);
6410         setbit(eventmask, WLC_E_PFN_BSSID_NET_FOUND);
6411         setbit(eventmask, WLC_E_PFN_BSSID_NET_LOST);
6412 #endif /* PNO_SUPPORT */
6413         /* enable dongle roaming event */
6414         /* WLC_E_ROAM event is depricated for bcm4354
6415            WLC_E_BSSID event is used for roaming in bcm4354*/
6416 #ifndef DISABLE_ROAM_EVENT
6417 if (!bcmdhd_disable_roam_event) {
6418         setbit(eventmask, WLC_E_ROAM);
6419 }
6420 #endif /* DISABLE_ROAM_EVENT */
6421         setbit(eventmask, WLC_E_BSSID);
6422 #ifdef WLTDLS
6423         setbit(eventmask, WLC_E_TDLS_PEER_EVENT);
6424 #endif /* WLTDLS */
6425 #ifdef WL_CFG80211
6426         setbit(eventmask, WLC_E_ESCAN_RESULT);
6427         if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
6428                 setbit(eventmask, WLC_E_ACTION_FRAME_RX);
6429                 setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE);
6430         }
6431 #endif /* WL_CFG80211 */
6432         setbit(eventmask, WLC_E_TRACE);
6433         setbit(eventmask, WLC_E_CSA_COMPLETE_IND);
6434         /* Write updated Event mask */
6435         bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
6436         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
6437                 DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret));
6438                 goto done;
6439         }
6440
6441         /* make up event mask ext message iovar for event larger than 128 */
6442         msglen = ROUNDUP(WLC_E_LAST, NBBY)/NBBY + EVENTMSGS_EXT_STRUCT_SIZE;
6443         eventmask_msg = (eventmsgs_ext_t*)kmalloc(msglen, GFP_KERNEL);
6444         if (eventmask_msg == NULL) {
6445                 DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", msglen));
6446                 ret = BCME_NOMEM;
6447                 goto done;
6448         }
6449         bzero(eventmask_msg, msglen);
6450         eventmask_msg->ver = EVENTMSGS_VER;
6451         eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
6452
6453         /* Read event_msgs_ext mask */
6454         bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, WLC_IOCTL_SMLEN);
6455         ret2  = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iov_buf, WLC_IOCTL_SMLEN, FALSE, 0);
6456         if (ret2 != BCME_UNSUPPORTED)
6457                 ret = ret2;
6458         if (ret2 == 0) { /* event_msgs_ext must be supported */
6459                 bcopy(iov_buf, eventmask_msg, msglen);
6460
6461 #ifdef BT_WIFI_HANDOVER
6462                 setbit(eventmask_msg->mask, WLC_E_BT_WIFI_HANDOVER_REQ);
6463 #endif /* BT_WIFI_HANDOVER */
6464
6465                 /* Write updated Event mask */
6466                 eventmask_msg->ver = EVENTMSGS_VER;
6467                 eventmask_msg->command = EVENTMSGS_SET_MASK;
6468                 eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
6469                 bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg,
6470                         msglen, iov_buf, WLC_IOCTL_SMLEN);
6471                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
6472                         iov_buf, WLC_IOCTL_SMLEN, TRUE, 0)) < 0) {
6473                         DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret));
6474                         goto done;
6475                 }
6476         } else if (ret2 < 0 && ret2 != BCME_UNSUPPORTED) {
6477                 DHD_ERROR(("%s read event mask ext failed %d\n", __FUNCTION__, ret2));
6478                 goto done;
6479         } /* unsupported is ok */
6480
6481         dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
6482                 sizeof(scan_assoc_time), TRUE, 0);
6483         dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
6484                 sizeof(scan_unassoc_time), TRUE, 0);
6485         dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time,
6486                 sizeof(scan_passive_time), TRUE, 0);
6487
6488 #ifdef ARP_OFFLOAD_SUPPORT
6489         /* Set and enable ARP offload feature for STA only  */
6490 #if defined(SOFTAP)
6491         if (arpoe && !ap_fw_loaded) {
6492 #else
6493         if (arpoe) {
6494 #endif 
6495                 dhd_arp_offload_enable(dhd, TRUE);
6496                 dhd_arp_offload_set(dhd, dhd_arp_mode);
6497         } else {
6498                 dhd_arp_offload_enable(dhd, FALSE);
6499                 dhd_arp_offload_set(dhd, 0);
6500         }
6501         dhd_arp_enable = arpoe;
6502 #endif /* ARP_OFFLOAD_SUPPORT */
6503
6504 #ifdef PKT_FILTER_SUPPORT
6505         /* Setup default defintions for pktfilter , enable in suspend */
6506         dhd->pktfilter_count = 6;
6507         /* Setup filter to allow only unicast */
6508         dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00";
6509         dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL;
6510         dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL;
6511         dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL;
6512         /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */
6513         dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB";
6514         /* apply APP pktfilter */
6515         dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806";
6516
6517
6518 #if defined(SOFTAP)
6519         if (ap_fw_loaded) {
6520                 dhd_enable_packet_filter(0, dhd);
6521         }
6522 #endif /* defined(SOFTAP) */
6523         dhd_set_packet_filter(dhd);
6524 #endif /* PKT_FILTER_SUPPORT */
6525 #ifdef DISABLE_11N
6526         bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf));
6527         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
6528                 DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret));
6529 #endif /* DISABLE_11N */
6530
6531         /* query for 'ver' to get version info from firmware */
6532         memset(buf, 0, sizeof(buf));
6533         ptr = buf;
6534         bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf));
6535         if ((ret  = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0)
6536                 DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
6537         else {
6538                 bcmstrtok(&ptr, "\n", 0);
6539                 /* Print fw version info */
6540                 DHD_ERROR(("Firmware version = %s\n", buf));
6541 #if defined(BCMSDIO)
6542                 dhd_set_version_info(dhd, buf);
6543 #endif /* defined(BCMSDIO) */
6544         }
6545
6546 #if defined(BCMSDIO)
6547         dhd_txglom_enable(dhd, TRUE);
6548 #endif /* defined(BCMSDIO) */
6549
6550 #if defined(BCMSDIO)
6551 #ifdef PROP_TXSTATUS
6552         if (disable_proptx ||
6553 #ifdef PROP_TXSTATUS_VSDB
6554                 /* enable WLFC only if the firmware is VSDB when it is in STA mode */
6555                 (bcmdhd_prop_txstatus_vsdb &&
6556                 (dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
6557                  dhd->op_mode != DHD_FLAG_IBSS_MODE)) ||
6558 #endif /* PROP_TXSTATUS_VSDB */
6559                 FALSE) {
6560                 wlfc_enable = FALSE;
6561         }
6562
6563 #ifndef DISABLE_11N
6564         bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, iovbuf, sizeof(iovbuf));
6565         if ((ret2 = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
6566                 DHD_ERROR(("%s wl ampdu_hostreorder failed %d\n", __FUNCTION__, ret2));
6567                 if (ret2 != BCME_UNSUPPORTED)
6568                         ret = ret2;
6569                 if (ret == BCME_NOTDOWN) {
6570                         uint wl_down = 1;
6571                         ret2 = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, (char *)&wl_down,
6572                                 sizeof(wl_down), TRUE, 0);
6573                         DHD_ERROR(("%s ampdu_hostreorder fail WL_DOWN : %d, hostreorder :%d\n",
6574                                 __FUNCTION__, ret2, hostreorder));
6575
6576                         bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4,
6577                                 iovbuf, sizeof(iovbuf));
6578                         ret2 = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6579                         DHD_ERROR(("%s wl ampdu_hostreorder. ret --> %d\n", __FUNCTION__, ret2));
6580                         if (ret2 != BCME_UNSUPPORTED)
6581                                         ret = ret2;
6582                 }
6583                 if (ret2 != BCME_OK)
6584                         hostreorder = 0;
6585         }
6586 #endif /* DISABLE_11N */
6587
6588
6589         if (wlfc_enable)
6590                 dhd_wlfc_init(dhd);
6591 #ifndef DISABLE_11N
6592         else if (hostreorder)
6593                 dhd_wlfc_hostreorder_init(dhd);
6594 #endif /* DISABLE_11N */
6595
6596 #endif /* PROP_TXSTATUS */
6597 #endif /* BCMSDIO || BCMBUS */
6598 #ifdef PCIE_FULL_DONGLE
6599         /* For FD we need all the packets at DHD to handle intra-BSS forwarding */
6600         if (FW_SUPPORTED(dhd, ap)) {
6601                 wl_ap_isolate = AP_ISOLATE_SENDUP_ALL;
6602                 bcm_mkiovar("ap_isolate", (char *)&wl_ap_isolate, 4, iovbuf, sizeof(iovbuf));
6603                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
6604                         DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
6605         }
6606 #endif /* PCIE_FULL_DONGLE */
6607 #ifdef PNO_SUPPORT
6608         if (!dhd->pno_state) {
6609                 dhd_pno_init(dhd);
6610         }
6611 #endif
6612 #ifdef WL11U
6613 if (bcmdhd_wl11u) {
6614         dhd_interworking_enable(dhd);
6615 }
6616 #endif /* WL11U */
6617
6618 /*RXCB not applicable to PCIE*/
6619 #if !defined(BCMPCIE) && defined(RXCB)
6620         if (bcmdhd_custom_rxcb) {
6621                 /* Enable bus rx callback */
6622                 bcm_mkiovar("bus:rxcb", (char *)&rxcb, 4, iovbuf, sizeof(iovbuf));
6623                 ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6624                 if (ret < 0)
6625                         DHD_ERROR(("%s failed to set RXCB %d\n", __FUNCTION__, ret));
6626         }
6627 #endif
6628
6629 done:
6630
6631         if (eventmask_msg)
6632                 kfree(eventmask_msg);
6633         if (iov_buf)
6634                 kfree(iov_buf);
6635
6636         return ret;
6637 }
6638
6639 void dhd_set_ampdu_rx_tid(struct net_device *dev, int ampdu_rx_tid)
6640 {
6641         int i, ret = 0;
6642         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
6643         dhd_pub_t *pub = &dhd->pub;
6644         char iovbuf[32];
6645         for (i = 0; i < 8; i++) { /* One bit each for traffic class CS7 - CS0 */
6646                 struct ampdu_tid_control atc;
6647                 atc.tid = i;
6648                 atc.enable = (ampdu_rx_tid >> i) & 1;
6649                 bcm_mkiovar("ampdu_rx_tid", (char *)&atc, sizeof(atc), iovbuf,sizeof(iovbuf));
6650                 ret = dhd_wl_ioctl_cmd(pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf),TRUE, 0);
6651                 if (ret < 0)
6652                         DHD_ERROR(("%s failed %d\n", __func__, ret));
6653         }
6654 }
6655
6656 int
6657 dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set)
6658 {
6659         char buf[strlen(name) + 1 + cmd_len];
6660         int len = sizeof(buf);
6661         wl_ioctl_t ioc;
6662         int ret;
6663
6664         len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len);
6665
6666         memset(&ioc, 0, sizeof(ioc));
6667
6668         ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR;
6669         ioc.buf = buf;
6670         ioc.len = len;
6671         ioc.set = set;
6672
6673         ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len);
6674         if (!set && ret >= 0)
6675                 memcpy(cmd_buf, buf, cmd_len);
6676
6677         return ret;
6678 }
6679
6680 int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
6681 {
6682         struct dhd_info *dhd = dhdp->info;
6683         struct net_device *dev = NULL;
6684
6685         ASSERT(dhd && dhd->iflist[ifidx]);
6686         dev = dhd->iflist[ifidx]->net;
6687         ASSERT(dev);
6688
6689         if (netif_running(dev)) {
6690                 DHD_ERROR(("%s: Must be down to change its MTU", dev->name));
6691                 return BCME_NOTDOWN;
6692         }
6693
6694 #define DHD_MIN_MTU 1500
6695 #define DHD_MAX_MTU 1752
6696
6697         if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) {
6698                 DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu));
6699                 return BCME_BADARG;
6700         }
6701
6702         dev->mtu = new_mtu;
6703         return 0;
6704 }
6705
6706 #ifdef ARP_OFFLOAD_SUPPORT
6707 /* add or remove AOE host ip(s) (up to 8 IPs on the interface)  */
6708 void
6709 aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx)
6710 {
6711         u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */
6712         int i;
6713         int ret;
6714
6715         bzero(ipv4_buf, sizeof(ipv4_buf));
6716
6717         /* display what we've got */
6718         ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx);
6719         DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__));
6720 #ifdef AOE_DBG
6721         dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
6722 #endif
6723         /* now we saved hoste_ip table, clr it in the dongle AOE */
6724         dhd_aoe_hostip_clr(dhd_pub, idx);
6725
6726         if (ret) {
6727                 DHD_ERROR(("%s failed\n", __FUNCTION__));
6728                 return;
6729         }
6730
6731         for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
6732                 if (add && (ipv4_buf[i] == 0)) {
6733                                 ipv4_buf[i] = ipa;
6734                                 add = FALSE; /* added ipa to local table  */
6735                                 DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n",
6736                                 __FUNCTION__, i));
6737                 } else if (ipv4_buf[i] == ipa) {
6738                         ipv4_buf[i]     = 0;
6739                         DHD_ARPOE(("%s: removed IP:%x from temp table %d\n",
6740                                 __FUNCTION__, ipa, i));
6741                 }
6742
6743                 if (ipv4_buf[i] != 0) {
6744                         /* add back host_ip entries from our local cache */
6745                         dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx);
6746                         DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n",
6747                                 __FUNCTION__, ipv4_buf[i], i));
6748                 }
6749         }
6750 #ifdef AOE_DBG
6751         /* see the resulting hostip table */
6752         dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx);
6753         DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__));
6754         dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
6755 #endif
6756 }
6757
6758 /*
6759  * Notification mechanism from kernel to our driver. This function is called by the Linux kernel
6760  * whenever there is an event related to an IP address.
6761  * ptr : kernel provided pointer to IP address that has changed
6762  */
6763 static int dhd_inetaddr_notifier_call(struct notifier_block *this,
6764         unsigned long event,
6765         void *ptr)
6766 {
6767         struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
6768
6769         dhd_info_t *dhd;
6770         dhd_pub_t *dhd_pub;
6771         int idx;
6772
6773         if (!dhd_arp_enable)
6774                 return NOTIFY_DONE;
6775         if (!ifa || !(ifa->ifa_dev->dev))
6776                 return NOTIFY_DONE;
6777
6778 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
6779         /* Filter notifications meant for non Broadcom devices */
6780         if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) &&
6781             (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) {
6782 #if defined(WL_ENABLE_P2P_IF)
6783                 if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops))
6784 #endif /* WL_ENABLE_P2P_IF */
6785                         return NOTIFY_DONE;
6786         }
6787 #endif /* LINUX_VERSION_CODE */
6788
6789         dhd = DHD_DEV_INFO(ifa->ifa_dev->dev);
6790         if (!dhd)
6791                 return NOTIFY_DONE;
6792
6793         dhd_pub = &dhd->pub;
6794
6795         if (dhd_pub->arp_version == 1) {
6796                 idx = 0;
6797         }
6798         else {
6799                 for (idx = 0; idx < DHD_MAX_IFS; idx++) {
6800                         if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev)
6801                         break;
6802                 }
6803                 if (idx < DHD_MAX_IFS)
6804                         DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net,
6805                                 dhd->iflist[idx]->name, dhd->iflist[idx]->idx));
6806                 else {
6807                         DHD_ERROR(("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label));
6808                         idx = 0;
6809                 }
6810         }
6811
6812         switch (event) {
6813                 case NETDEV_UP:
6814                         DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n",
6815                                 __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
6816
6817                         if (dhd->pub.busstate != DHD_BUS_DATA) {
6818                                 DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__));
6819                                 if (dhd->pend_ipaddr) {
6820                                         DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n",
6821                                                 __FUNCTION__, dhd->pend_ipaddr));
6822                                 }
6823                                 dhd->pend_ipaddr = ifa->ifa_address;
6824                                 break;
6825                         }
6826
6827 #ifdef AOE_IP_ALIAS_SUPPORT
6828                         DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n",
6829                                 __FUNCTION__));
6830                         aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx);
6831 #endif /* AOE_IP_ALIAS_SUPPORT */
6832                         break;
6833
6834                 case NETDEV_DOWN:
6835                         DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n",
6836                                 __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
6837                         dhd->pend_ipaddr = 0;
6838 #ifdef AOE_IP_ALIAS_SUPPORT
6839                         DHD_ARPOE(("%s:interface is down, AOE clr all for this if\n",
6840                                 __FUNCTION__));
6841                         aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx);
6842 #else
6843                         dhd_aoe_hostip_clr(&dhd->pub, idx);
6844                         dhd_aoe_arp_clr(&dhd->pub, idx);
6845 #endif /* AOE_IP_ALIAS_SUPPORT */
6846                         break;
6847
6848                 default:
6849                         DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n",
6850                                 __func__, ifa->ifa_label, event));
6851                         break;
6852         }
6853         return NOTIFY_DONE;
6854 }
6855 #endif /* ARP_OFFLOAD_SUPPORT */
6856
6857 #ifdef CONFIG_IPV6
6858 /* Neighbor Discovery Offload: defered handler */
6859 static void
6860 dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event)
6861 {
6862         struct ipv6_work_info_t *ndo_work = (struct ipv6_work_info_t *)event_data;
6863         dhd_pub_t       *pub = &((dhd_info_t *)dhd_info)->pub;
6864         int             ret;
6865
6866         if (event != DHD_WQ_WORK_IPV6_NDO) {
6867                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
6868                 return;
6869         }
6870
6871         if (!ndo_work) {
6872                 DHD_ERROR(("%s: ipv6 work info is not initialized \n", __FUNCTION__));
6873                 return;
6874         }
6875
6876         if (!pub) {
6877                 DHD_ERROR(("%s: dhd pub is not initialized \n", __FUNCTION__));
6878                 return;
6879         }
6880
6881         if (ndo_work->if_idx) {
6882                 DHD_ERROR(("%s: idx %d \n", __FUNCTION__, ndo_work->if_idx));
6883                 return;
6884         }
6885
6886         switch (ndo_work->event) {
6887                 case NETDEV_UP:
6888                         DHD_TRACE(("%s: Enable NDO and add ipv6 into table \n ", __FUNCTION__));
6889                         ret = dhd_ndo_enable(pub, TRUE);
6890                         if (ret < 0) {
6891                                 DHD_ERROR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, ret));
6892                         }
6893
6894                         ret = dhd_ndo_add_ip(pub, &ndo_work->ipv6_addr[0], ndo_work->if_idx);
6895                         if (ret < 0) {
6896                                 DHD_ERROR(("%s: Adding host ip for NDO failed %d\n",
6897                                         __FUNCTION__, ret));
6898                         }
6899                         break;
6900                 case NETDEV_DOWN:
6901                         DHD_TRACE(("%s: clear ipv6 table \n", __FUNCTION__));
6902                         ret = dhd_ndo_remove_ip(pub, ndo_work->if_idx);
6903                         if (ret < 0) {
6904                                 DHD_ERROR(("%s: Removing host ip for NDO failed %d\n",
6905                                         __FUNCTION__, ret));
6906                                 goto done;
6907                         }
6908
6909                         ret = dhd_ndo_enable(pub, FALSE);
6910                         if (ret < 0) {
6911                                 DHD_ERROR(("%s: disabling NDO Failed %d\n", __FUNCTION__, ret));
6912                                 goto done;
6913                         }
6914                         break;
6915                 default:
6916                         DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__));
6917                         break;
6918         }
6919 done:
6920         /* free ndo_work. alloced while scheduling the work */
6921         kfree(ndo_work);
6922
6923         return;
6924 }
6925
6926 /*
6927  * Neighbor Discovery Offload: Called when an interface
6928  * is assigned with ipv6 address.
6929  * Handles only primary interface
6930  */
6931 static int dhd_inet6addr_notifier_call(struct notifier_block *this,
6932         unsigned long event,
6933         void *ptr)
6934 {
6935         dhd_info_t *dhd;
6936         dhd_pub_t *dhd_pub;
6937         struct inet6_ifaddr *inet6_ifa = ptr;
6938         struct in6_addr *ipv6_addr = &inet6_ifa->addr;
6939         struct ipv6_work_info_t *ndo_info;
6940         int idx = 0; /* REVISIT */
6941
6942 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
6943         /* Filter notifications meant for non Broadcom devices */
6944         if (inet6_ifa->idev->dev->netdev_ops != &dhd_ops_pri) {
6945                         return NOTIFY_DONE;
6946         }
6947 #endif /* LINUX_VERSION_CODE */
6948
6949         dhd = DHD_DEV_INFO(inet6_ifa->idev->dev);
6950         if (!dhd)
6951                 return NOTIFY_DONE;
6952
6953         if (dhd->iflist[idx] && dhd->iflist[idx]->net != inet6_ifa->idev->dev)
6954                 return NOTIFY_DONE;
6955         dhd_pub = &dhd->pub;
6956         if (!FW_SUPPORTED(dhd_pub, ndoe))
6957                 return NOTIFY_DONE;
6958
6959         ndo_info = (struct ipv6_work_info_t *)kzalloc(sizeof(struct ipv6_work_info_t), GFP_ATOMIC);
6960         if (!ndo_info) {
6961                 DHD_ERROR(("%s: ipv6 work alloc failed\n", __FUNCTION__));
6962                 return NOTIFY_DONE;
6963         }
6964
6965         ndo_info->event = event;
6966         ndo_info->if_idx = idx;
6967         memcpy(&ndo_info->ipv6_addr[0], ipv6_addr, IPV6_ADDR_LEN);
6968
6969         /* defer the work to thread as it may block kernel */
6970         dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)ndo_info, DHD_WQ_WORK_IPV6_NDO,
6971                 dhd_inet6_work_handler, DHD_WORK_PRIORITY_LOW);
6972         return NOTIFY_DONE;
6973 }
6974 #endif /* #ifdef CONFIG_IPV6 */
6975
6976 int
6977 dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock)
6978 {
6979         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
6980         dhd_if_t *ifp;
6981         struct net_device *net = NULL;
6982         int err = 0;
6983         uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 };
6984
6985         DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
6986
6987         ASSERT(dhd && dhd->iflist[ifidx]);
6988         ifp = dhd->iflist[ifidx];
6989         net = ifp->net;
6990         ASSERT(net && (ifp->idx == ifidx));
6991
6992 #ifndef  P2PONEINT
6993 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
6994         ASSERT(!net->open);
6995         net->get_stats = dhd_get_stats;
6996         net->do_ioctl = dhd_ioctl_entry;
6997         net->hard_start_xmit = dhd_start_xmit;
6998         net->set_mac_address = dhd_set_mac_address;
6999         net->set_multicast_list = dhd_set_multicast_list;
7000         net->open = net->stop = NULL;
7001 #else
7002         ASSERT(!net->netdev_ops);
7003         net->netdev_ops = &dhd_ops_virt;
7004 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
7005 #else
7006         net->netdev_ops = &dhd_cfgp2p_ops_virt;
7007 #endif /* P2PONEINT */
7008
7009         /* Ok, link into the network layer... */
7010         if (ifidx == 0) {
7011                 /*
7012                  * device functions for the primary interface only
7013                  */
7014 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
7015                 net->open = dhd_open;
7016                 net->stop = dhd_stop;
7017 #else
7018                 net->netdev_ops = &dhd_ops_pri;
7019 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
7020                 if (!ETHER_ISNULLADDR(dhd->pub.mac.octet))
7021                         memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
7022         } else {
7023                 /*
7024                  * We have to use the primary MAC for virtual interfaces
7025                  */
7026                 memcpy(temp_addr, ifp->mac_addr, ETHER_ADDR_LEN);
7027                 /*
7028                  * Android sets the locally administered bit to indicate that this is a
7029                  * portable hotspot.  This will not work in simultaneous AP/STA mode,
7030                  * nor with P2P.  Need to set the Donlge's MAC address, and then use that.
7031                  */
7032                 if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr,
7033                         ETHER_ADDR_LEN)) {
7034                         DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n",
7035                         __func__, net->name));
7036                         temp_addr[0] |= 0x02;
7037                 }
7038         }
7039
7040         net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen;
7041 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
7042         net->ethtool_ops = &dhd_ethtool_ops;
7043 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
7044
7045 #if defined(WL_WIRELESS_EXT)
7046 #if WIRELESS_EXT < 19
7047         net->get_wireless_stats = dhd_get_wireless_stats;
7048 #endif /* WIRELESS_EXT < 19 */
7049 #if WIRELESS_EXT > 12
7050         net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
7051 #endif /* WIRELESS_EXT > 12 */
7052 #endif /* defined(WL_WIRELESS_EXT) */
7053
7054         dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net);
7055
7056         memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
7057
7058         if (ifidx == 0)
7059                 printf("%s\n", dhd_version);
7060
7061         if (need_rtnl_lock)
7062                 err = register_netdev(net);
7063         else
7064                 err = register_netdevice(net);
7065
7066 #ifdef CONFIG_BCMDHD_CUSTOM_SYSFS_TEGRA
7067 {
7068         extern struct net_device *dhd_custom_sysfs_tegra_histogram_stat_netdev;
7069         if (ifidx == 0)
7070                 dhd_custom_sysfs_tegra_histogram_stat_netdev = net;
7071 }
7072 #endif
7073
7074         if (err != 0) {
7075                 DHD_ERROR(("couldn't register the net device [%s], err %d\n", net->name, err));
7076                 goto fail;
7077         }
7078
7079
7080         printf("Register interface [%s]  MAC: "MACDBG"\n\n", net->name,
7081                 MAC2STRDBG(net->dev_addr));
7082
7083 #if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211)
7084                 wl_iw_iscan_set_scan_broadcast_prep(net, 1);
7085 #endif
7086
7087 #if (defined(BCMPCIE) || (defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= \
7088         KERNEL_VERSION(2, 6, 27))))
7089         if (ifidx == 0) {
7090 #ifdef BCMLXSDMMC
7091                 up(&dhd_registration_sem);
7092 #endif
7093                 if (!dhd_download_fw_on_driverload) {
7094                         dhd_net_bus_devreset(net, TRUE);
7095 #ifdef BCMLXSDMMC
7096                         dhd_net_bus_suspend(net);
7097 #endif /* BCMLXSDMMC */
7098                         wifi_platform_set_power(dhdp->info->adapter, FALSE, WIFI_TURNOFF_DELAY);
7099                 }
7100         }
7101 #endif /* OEM_ANDROID && (BCMPCIE || (BCMLXSDMMC && KERNEL_VERSION >= 2.6.27)) */
7102         return 0;
7103
7104 fail:
7105 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
7106         net->open = NULL;
7107 #else
7108         net->netdev_ops = NULL;
7109 #endif
7110         return err;
7111 }
7112
7113 void
7114 dhd_bus_detach(dhd_pub_t *dhdp)
7115 {
7116         dhd_info_t *dhd;
7117
7118         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7119
7120         if (dhdp) {
7121                 dhd = (dhd_info_t *)dhdp->info;
7122                 if (dhd) {
7123
7124                         /*
7125                          * In case of Android cfg80211 driver, the bus is down in dhd_stop,
7126                          *  calling stop again will cuase SD read/write errors.
7127                          */
7128                         if (dhd->pub.busstate != DHD_BUS_DOWN) {
7129                                 /* Stop the protocol module */
7130                                 dhd_prot_stop(&dhd->pub);
7131
7132                                 /* Stop the bus module */
7133                                 dhd_bus_stop(dhd->pub.bus, TRUE);
7134                         }
7135
7136 #if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE)
7137                         dhd_bus_oob_intr_unregister(dhdp);
7138 #endif 
7139                 }
7140         }
7141 }
7142
7143
7144 void dhd_detach(dhd_pub_t *dhdp)
7145 {
7146         dhd_info_t *dhd;
7147         unsigned long flags;
7148         int timer_valid = FALSE;
7149
7150         if (!dhdp)
7151                 return;
7152
7153         dhd = (dhd_info_t *)dhdp->info;
7154         if (!dhd)
7155                 return;
7156
7157 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
7158         dhd_global = NULL;
7159 #endif /* CUSTOMER_HW20 && WLANAUDIO */
7160
7161         DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state));
7162
7163         dhd->pub.up = 0;
7164         if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) {
7165                 /* Give sufficient time for threads to start running in case
7166                  * dhd_attach() has failed
7167                  */
7168                 OSL_SLEEP(100);
7169         }
7170
7171 #ifdef PROP_TXSTATUS
7172 #ifdef DHD_WLFC_THREAD
7173         if (dhd->pub.wlfc_thread) {
7174                 kthread_stop(dhd->pub.wlfc_thread);
7175                 dhdp->wlfc_thread_go = TRUE;
7176                 wake_up_interruptible(&dhdp->wlfc_wqhead);
7177         }
7178         dhd->pub.wlfc_thread = NULL;
7179 #endif /* DHD_WLFC_THREAD */
7180 #endif /* PROP_TXSTATUS */
7181
7182         if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) {
7183                 dhd_bus_detach(dhdp);
7184 #ifdef PCIE_FULL_DONGLE
7185                 dhd_flow_rings_deinit(dhdp);
7186 #endif
7187
7188                 if (dhdp->prot)
7189                         dhd_prot_detach(dhdp);
7190         }
7191
7192 #ifdef ARP_OFFLOAD_SUPPORT
7193         if (dhd_inetaddr_notifier_registered) {
7194                 dhd_inetaddr_notifier_registered = FALSE;
7195                 unregister_inetaddr_notifier(&dhd_inetaddr_notifier);
7196         }
7197 #endif /* ARP_OFFLOAD_SUPPORT */
7198 #ifdef CONFIG_IPV6
7199         if (dhd_inet6addr_notifier_registered) {
7200                 dhd_inet6addr_notifier_registered = FALSE;
7201                 unregister_inet6addr_notifier(&dhd_inet6addr_notifier);
7202         }
7203 #endif
7204
7205 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
7206         if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) {
7207                 if (dhd->early_suspend.suspend)
7208                         unregister_early_suspend(&dhd->early_suspend);
7209         }
7210 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
7211
7212 #if defined(WL_WIRELESS_EXT)
7213         if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
7214                 /* Detatch and unlink in the iw */
7215                 wl_iw_detach();
7216         }
7217 #endif /* defined(WL_WIRELESS_EXT) */
7218
7219         /* delete all interfaces, start with virtual  */
7220         if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) {
7221                 int i = 1;
7222                 dhd_if_t *ifp;
7223
7224                 /* Cleanup virtual interfaces */
7225                 dhd_net_if_lock_local(dhd);
7226                 for (i = 1; i < DHD_MAX_IFS; i++) {
7227                         if (dhd->iflist[i])
7228                                 dhd_remove_if(&dhd->pub, i, TRUE);
7229                 }
7230                 dhd_net_if_unlock_local(dhd);
7231
7232                 /*  delete primary interface 0 */
7233                 ifp = dhd->iflist[0];
7234                 ASSERT(ifp);
7235                 ASSERT(ifp->net);
7236                 if (ifp && ifp->net) {
7237
7238
7239
7240                         /* in unregister_netdev case, the interface gets freed by net->destructor
7241                          * (which is set to free_netdev)
7242                          */
7243                         if (ifp->net->reg_state == NETREG_UNINITIALIZED)
7244                                 free_netdev(ifp->net);
7245                         else {
7246 #ifdef SET_RPS_CPUS
7247                                 custom_rps_map_clear(ifp->net->_rx);
7248 #endif /* SET_RPS_CPUS */
7249                                 unregister_netdev(ifp->net);
7250                         }
7251                         ifp->net = NULL;
7252 #ifdef DHD_WMF
7253                         dhd_wmf_cleanup(dhdp, 0);
7254 #endif /* DHD_WMF */
7255
7256                         dhd_if_del_sta_list(ifp);
7257
7258                         MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
7259                         dhd->iflist[0] = NULL;
7260                 }
7261         }
7262
7263         /* Clear the watchdog timer */
7264         DHD_GENERAL_LOCK(&dhd->pub, flags);
7265         timer_valid = dhd->wd_timer_valid;
7266         dhd->wd_timer_valid = FALSE;
7267         DHD_GENERAL_UNLOCK(&dhd->pub, flags);
7268         if (timer_valid)
7269                 del_timer_sync(&dhd->timer);
7270
7271         if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) {
7272                 if (dhd->thr_wdt_ctl.thr_pid >= 0) {
7273                         PROC_STOP(&dhd->thr_wdt_ctl);
7274                 }
7275
7276                 if (dhd->rxthread_enabled && dhd->thr_rxf_ctl.thr_pid >= 0) {
7277                         PROC_STOP(&dhd->thr_rxf_ctl);
7278                 }
7279
7280                 if (dhd->thr_dpc_ctl.thr_pid >= 0) {
7281                         PROC_STOP(&dhd->thr_dpc_ctl);
7282                 } else
7283                         tasklet_kill(&dhd->tasklet);
7284         }
7285 #ifdef WL_CFG80211
7286         if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
7287                 wl_cfg80211_detach(NULL);
7288                 dhd_monitor_uninit();
7289         }
7290 #endif
7291         /* free deferred work queue */
7292         dhd_deferred_work_deinit(dhd->dhd_deferred_wq);
7293         dhd->dhd_deferred_wq = NULL;
7294
7295 #ifdef SHOW_LOGTRACE
7296         if (dhd->event_data.fmts)
7297                 kfree(dhd->event_data.fmts);
7298         if (dhd->event_data.raw_fmts)
7299                 kfree(dhd->event_data.raw_fmts);
7300 #endif /* SHOW_LOGTRACE */
7301
7302 #ifdef PNO_SUPPORT
7303         if (dhdp->pno_state)
7304                 dhd_pno_deinit(dhdp);
7305 #endif
7306 #if defined(CONFIG_PM_SLEEP)
7307         if (dhd_pm_notifier_registered) {
7308                 unregister_pm_notifier(&dhd_pm_notifier);
7309                 dhd_pm_notifier_registered = FALSE;
7310         }
7311 #endif /* CONFIG_PM_SLEEP */
7312 #ifdef DEBUG_CPU_FREQ
7313                 if (dhd->new_freq)
7314                         free_percpu(dhd->new_freq);
7315                 dhd->new_freq = NULL;
7316                 cpufreq_unregister_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER);
7317 #endif
7318         if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) {
7319                 DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter));
7320 #ifdef CONFIG_HAS_WAKELOCK
7321                 dhd->wakelock_counter = 0;
7322                 dhd->wakelock_wd_counter = 0;
7323                 dhd->wakelock_rx_timeout_enable = 0;
7324                 dhd->wakelock_ctrl_timeout_enable = 0;
7325                 wake_lock_destroy(&dhd->wl_wifi);
7326                 wake_lock_destroy(&dhd->wl_rxwake);
7327                 wake_lock_destroy(&dhd->wl_ctrlwake);
7328                 wake_lock_destroy(&dhd->wl_wdwake);
7329 #ifdef BCMPCIE_OOB_HOST_WAKE
7330                 wake_lock_destroy(&dhd->wl_intrwake);
7331 #endif /* BCMPCIE_OOB_HOST_WAKE */
7332 #endif /* CONFIG_HAS_WAKELOCK */
7333         }
7334
7335
7336
7337
7338 #ifdef DHDTCPACK_SUPPRESS
7339         /* This will free all MEM allocated for TCPACK SUPPRESS */
7340         dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF);
7341 #endif /* DHDTCPACK_SUPPRESS */
7342 }
7343
7344
7345 void
7346 dhd_free(dhd_pub_t *dhdp)
7347 {
7348         dhd_info_t *dhd;
7349         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7350
7351         if (dhdp) {
7352                 int i;
7353                 for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) {
7354                         if (dhdp->reorder_bufs[i]) {
7355                                 reorder_info_t *ptr;
7356                                 uint32 buf_size = sizeof(struct reorder_info);
7357
7358                                 ptr = dhdp->reorder_bufs[i];
7359
7360                                 buf_size += ((ptr->max_idx + 1) * sizeof(void*));
7361                                 DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n",
7362                                         i, ptr->max_idx, buf_size));
7363
7364                                 MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size);
7365                                 dhdp->reorder_bufs[i] = NULL;
7366                         }
7367                 }
7368
7369                 dhd_sta_pool_fini(dhdp, DHD_MAX_STA);
7370
7371                 dhd = (dhd_info_t *)dhdp->info;
7372                 if (dhdp->soc_ram) {
7373                         MFREE(dhdp->osh, dhdp->soc_ram, dhdp->soc_ram_length);
7374                         dhdp->soc_ram = NULL;
7375                 }
7376
7377                 /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */
7378                 if (dhd &&
7379                         dhd != (dhd_info_t *)dhd_os_prealloc(dhdp, DHD_PREALLOC_DHD_INFO, 0, FALSE))
7380                         MFREE(dhd->pub.osh, dhd, sizeof(*dhd));
7381                 dhd = NULL;
7382         }
7383 }
7384
7385 void
7386 dhd_clear(dhd_pub_t *dhdp)
7387 {
7388         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7389
7390         if (dhdp) {
7391                 int i;
7392 #ifdef DHDTCPACK_SUPPRESS
7393                 /* Clean up timer/data structure for any remaining/pending packet or timer. */
7394                 dhd_tcpack_info_tbl_clean(dhdp);
7395 #endif /* DHDTCPACK_SUPPRESS */
7396                 for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) {
7397                         if (dhdp->reorder_bufs[i]) {
7398                                 reorder_info_t *ptr;
7399                                 uint32 buf_size = sizeof(struct reorder_info);
7400
7401                                 ptr = dhdp->reorder_bufs[i];
7402
7403                                 buf_size += ((ptr->max_idx + 1) * sizeof(void*));
7404                                 DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n",
7405                                         i, ptr->max_idx, buf_size));
7406
7407                                 MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size);
7408                                 dhdp->reorder_bufs[i] = NULL;
7409                         }
7410                 }
7411
7412                 dhd_sta_pool_clear(dhdp, DHD_MAX_STA);
7413
7414                 if (dhdp->soc_ram) {
7415                         MFREE(dhdp->osh, dhdp->soc_ram, dhdp->soc_ram_length);
7416                         dhdp->soc_ram = NULL;
7417                 }
7418         }
7419 }
7420
7421 static void
7422 dhd_module_cleanup(void)
7423 {
7424         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7425
7426         dhd_bus_unregister();
7427
7428         wl_android_exit();
7429
7430         dhd_wifi_platform_unregister_drv();
7431 }
7432
7433 static void __exit
7434 dhd_module_exit(void)
7435 {
7436         dhd_module_cleanup();
7437         unregister_reboot_notifier(&dhd_reboot_notifier);
7438 }
7439
7440 static int __init
7441 dhd_module_init(void)
7442 {
7443         int err;
7444         int retry = POWERUP_MAX_RETRY;
7445
7446         DHD_ERROR(("%s in\n", __FUNCTION__));
7447
7448         DHD_PERIM_RADIO_INIT();
7449
7450         if (firmware_path[0] != '\0') {
7451                 strncpy(fw_bak_path, firmware_path, MOD_PARAM_PATHLEN);
7452                 fw_bak_path[MOD_PARAM_PATHLEN-1] = '\0';
7453         }
7454
7455         if (nvram_path[0] != '\0') {
7456                 strncpy(nv_bak_path, nvram_path, MOD_PARAM_PATHLEN);
7457                 nv_bak_path[MOD_PARAM_PATHLEN-1] = '\0';
7458         }
7459
7460         do {
7461                 err = dhd_wifi_platform_register_drv();
7462                 if (!err) {
7463                         register_reboot_notifier(&dhd_reboot_notifier);
7464                         break;
7465                 }
7466                 else {
7467                         DHD_ERROR(("%s: Failed to load the driver, try cnt %d\n",
7468                                 __FUNCTION__, retry));
7469                         strncpy(firmware_path, fw_bak_path, MOD_PARAM_PATHLEN);
7470                         firmware_path[MOD_PARAM_PATHLEN-1] = '\0';
7471                         strncpy(nvram_path, nv_bak_path, MOD_PARAM_PATHLEN);
7472                         nvram_path[MOD_PARAM_PATHLEN-1] = '\0';
7473                 }
7474         } while (retry--);
7475
7476         if (err)
7477                 DHD_ERROR(("%s: Failed to load driver max retry reached**\n", __FUNCTION__));
7478
7479         return err;
7480 }
7481
7482 static int
7483 dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused)
7484 {
7485         DHD_TRACE(("%s: code = %ld\n", __FUNCTION__, code));
7486         if (code == SYS_RESTART) {
7487         }
7488
7489         return NOTIFY_DONE;
7490 }
7491
7492
7493 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
7494 #if defined(CONFIG_DEFERRED_INITCALLS)
7495 deferred_module_init(dhd_module_init);
7496 #elif defined(USE_LATE_INITCALL_SYNC)
7497 late_initcall_sync(dhd_module_init);
7498 #else
7499 late_initcall(dhd_module_init);
7500 #endif /* USE_LATE_INITCALL_SYNC */
7501 #else
7502 module_init(dhd_module_init);
7503 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
7504
7505 module_exit(dhd_module_exit);
7506
7507 /*
7508  * OS specific functions required to implement DHD driver in OS independent way
7509  */
7510 int
7511 dhd_os_proto_block(dhd_pub_t *pub)
7512 {
7513         dhd_info_t * dhd = (dhd_info_t *)(pub->info);
7514
7515         if (dhd) {
7516                 DHD_PERIM_UNLOCK(pub);
7517
7518                 down(&dhd->proto_sem);
7519
7520                 DHD_PERIM_LOCK(pub);
7521                 return 1;
7522         }
7523
7524         return 0;
7525 }
7526
7527 int
7528 dhd_os_proto_unblock(dhd_pub_t *pub)
7529 {
7530         dhd_info_t * dhd = (dhd_info_t *)(pub->info);
7531
7532         if (dhd) {
7533                 up(&dhd->proto_sem);
7534                 return 1;
7535         }
7536
7537         return 0;
7538 }
7539
7540 unsigned int
7541 dhd_os_get_ioctl_resp_timeout(void)
7542 {
7543         return ((unsigned int)dhd_ioctl_timeout_msec);
7544 }
7545
7546 void
7547 dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec)
7548 {
7549         dhd_ioctl_timeout_msec = (int)timeout_msec;
7550 }
7551
7552 int
7553 dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending)
7554 {
7555         dhd_info_t * dhd = (dhd_info_t *)(pub->info);
7556         int timeout;
7557
7558         /* Convert timeout in millsecond to jiffies */
7559 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
7560         timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec);
7561 #else
7562         timeout = dhd_ioctl_timeout_msec * HZ / 1000;
7563 #endif
7564
7565         DHD_PERIM_UNLOCK(pub);
7566
7567         timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout);
7568
7569         DHD_PERIM_LOCK(pub);
7570
7571         return timeout;
7572 }
7573
7574 int
7575 dhd_os_ioctl_resp_wake(dhd_pub_t *pub)
7576 {
7577         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
7578
7579         wake_up(&dhd->ioctl_resp_wait);
7580         return 0;
7581 }
7582
7583 int
7584 dhd_os_d3ack_wait(dhd_pub_t *pub, uint *condition, bool *pending)
7585 {
7586         dhd_info_t * dhd = (dhd_info_t *)(pub->info);
7587         int timeout;
7588
7589         /* Convert timeout in millsecond to jiffies */
7590 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
7591         timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec);
7592 #else
7593         timeout = dhd_ioctl_timeout_msec * HZ / 1000;
7594 #endif
7595
7596         DHD_PERIM_UNLOCK(pub);
7597
7598         timeout = wait_event_timeout(dhd->d3ack_wait, (*condition), timeout);
7599
7600         DHD_PERIM_LOCK(pub);
7601
7602         return timeout;
7603 }
7604
7605 int
7606 dhd_os_d3ack_wake(dhd_pub_t *pub)
7607 {
7608         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
7609
7610         wake_up(&dhd->d3ack_wait);
7611         return 0;
7612 }
7613
7614 void
7615 dhd_os_wd_timer_extend(void *bus, bool extend)
7616 {
7617         dhd_pub_t *pub = bus;
7618         dhd_info_t *dhd = (dhd_info_t *)pub->info;
7619
7620         if (extend)
7621                 dhd_os_wd_timer(bus, WATCHDOG_EXTEND_INTERVAL);
7622         else
7623                 dhd_os_wd_timer(bus, dhd->default_wd_interval);
7624 }
7625
7626
7627 void
7628 dhd_os_wd_timer(void *bus, uint wdtick)
7629 {
7630         dhd_pub_t *pub = bus;
7631         dhd_info_t *dhd = (dhd_info_t *)pub->info;
7632         unsigned long flags;
7633
7634         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7635
7636         if (!dhd) {
7637                 DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__));
7638                 return;
7639         }
7640
7641         DHD_GENERAL_LOCK(pub, flags);
7642
7643         /* don't start the wd until fw is loaded */
7644         if (pub->busstate == DHD_BUS_DOWN) {
7645                 DHD_GENERAL_UNLOCK(pub, flags);
7646                 if (!wdtick)
7647                         DHD_OS_WD_WAKE_UNLOCK(pub);
7648                 return;
7649         }
7650
7651         /* Totally stop the timer */
7652         if (!wdtick && dhd->wd_timer_valid == TRUE) {
7653                 dhd->wd_timer_valid = FALSE;
7654                 DHD_GENERAL_UNLOCK(pub, flags);
7655                 del_timer_sync(&dhd->timer);
7656                 DHD_OS_WD_WAKE_UNLOCK(pub);
7657                 return;
7658         }
7659
7660         if (wdtick) {
7661                 DHD_OS_WD_WAKE_LOCK(pub);
7662                 dhd_watchdog_ms = (uint)wdtick;
7663                 /* Re arm the timer, at last watchdog period */
7664                 mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms));
7665                 dhd->wd_timer_valid = TRUE;
7666         }
7667         DHD_GENERAL_UNLOCK(pub, flags);
7668 }
7669
7670 void *
7671 dhd_os_open_image(char *filename)
7672 {
7673         struct file *fp;
7674
7675         fp = filp_open(filename, O_RDONLY, 0);
7676         /*
7677          * 2.6.11 (FC4) supports filp_open() but later revs don't?
7678          * Alternative:
7679          * fp = open_namei(AT_FDCWD, filename, O_RD, 0);
7680          * ???
7681          */
7682          if (IS_ERR(fp))
7683                  fp = NULL;
7684
7685          return fp;
7686 }
7687
7688 int
7689 dhd_os_get_image_block(char *buf, int len, void *image)
7690 {
7691         struct file *fp = (struct file *)image;
7692         int rdlen;
7693
7694         if (!image)
7695                 return 0;
7696
7697         rdlen = kernel_read(fp, fp->f_pos, buf, len);
7698         if (rdlen > 0)
7699                 fp->f_pos += rdlen;
7700
7701         return rdlen;
7702 }
7703
7704 void
7705 dhd_os_close_image(void *image)
7706 {
7707         if (image)
7708                 filp_close((struct file *)image, NULL);
7709 }
7710
7711 void
7712 dhd_os_sdlock(dhd_pub_t *pub)
7713 {
7714         dhd_info_t *dhd;
7715
7716         dhd = (dhd_info_t *)(pub->info);
7717
7718         if (dhd_dpc_prio >= 0)
7719                 down(&dhd->sdsem);
7720         else
7721                 spin_lock_bh(&dhd->sdlock);
7722 }
7723
7724 void
7725 dhd_os_sdunlock(dhd_pub_t *pub)
7726 {
7727         dhd_info_t *dhd;
7728
7729         dhd = (dhd_info_t *)(pub->info);
7730
7731         if (dhd_dpc_prio >= 0)
7732                 up(&dhd->sdsem);
7733         else
7734                 spin_unlock_bh(&dhd->sdlock);
7735 }
7736
7737 void
7738 dhd_os_sdlock_txq(dhd_pub_t *pub)
7739 {
7740         dhd_info_t *dhd;
7741
7742         dhd = (dhd_info_t *)(pub->info);
7743         spin_lock_bh(&dhd->txqlock);
7744 }
7745
7746 void
7747 dhd_os_sdunlock_txq(dhd_pub_t *pub)
7748 {
7749         dhd_info_t *dhd;
7750
7751         dhd = (dhd_info_t *)(pub->info);
7752         spin_unlock_bh(&dhd->txqlock);
7753 }
7754
7755 void
7756 dhd_os_sdlock_rxq(dhd_pub_t *pub)
7757 {
7758 }
7759
7760 void
7761 dhd_os_sdunlock_rxq(dhd_pub_t *pub)
7762 {
7763 }
7764
7765 static void
7766 dhd_os_rxflock(dhd_pub_t *pub)
7767 {
7768         dhd_info_t *dhd;
7769
7770         dhd = (dhd_info_t *)(pub->info);
7771         spin_lock_bh(&dhd->rxf_lock);
7772
7773 }
7774
7775 static void
7776 dhd_os_rxfunlock(dhd_pub_t *pub)
7777 {
7778         dhd_info_t *dhd;
7779
7780         dhd = (dhd_info_t *)(pub->info);
7781         spin_unlock_bh(&dhd->rxf_lock);
7782 }
7783
7784 #ifdef DHDTCPACK_SUPPRESS
7785 void
7786 dhd_os_tcpacklock(dhd_pub_t *pub)
7787 {
7788         dhd_info_t *dhd;
7789
7790         dhd = (dhd_info_t *)(pub->info);
7791 #ifdef BCMPCIE
7792         if (irqs_disabled())
7793                 spin_lock(&dhd->tcpack_lock);
7794         else
7795                 spin_lock_bh(&dhd->tcpack_lock);
7796 #else
7797         spin_lock_bh(&dhd->tcpack_lock);
7798 #endif
7799
7800 }
7801
7802 void
7803 dhd_os_tcpackunlock(dhd_pub_t *pub)
7804 {
7805         dhd_info_t *dhd;
7806
7807         dhd = (dhd_info_t *)(pub->info);
7808 #ifdef BCMPCIE
7809         if (irqs_disabled())
7810                 spin_unlock(&dhd->tcpack_lock);
7811         else
7812                 spin_unlock_bh(&dhd->tcpack_lock);
7813 #else
7814         spin_unlock_bh(&dhd->tcpack_lock);
7815 #endif
7816 }
7817 #endif /* DHDTCPACK_SUPPRESS */
7818
7819 uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail)
7820 {
7821         uint8* buf;
7822         gfp_t flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC;
7823
7824         buf = (uint8*)wifi_platform_prealloc(dhdpub->info->adapter, section, size);
7825         if (buf == NULL) {
7826                 DHD_ERROR(("%s: failed to alloc memory, section: %d,"
7827                         " size: %dbytes", __FUNCTION__, section, size));
7828                 if (kmalloc_if_fail)
7829                         buf = kmalloc(size, flags);
7830         }
7831
7832         return buf;
7833 }
7834
7835 void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size)
7836 {
7837 }
7838
7839 #if defined(WL_WIRELESS_EXT)
7840 struct iw_statistics *
7841 dhd_get_wireless_stats(struct net_device *dev)
7842 {
7843         int res = 0;
7844         dhd_info_t *dhd = DHD_DEV_INFO(dev);
7845
7846         if (!dhd->pub.up) {
7847                 return NULL;
7848         }
7849
7850         res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats);
7851
7852         if (res == 0)
7853                 return &dhd->iw.wstats;
7854         else
7855                 return NULL;
7856 }
7857 #endif /* defined(WL_WIRELESS_EXT) */
7858
7859 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
7860 static int
7861 dhd_wlanaudio_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
7862                     wl_event_msg_t *event, void **data)
7863 {
7864         int cnt;
7865         char eabuf[ETHER_ADDR_STR_LEN];
7866         struct ether_addr *addr = &event->addr;
7867         uint32 type = ntoh32_ua((void *)&event->event_type);
7868
7869         switch (type) {
7870         case WLC_E_TXFAIL:
7871                 if (addr != NULL)
7872                         bcm_ether_ntoa(addr, eabuf);
7873                 else
7874                         return (BCME_ERROR);
7875
7876                 for (cnt = 0; cnt < MAX_WLANAUDIO_BLACKLIST; cnt++) {
7877                         if (dhd->wlanaudio_blist[cnt].is_blacklist)
7878                                 break;
7879
7880                         if (!bcmp(&dhd->wlanaudio_blist[cnt].blacklist_addr,
7881                                   addr, ETHER_ADDR_LEN)) {
7882                                 /* Mac address is Same */
7883                                 dhd->wlanaudio_blist[cnt].cnt++;
7884
7885                                 if (dhd->wlanaudio_blist[cnt].cnt < 15) {
7886                                         /* black list is false */
7887                                         if ((dhd->wlanaudio_blist[cnt].cnt > 10) &&
7888                                             (jiffies - dhd->wlanaudio_blist[cnt].txfail_jiffies
7889                                              < 100)) {
7890                                                 dhd->wlanaudio_blist[cnt].is_blacklist = true;
7891                                                 dhd->is_wlanaudio_blist = true;
7892                                         }
7893                                 } else {
7894                                         if ((!dhd->wlanaudio_blist[cnt].is_blacklist) &&
7895                                            (jiffies - dhd->wlanaudio_blist[cnt].txfail_jiffies
7896                                             > 100)) {
7897
7898                                                 bzero(&dhd->wlanaudio_blist[cnt],
7899                                                       sizeof(struct wlanaudio_blacklist));
7900                                         }
7901                                 }
7902                                 break;
7903                         } else if ((!dhd->wlanaudio_blist[cnt].is_blacklist) &&
7904                                    (!dhd->wlanaudio_blist[cnt].cnt)) {
7905                                 bcopy(addr,
7906                                       (char*)&dhd->wlanaudio_blist[cnt].blacklist_addr,
7907                                       ETHER_ADDR_LEN);
7908                                 dhd->wlanaudio_blist[cnt].cnt++;
7909                                 dhd->wlanaudio_blist[cnt].txfail_jiffies = jiffies;
7910
7911                                 bcm_ether_ntoa(&dhd->wlanaudio_blist[cnt].blacklist_addr, eabuf);
7912                                 break;
7913                         }
7914                 }
7915                 break;
7916         case WLC_E_AUTH  :
7917         case WLC_E_AUTH_IND :
7918         case WLC_E_DEAUTH :
7919         case WLC_E_DEAUTH_IND :
7920         case WLC_E_ASSOC:
7921         case WLC_E_ASSOC_IND:
7922         case WLC_E_REASSOC:
7923         case WLC_E_REASSOC_IND:
7924         case WLC_E_DISASSOC:
7925         case WLC_E_DISASSOC_IND:
7926                 {
7927                         int bl_cnt = 0;
7928
7929                         if (addr != NULL)
7930                                 bcm_ether_ntoa(addr, eabuf);
7931                         else
7932                                 return (BCME_ERROR);
7933
7934                         for (cnt = 0; cnt < MAX_WLANAUDIO_BLACKLIST; cnt++) {
7935                                 if (!bcmp(&dhd->wlanaudio_blist[cnt].blacklist_addr,
7936                                           addr, ETHER_ADDR_LEN)) {
7937                                         /* Mac address is Same */
7938                                         if (dhd->wlanaudio_blist[cnt].is_blacklist) {
7939                                                 /* black list is true */
7940                                                 bzero(&dhd->wlanaudio_blist[cnt],
7941                                                       sizeof(struct wlanaudio_blacklist));
7942                                         }
7943                                 }
7944                         }
7945
7946                         for (cnt = 0; cnt < MAX_WLANAUDIO_BLACKLIST; cnt++) {
7947                                 if (dhd->wlanaudio_blist[cnt].is_blacklist)
7948                                         bl_cnt++;
7949                         }
7950
7951                         if (!bl_cnt)
7952                         {
7953                                 dhd->is_wlanaudio_blist = false;
7954                         }
7955
7956                         break;
7957                 }
7958         }
7959         return BCME_OK;
7960 }
7961 #endif /* CUSTOMER_HW20 && WLANAUDIO */
7962 static int
7963 dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
7964         wl_event_msg_t *event, void **data)
7965 {
7966         int bcmerror = 0;
7967
7968         ASSERT(dhd != NULL);
7969
7970 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
7971         bcmerror = dhd_wlanaudio_event(dhd, ifidx, pktdata, event, data);
7972
7973         if (bcmerror != BCME_OK)
7974                 return (bcmerror);
7975 #endif /* CUSTOMER_HW20 && WLANAUDIO */
7976
7977 #ifdef SHOW_LOGTRACE
7978         bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data, &dhd->event_data);
7979 #else
7980         bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data, NULL);
7981 #endif /* SHOW_LOGTRACE */
7982
7983         if (bcmerror != BCME_OK)
7984                 return (bcmerror);
7985
7986 #if defined(WL_WIRELESS_EXT)
7987         if (event->bsscfgidx == 0) {
7988                 /*
7989                  * Wireless ext is on primary interface only
7990                  */
7991
7992         ASSERT(dhd->iflist[*ifidx] != NULL);
7993         ASSERT(dhd->iflist[*ifidx]->net != NULL);
7994
7995                 if (dhd->iflist[*ifidx]->net) {
7996                 wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
7997                 }
7998         }
7999 #endif /* defined(WL_WIRELESS_EXT)  */
8000
8001 #ifdef WL_CFG80211
8002         ASSERT(dhd->iflist[*ifidx] != NULL);
8003         if (dhd->iflist[*ifidx] == NULL)
8004                 return BCME_BADARG;
8005         ASSERT(dhd->iflist[*ifidx]->net != NULL);
8006         if (dhd->iflist[*ifidx]->net == NULL)
8007                 return BCME_BADARG;
8008         if (dhd->iflist[*ifidx]->net)
8009                 wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data);
8010 #endif /* defined(WL_CFG80211) */
8011
8012         return (bcmerror);
8013 }
8014
8015 /* send up locally generated event */
8016 void
8017 dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
8018 {
8019         switch (ntoh32(event->event_type)) {
8020
8021         default:
8022                 break;
8023         }
8024 }
8025
8026 #ifdef LOG_INTO_TCPDUMP
8027 void
8028 dhd_sendup_log(dhd_pub_t *dhdp, void *data, int data_len)
8029 {
8030         struct sk_buff *p, *skb;
8031         uint32 pktlen;
8032         int len;
8033         dhd_if_t *ifp;
8034         dhd_info_t *dhd;
8035         uchar *skb_data;
8036         int ifidx = 0;
8037         struct ether_header eth;
8038
8039         pktlen = sizeof(eth) + data_len;
8040         dhd = dhdp->info;
8041
8042         if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) {
8043                 ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32)));
8044
8045                 bcopy(&dhdp->mac, &eth.ether_dhost, ETHER_ADDR_LEN);
8046                 bcopy(&dhdp->mac, &eth.ether_shost, ETHER_ADDR_LEN);
8047                 ETHER_TOGGLE_LOCALADDR(&eth.ether_shost);
8048                 eth.ether_type = hton16(ETHER_TYPE_BRCM);
8049
8050                 bcopy((void *)&eth, PKTDATA(dhdp->osh, p), sizeof(eth));
8051                 bcopy(data, PKTDATA(dhdp->osh, p) + sizeof(eth), data_len);
8052                 skb = PKTTONATIVE(dhdp->osh, p);
8053                 skb_data = skb->data;
8054                 len = skb->len;
8055
8056                 ifidx = dhd_ifname2idx(dhd, "wlan0");
8057                 ifp = dhd->iflist[ifidx];
8058                 if (ifp == NULL)
8059                          ifp = dhd->iflist[0];
8060
8061                 ASSERT(ifp);
8062                 skb->dev = ifp->net;
8063                 skb->protocol = eth_type_trans(skb, skb->dev);
8064                 skb->data = skb_data;
8065                 skb->len = len;
8066
8067                 /* Strip header, count, deliver upward */
8068                 skb_pull(skb, ETH_HLEN);
8069
8070                 /* Send the packet */
8071                 if (in_interrupt()) {
8072                         netif_rx(skb);
8073                 } else {
8074                         netif_rx_ni(skb);
8075                 }
8076         }
8077         else {
8078                 /* Could not allocate a sk_buf */
8079                 DHD_ERROR(("%s: unable to alloc sk_buf", __FUNCTION__));
8080         }
8081 }
8082 #endif /* LOG_INTO_TCPDUMP */
8083
8084 void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
8085 {
8086 #if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
8087         struct dhd_info *dhdinfo =  dhd->info;
8088
8089 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
8090         int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT);
8091 #else
8092         int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ;
8093 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
8094
8095         dhd_os_sdunlock(dhd);
8096         wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout);
8097         dhd_os_sdlock(dhd);
8098 #endif /* defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */
8099         return;
8100 }
8101
8102 void dhd_wait_event_wakeup(dhd_pub_t *dhd)
8103 {
8104 #if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
8105         struct dhd_info *dhdinfo =  dhd->info;
8106         if (waitqueue_active(&dhdinfo->ctrl_wait))
8107                 wake_up(&dhdinfo->ctrl_wait);
8108 #endif
8109         return;
8110 }
8111
8112 #if defined(BCMSDIO) || defined(BCMPCIE)
8113 int
8114 dhd_net_bus_devreset(struct net_device *dev, uint8 flag)
8115 {
8116         int ret = 0;
8117         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8118
8119         if (flag == TRUE) {
8120                 /* Issue wl down command before resetting the chip */
8121                 if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) {
8122                         DHD_TRACE(("%s: wl down failed\n", __FUNCTION__));
8123                 }
8124 #ifdef PROP_TXSTATUS
8125                 if (dhd->pub.wlfc_enabled)
8126                         dhd_wlfc_deinit(&dhd->pub);
8127 #endif /* PROP_TXSTATUS */
8128 #ifdef PNO_SUPPORT
8129         if (dhd->pub.pno_state)
8130                 dhd_pno_deinit(&dhd->pub);
8131 #endif
8132         }
8133
8134 #ifdef BCMSDIO
8135         if (!flag) {
8136                 dhd_update_fw_nv_path(dhd);
8137                 /* update firmware and nvram path to sdio bus */
8138                 dhd_bus_update_fw_nv_path(dhd->pub.bus,
8139                         dhd->fw_path, dhd->nv_path);
8140         }
8141 #endif /* BCMSDIO */
8142
8143         ret = dhd_bus_devreset(&dhd->pub, flag);
8144         if (ret) {
8145                 DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret));
8146                 return ret;
8147         }
8148
8149         return ret;
8150 }
8151
8152 #ifdef BCMSDIO
8153 int
8154 dhd_net_bus_suspend(struct net_device *dev)
8155 {
8156         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8157         return dhd_bus_suspend(&dhd->pub);
8158 }
8159
8160 int
8161 dhd_net_bus_resume(struct net_device *dev, uint8 stage)
8162 {
8163         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8164         return dhd_bus_resume(&dhd->pub, stage);
8165 }
8166
8167 #endif /* BCMSDIO */
8168 #endif /* BCMSDIO || BCMPCIE */
8169
8170 int net_os_set_suspend_disable(struct net_device *dev, int val)
8171 {
8172         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8173         int ret = 0;
8174
8175         if (dhd) {
8176                 ret = dhd->pub.suspend_disable_flag;
8177                 dhd->pub.suspend_disable_flag = val;
8178         }
8179         return ret;
8180 }
8181
8182 int net_os_set_suspend(struct net_device *dev, int val, int force)
8183 {
8184         int ret = 0;
8185         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8186
8187         if (dhd) {
8188 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
8189                 ret = dhd_set_suspend(val, &dhd->pub);
8190 #else
8191                 ret = dhd_suspend_resume_helper(dhd, val, force);
8192 #endif
8193 #ifdef WL_CFG80211
8194                 wl_cfg80211_update_power_mode(dev);
8195 #endif
8196         }
8197         return ret;
8198 }
8199
8200 int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val)
8201 {
8202         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8203
8204         if (dhd)
8205                 dhd->pub.suspend_bcn_li_dtim = val;
8206
8207         return 0;
8208 }
8209
8210 #ifdef PKT_FILTER_SUPPORT
8211 int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num)
8212 {
8213         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8214         char *filterp = NULL;
8215         int filter_id = 0;
8216         int ret = 0;
8217
8218         if (!dhd || (num == DHD_UNICAST_FILTER_NUM) ||
8219                 (num == DHD_MDNS_FILTER_NUM))
8220                 return ret;
8221         if (num >= dhd->pub.pktfilter_count)
8222                 return -EINVAL;
8223         switch (num) {
8224                 case DHD_BROADCAST_FILTER_NUM:
8225                         filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF";
8226                         filter_id = 101;
8227                         break;
8228                 case DHD_MULTICAST4_FILTER_NUM:
8229                         filterp = "102 0 0 0 0xFFFFFF 0x01005E";
8230                         filter_id = 102;
8231                         break;
8232                 case DHD_MULTICAST6_FILTER_NUM:
8233                         filterp = "103 0 0 0 0xFFFF 0x3333";
8234                         filter_id = 103;
8235                         break;
8236                 default:
8237                         return -EINVAL;
8238         }
8239
8240         /* Add filter */
8241         if (add_remove) {
8242                 dhd->pub.pktfilter[num] = filterp;
8243                 dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]);
8244         } else { /* Delete filter */
8245                 if (dhd->pub.pktfilter[num] != NULL) {
8246                         dhd_pktfilter_offload_delete(&dhd->pub, filter_id);
8247                         dhd->pub.pktfilter[num] = NULL;
8248                 }
8249         }
8250         return ret;
8251 }
8252
8253 int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val)
8254
8255 {
8256         int ret = 0;
8257
8258         /* Packet filtering is set only if we still in early-suspend and
8259          * we need either to turn it ON or turn it OFF
8260          * We can always turn it OFF in case of early-suspend, but we turn it
8261          * back ON only if suspend_disable_flag was not set
8262         */
8263         if (dhdp && dhdp->up) {
8264                 if (dhdp->in_suspend) {
8265                         if (!val || (val && !dhdp->suspend_disable_flag))
8266                                 dhd_enable_packet_filter(val, dhdp);
8267                 }
8268         }
8269         return ret;
8270 }
8271
8272 /* function to enable/disable packet for Network device */
8273 int net_os_enable_packet_filter(struct net_device *dev, int val)
8274 {
8275         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8276
8277         return dhd_os_enable_packet_filter(&dhd->pub, val);
8278 }
8279 #endif /* PKT_FILTER_SUPPORT */
8280
8281 int
8282 dhd_dev_init_ioctl(struct net_device *dev)
8283 {
8284         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8285         int ret;
8286
8287         if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0)
8288                 goto done;
8289
8290 done:
8291         return ret;
8292 }
8293
8294 #ifdef PNO_SUPPORT
8295 /* Linux wrapper to call common dhd_pno_stop_for_ssid */
8296 int
8297 dhd_dev_pno_stop_for_ssid(struct net_device *dev)
8298 {
8299         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8300
8301         return (dhd_pno_stop_for_ssid(&dhd->pub));
8302 }
8303 /* Linux wrapper to call common dhd_pno_set_for_ssid */
8304 int
8305 dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid,
8306         uint16  scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan)
8307 {
8308         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8309
8310         return (dhd_pno_set_for_ssid(&dhd->pub, ssids_local, nssid, scan_fr,
8311                 pno_repeat, pno_freq_expo_max, channel_list, nchan));
8312 }
8313
8314 /* Linux wrapper to call common dhd_pno_enable */
8315 int
8316 dhd_dev_pno_enable(struct net_device *dev, int enable)
8317 {
8318         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8319
8320         return (dhd_pno_enable(&dhd->pub, enable));
8321 }
8322
8323 /* Linux wrapper to call common dhd_pno_set_for_hotlist */
8324 int
8325 dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid,
8326         struct dhd_pno_hotlist_params *hotlist_params)
8327 {
8328         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8329         return (dhd_pno_set_for_hotlist(&dhd->pub, p_pfn_bssid, hotlist_params));
8330 }
8331 /* Linux wrapper to call common dhd_dev_pno_stop_for_batch */
8332 int
8333 dhd_dev_pno_stop_for_batch(struct net_device *dev)
8334 {
8335         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8336         return (dhd_pno_stop_for_batch(&dhd->pub));
8337 }
8338 /* Linux wrapper to call common dhd_dev_pno_set_for_batch */
8339 int
8340 dhd_dev_pno_set_for_batch(struct net_device *dev, struct dhd_pno_batch_params *batch_params)
8341 {
8342         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8343         return (dhd_pno_set_for_batch(&dhd->pub, batch_params));
8344 }
8345 /* Linux wrapper to call common dhd_dev_pno_get_for_batch */
8346 int
8347 dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize)
8348 {
8349         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8350         return (dhd_pno_get_for_batch(&dhd->pub, buf, bufsize, PNO_STATUS_NORMAL));
8351 }
8352 #endif /* PNO_SUPPORT */
8353
8354 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
8355 static void dhd_hang_process(void *dhd_info, void *event_info, u8 event)
8356 {
8357         dhd_info_t *dhd;
8358         struct net_device *dev;
8359
8360         dhd = (dhd_info_t *)((dhd_pub_t *)dhd_info)->info;
8361         dev = dhd->iflist[0]->net;
8362
8363         if (dev) {
8364                 rtnl_lock();
8365                 dev_close(dev);
8366                 rtnl_unlock();
8367 #if defined(WL_WIRELESS_EXT)
8368                 wl_iw_send_priv_event(dev, "HANG");
8369 #endif
8370 #if defined(WL_CFG80211)
8371                 wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
8372 #endif
8373         }
8374 }
8375
8376
8377 int dhd_os_send_hang_message(dhd_pub_t *dhdp)
8378 {
8379         int ret = 0;
8380         if (dhdp) {
8381                 if (!dhdp->hang_was_sent) {
8382                         dhdp->hang_was_sent = 1;
8383                         dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dhdp,
8384                                 DHD_WQ_WORK_HANG_MSG, dhd_hang_process, DHD_WORK_PRIORITY_HIGH);
8385                 }
8386         }
8387         return ret;
8388 }
8389
8390 int net_os_send_hang_message(struct net_device *dev)
8391 {
8392         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8393         int ret = 0;
8394
8395         if (dhd) {
8396                 /* Report FW problem when enabled */
8397                 if (dhd->pub.hang_report) {
8398 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
8399                         ret = dhd_os_send_hang_message(&dhd->pub);
8400 #else
8401                         ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
8402 #endif
8403                 } else {
8404                         DHD_ERROR(("%s: FW HANG ignored (for testing purpose) and not sent up\n",
8405                                 __FUNCTION__));
8406                         /* Enforce bus down to stop any future traffic */
8407                         dhd->pub.busstate = DHD_BUS_DOWN;
8408                 }
8409         }
8410         return ret;
8411 }
8412 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */
8413
8414
8415 int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on, unsigned long delay_msec)
8416 {
8417         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8418         return wifi_platform_set_power(dhd->adapter, on, delay_msec);
8419 }
8420
8421 void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code,
8422         wl_country_t *cspec)
8423 {
8424         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8425         get_customized_country_code(dhd->adapter, country_iso_code, cspec);
8426
8427 }
8428 void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify)
8429 {
8430         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8431         if (dhd && dhd->pub.up) {
8432                 memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
8433 #ifdef WL_CFG80211
8434                 wl_update_wiphybands(NULL, notify);
8435 #endif
8436         }
8437 }
8438
8439 void dhd_bus_band_set(struct net_device *dev, uint band)
8440 {
8441         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8442         if (dhd && dhd->pub.up) {
8443 #ifdef WL_CFG80211
8444                 wl_update_wiphybands(NULL, true);
8445 #endif
8446         }
8447 }
8448
8449 int dhd_net_set_fw_path(struct net_device *dev, char *fw)
8450 {
8451         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8452
8453         if (!fw || fw[0] == '\0')
8454                 return -EINVAL;
8455
8456         strncpy(dhd->fw_path, fw, sizeof(dhd->fw_path) - 1);
8457         dhd->fw_path[sizeof(dhd->fw_path)-1] = '\0';
8458
8459 #if defined(SOFTAP)
8460         if (strstr(fw, "apsta") != NULL) {
8461                 DHD_INFO(("GOT APSTA FIRMWARE\n"));
8462                 ap_fw_loaded = TRUE;
8463         } else {
8464                 DHD_INFO(("GOT STA FIRMWARE\n"));
8465                 ap_fw_loaded = FALSE;
8466         }
8467 #endif 
8468         return 0;
8469 }
8470
8471 void dhd_net_if_lock(struct net_device *dev)
8472 {
8473         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8474         dhd_net_if_lock_local(dhd);
8475 }
8476
8477 void dhd_net_if_unlock(struct net_device *dev)
8478 {
8479         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8480         dhd_net_if_unlock_local(dhd);
8481 }
8482
8483 static void dhd_net_if_lock_local(dhd_info_t *dhd)
8484 {
8485 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
8486         if (dhd)
8487                 mutex_lock(&dhd->dhd_net_if_mutex);
8488 #endif
8489 }
8490
8491 static void dhd_net_if_unlock_local(dhd_info_t *dhd)
8492 {
8493 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
8494         if (dhd)
8495                 mutex_unlock(&dhd->dhd_net_if_mutex);
8496 #endif
8497 }
8498
8499 static void dhd_suspend_lock(dhd_pub_t *pub)
8500 {
8501 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
8502         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8503         if (dhd)
8504                 mutex_lock(&dhd->dhd_suspend_mutex);
8505 #endif
8506 }
8507
8508 static void dhd_suspend_unlock(dhd_pub_t *pub)
8509 {
8510 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
8511         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8512         if (dhd)
8513                 mutex_unlock(&dhd->dhd_suspend_mutex);
8514 #endif
8515 }
8516
8517 unsigned long dhd_os_general_spin_lock(dhd_pub_t *pub)
8518 {
8519         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8520         unsigned long flags = 0;
8521
8522         if (dhd)
8523                 spin_lock_irqsave(&dhd->dhd_lock, flags);
8524
8525         return flags;
8526 }
8527
8528 void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags)
8529 {
8530         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8531
8532         if (dhd)
8533                 spin_unlock_irqrestore(&dhd->dhd_lock, flags);
8534 }
8535
8536 /* Linux specific multipurpose spinlock API */
8537 void *
8538 dhd_os_spin_lock_init(osl_t *osh)
8539 {
8540         /* Adding 4 bytes since the sizeof(spinlock_t) could be 0 */
8541         /* if CONFIG_SMP and CONFIG_DEBUG_SPINLOCK are not defined */
8542         /* and this results in kernel asserts in internal builds */
8543         spinlock_t * lock = MALLOC(osh, sizeof(spinlock_t) + 4);
8544         if (lock)
8545                 spin_lock_init(lock);
8546         return ((void *)lock);
8547 }
8548 void
8549 dhd_os_spin_lock_deinit(osl_t *osh, void *lock)
8550 {
8551         MFREE(osh, lock, sizeof(spinlock_t) + 4);
8552 }
8553 unsigned long
8554 dhd_os_spin_lock(void *lock)
8555 {
8556         unsigned long flags = 0;
8557
8558         if (lock)
8559                 spin_lock_irqsave((spinlock_t *)lock, flags);
8560
8561         return flags;
8562 }
8563 void
8564 dhd_os_spin_unlock(void *lock, unsigned long flags)
8565 {
8566         if (lock)
8567                 spin_unlock_irqrestore((spinlock_t *)lock, flags);
8568 }
8569
8570 static int
8571 dhd_get_pend_8021x_cnt(dhd_info_t *dhd)
8572 {
8573         return (atomic_read(&dhd->pend_8021x_cnt));
8574 }
8575
8576 #define MAX_WAIT_FOR_8021X_TX   100
8577
8578 int
8579 dhd_wait_pend8021x(struct net_device *dev)
8580 {
8581         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8582         int timeout = msecs_to_jiffies(10);
8583         int ntimes = MAX_WAIT_FOR_8021X_TX;
8584         int pend = dhd_get_pend_8021x_cnt(dhd);
8585
8586         while (ntimes && pend) {
8587                 if (pend) {
8588                         set_current_state(TASK_INTERRUPTIBLE);
8589                         DHD_PERIM_UNLOCK(&dhd->pub);
8590                         schedule_timeout(timeout);
8591                         DHD_PERIM_LOCK(&dhd->pub);
8592                         set_current_state(TASK_RUNNING);
8593                         ntimes--;
8594                 }
8595                 pend = dhd_get_pend_8021x_cnt(dhd);
8596         }
8597         if (ntimes == 0)
8598         {
8599                 atomic_set(&dhd->pend_8021x_cnt, 0);
8600                 DHD_ERROR(("%s: TIMEOUT\n", __FUNCTION__));
8601         }
8602         return pend;
8603 }
8604
8605 #ifdef DHD_DEBUG
8606 int
8607 write_to_file(dhd_pub_t *dhd, uint8 *buf, int size)
8608 {
8609         int ret = 0;
8610         struct file *fp;
8611         mm_segment_t old_fs;
8612         loff_t pos = 0;
8613
8614         /* change to KERNEL_DS address limit */
8615         old_fs = get_fs();
8616         set_fs(KERNEL_DS);
8617
8618         /* open file to write */
8619 #if defined(CUSTOMER_HW5)
8620         fp = filp_open("/data/mem_dump", O_WRONLY|O_CREAT, 0640);
8621 #else
8622         fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640);
8623 #endif 
8624
8625         if (IS_ERR(fp)) {
8626                 fp = NULL;
8627                 printf("%s: open file error\n", __FUNCTION__);
8628                 ret = -1;
8629                 goto exit;
8630         }
8631
8632         /* Write buf to file */
8633         fp->f_op->write(fp, buf, size, &pos);
8634 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
8635         fp->f_op->fsync(fp, 0, size-1, 1);
8636 #else
8637         fp->f_op->fsync(fp, 1);
8638 #endif /* KERNEL_VERSION(3, 1, 0) */
8639
8640 exit:
8641         /* free buf before return */
8642         if (buf) {
8643                 MFREE(dhd->osh, buf, size);
8644         }
8645         /* close file before return */
8646         if (fp)
8647                 filp_close(fp, current->files);
8648         /* restore previous address limit */
8649         set_fs(old_fs);
8650
8651         return ret;
8652 }
8653 #endif /* DHD_DEBUG */
8654
8655 int dhd_os_wake_lock_timeout(dhd_pub_t *pub)
8656 {
8657         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8658         unsigned long flags;
8659         int ret = 0;
8660
8661         if (dhd) {
8662                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
8663                 ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ?
8664                         dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable;
8665 #ifdef CONFIG_HAS_WAKELOCK
8666                 if (dhd->wakelock_rx_timeout_enable)
8667                         wake_lock_timeout(&dhd->wl_rxwake,
8668                                 msecs_to_jiffies(dhd->wakelock_rx_timeout_enable));
8669                 if (dhd->wakelock_ctrl_timeout_enable)
8670                         wake_lock_timeout(&dhd->wl_ctrlwake,
8671                                 msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable));
8672 #endif
8673                 dhd->wakelock_rx_timeout_enable = 0;
8674                 dhd->wakelock_ctrl_timeout_enable = 0;
8675                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
8676         }
8677         return ret;
8678 }
8679
8680 int net_os_wake_lock_timeout(struct net_device *dev)
8681 {
8682         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8683         int ret = 0;
8684
8685         if (dhd)
8686                 ret = dhd_os_wake_lock_timeout(&dhd->pub);
8687         return ret;
8688 }
8689
8690 int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val)
8691 {
8692         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8693         unsigned long flags;
8694
8695         if (dhd) {
8696                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
8697                 if (val > dhd->wakelock_rx_timeout_enable)
8698                         dhd->wakelock_rx_timeout_enable = val;
8699                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
8700         }
8701         return 0;
8702 }
8703
8704 int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val)
8705 {
8706         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8707         unsigned long flags;
8708
8709         if (dhd) {
8710                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
8711                 if (val > dhd->wakelock_ctrl_timeout_enable)
8712                         dhd->wakelock_ctrl_timeout_enable = val;
8713                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
8714         }
8715         return 0;
8716 }
8717
8718 int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub)
8719 {
8720         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8721         unsigned long flags;
8722
8723         if (dhd) {
8724                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
8725                 dhd->wakelock_ctrl_timeout_enable = 0;
8726 #ifdef CONFIG_HAS_WAKELOCK
8727                 if (wake_lock_active(&dhd->wl_ctrlwake))
8728                         wake_unlock(&dhd->wl_ctrlwake);
8729 #endif
8730                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
8731         }
8732         return 0;
8733 }
8734
8735 int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val)
8736 {
8737         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8738         int ret = 0;
8739
8740         if (dhd)
8741                 ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val);
8742         return ret;
8743 }
8744
8745 int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val)
8746 {
8747         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8748         int ret = 0;
8749
8750         if (dhd)
8751                 ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val);
8752         return ret;
8753 }
8754
8755 int dhd_os_wake_lock(dhd_pub_t *pub)
8756 {
8757         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8758         unsigned long flags;
8759         int ret = 0;
8760
8761         if (dhd) {
8762                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
8763
8764                 if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) {
8765 #ifdef CONFIG_HAS_WAKELOCK
8766                         wake_lock(&dhd->wl_wifi);
8767 #elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
8768                         dhd_bus_dev_pm_stay_awake(pub);
8769 #endif
8770                 }
8771                 dhd->wakelock_counter++;
8772                 ret = dhd->wakelock_counter;
8773                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
8774         }
8775         return ret;
8776 }
8777
8778 int net_os_wake_lock(struct net_device *dev)
8779 {
8780         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8781         int ret = 0;
8782
8783         if (dhd)
8784                 ret = dhd_os_wake_lock(&dhd->pub);
8785         return ret;
8786 }
8787
8788 int dhd_os_wake_unlock(dhd_pub_t *pub)
8789 {
8790         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8791         unsigned long flags;
8792         int ret = 0;
8793
8794         dhd_os_wake_lock_timeout(pub);
8795         if (dhd) {
8796                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
8797                 if (dhd->wakelock_counter > 0) {
8798                         dhd->wakelock_counter--;
8799                         if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) {
8800 #ifdef CONFIG_HAS_WAKELOCK
8801                                 wake_unlock(&dhd->wl_wifi);
8802 #elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
8803                                 dhd_bus_dev_pm_relax(pub);
8804 #endif
8805                         }
8806                         ret = dhd->wakelock_counter;
8807                 }
8808                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
8809         }
8810         return ret;
8811 }
8812
8813 int dhd_os_check_wakelock(dhd_pub_t *pub)
8814 {
8815 #if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \
8816         KERNEL_VERSION(2, 6, 36)))
8817         dhd_info_t *dhd;
8818
8819         if (!pub)
8820                 return 0;
8821         dhd = (dhd_info_t *)(pub->info);
8822 #endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */
8823
8824 #ifdef CONFIG_HAS_WAKELOCK
8825         /* Indicate to the SD Host to avoid going to suspend if internal locks are up */
8826         if (dhd && (wake_lock_active(&dhd->wl_wifi) ||
8827                 (wake_lock_active(&dhd->wl_wdwake))))
8828                 return 1;
8829 #elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
8830         if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub))
8831                 return 1;
8832 #endif
8833         return 0;
8834 }
8835
8836 int dhd_os_check_wakelock_all(dhd_pub_t *pub)
8837 {
8838 #if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \
8839         KERNEL_VERSION(2, 6, 36)))
8840         dhd_info_t *dhd;
8841
8842         if (!pub)
8843                 return 0;
8844         dhd = (dhd_info_t *)(pub->info);
8845 #endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */
8846
8847 #ifdef CONFIG_HAS_WAKELOCK
8848         /* Indicate to the SD Host to avoid going to suspend if internal locks are up */
8849         if (dhd && (wake_lock_active(&dhd->wl_wifi) ||
8850                 wake_lock_active(&dhd->wl_wdwake) ||
8851                 wake_lock_active(&dhd->wl_rxwake) ||
8852                 wake_lock_active(&dhd->wl_ctrlwake))) {
8853                 return 1;
8854         }
8855 #elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
8856         if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub))
8857                 return 1;
8858 #endif
8859         return 0;
8860 }
8861
8862 int net_os_wake_unlock(struct net_device *dev)
8863 {
8864         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8865         int ret = 0;
8866
8867         if (dhd)
8868                 ret = dhd_os_wake_unlock(&dhd->pub);
8869         return ret;
8870 }
8871
8872 int dhd_os_wd_wake_lock(dhd_pub_t *pub)
8873 {
8874         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8875         unsigned long flags;
8876         int ret = 0;
8877
8878         if (dhd) {
8879                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
8880 #ifdef CONFIG_HAS_WAKELOCK
8881                 /* if wakelock_wd_counter was never used : lock it at once */
8882                 if (!dhd->wakelock_wd_counter)
8883                         wake_lock(&dhd->wl_wdwake);
8884 #endif
8885                 dhd->wakelock_wd_counter++;
8886                 ret = dhd->wakelock_wd_counter;
8887                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
8888         }
8889         return ret;
8890 }
8891
8892 int dhd_os_wd_wake_unlock(dhd_pub_t *pub)
8893 {
8894         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8895         unsigned long flags;
8896         int ret = 0;
8897
8898         if (dhd) {
8899                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
8900                 if (dhd->wakelock_wd_counter) {
8901                         dhd->wakelock_wd_counter = 0;
8902 #ifdef CONFIG_HAS_WAKELOCK
8903                         wake_unlock(&dhd->wl_wdwake);
8904 #endif
8905                 }
8906                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
8907         }
8908         return ret;
8909 }
8910
8911 #ifdef BCMPCIE_OOB_HOST_WAKE
8912 int dhd_os_oob_irq_wake_lock_timeout(dhd_pub_t *pub, int val)
8913 {
8914         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8915         int ret = 0;
8916
8917         if (dhd) {
8918 #ifdef CONFIG_HAS_WAKELOCK
8919                 wake_lock_timeout(&dhd->wl_intrwake, msecs_to_jiffies(val));
8920 #endif
8921         }
8922         return ret;
8923 }
8924
8925 int dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub)
8926 {
8927         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8928         int ret = 0;
8929
8930         if (dhd) {
8931 #ifdef CONFIG_HAS_WAKELOCK
8932                 /* if wl_intrwake is active, unlock it */
8933                 if (wake_lock_active(&dhd->wl_intrwake)) {
8934                         wake_unlock(&dhd->wl_intrwake);
8935                 }
8936 #endif
8937         }
8938         return ret;
8939 }
8940 #endif /* BCMPCIE_OOB_HOST_WAKE */
8941
8942 /* waive wakelocks for operations such as IOVARs in suspend function, must be closed
8943  * by a paired function call to dhd_wakelock_restore. returns current wakelock counter
8944  */
8945 int dhd_os_wake_lock_waive(dhd_pub_t *pub)
8946 {
8947         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8948         unsigned long flags;
8949         int ret = 0;
8950
8951         if (dhd) {
8952                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
8953                 /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */
8954                 if (dhd->waive_wakelock == FALSE) {
8955                         /* record current lock status */
8956                         dhd->wakelock_before_waive = dhd->wakelock_counter;
8957                         dhd->waive_wakelock = TRUE;
8958                 }
8959                 ret = dhd->wakelock_wd_counter;
8960                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
8961         }
8962         return ret;
8963 }
8964
8965 int dhd_os_wake_lock_restore(dhd_pub_t *pub)
8966 {
8967         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8968         unsigned long flags;
8969         int ret = 0;
8970
8971         if (!dhd)
8972                 return 0;
8973
8974         spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
8975         /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */
8976         if (!dhd->waive_wakelock)
8977                 goto exit;
8978
8979         dhd->waive_wakelock = FALSE;
8980         /* if somebody else acquires wakelock between dhd_wakelock_waive/dhd_wakelock_restore,
8981          * we need to make it up by calling wake_lock or pm_stay_awake. or if somebody releases
8982          * the lock in between, do the same by calling wake_unlock or pm_relax
8983          */
8984         if (dhd->wakelock_before_waive == 0 && dhd->wakelock_counter > 0) {
8985 #ifdef CONFIG_HAS_WAKELOCK
8986                 wake_lock(&dhd->wl_wifi);
8987 #elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
8988                 dhd_bus_dev_pm_stay_awake(&dhd->pub);
8989 #endif
8990         } else if (dhd->wakelock_before_waive > 0 && dhd->wakelock_counter == 0) {
8991 #ifdef CONFIG_HAS_WAKELOCK
8992                 wake_unlock(&dhd->wl_wifi);
8993 #elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
8994                 dhd_bus_dev_pm_relax(&dhd->pub);
8995 #endif
8996         }
8997         dhd->wakelock_before_waive = 0;
8998 exit:
8999         ret = dhd->wakelock_wd_counter;
9000         spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
9001         return ret;
9002 }
9003
9004 bool dhd_os_check_if_up(dhd_pub_t *pub)
9005 {
9006         if (!pub)
9007                 return FALSE;
9008         return pub->up;
9009 }
9010
9011 #if defined(BCMSDIO)
9012 /* function to collect firmware, chip id and chip version info */
9013 void dhd_set_version_info(dhd_pub_t *dhdp, char *fw)
9014 {
9015         int i;
9016
9017         i = snprintf(info_string, sizeof(info_string),
9018                 "  Driver: %s\n  Firmware: %s ", EPI_VERSION_STR, fw);
9019
9020         if (!dhdp)
9021                 return;
9022
9023         i = snprintf(&info_string[i], sizeof(info_string) - i,
9024                 "\n  Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp),
9025                 dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp));
9026 }
9027 #endif /* defined(BCMSDIO) */
9028 int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd)
9029 {
9030         int ifidx;
9031         int ret = 0;
9032         dhd_info_t *dhd = NULL;
9033
9034         if (!net || !DEV_PRIV(net)) {
9035                 DHD_ERROR(("%s invalid parameter\n", __FUNCTION__));
9036                 return -EINVAL;
9037         }
9038
9039         dhd = DHD_DEV_INFO(net);
9040         if (!dhd)
9041                 return -EINVAL;
9042
9043         ifidx = dhd_net2idx(dhd, net);
9044         if (ifidx == DHD_BAD_IF) {
9045                 DHD_ERROR(("%s bad ifidx\n", __FUNCTION__));
9046                 return -ENODEV;
9047         }
9048
9049         DHD_OS_WAKE_LOCK(&dhd->pub);
9050         DHD_PERIM_LOCK(&dhd->pub);
9051
9052         ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len);
9053         dhd_check_hang(net, &dhd->pub, ret);
9054
9055         DHD_PERIM_UNLOCK(&dhd->pub);
9056         DHD_OS_WAKE_UNLOCK(&dhd->pub);
9057
9058         return ret;
9059 }
9060
9061 bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret)
9062 {
9063         struct net_device *net;
9064
9065         net = dhd_idx2net(dhdp, ifidx);
9066         if (!net) {
9067                 DHD_ERROR(("%s : Invalid index : %d\n", __FUNCTION__, ifidx));
9068                 return -EINVAL;
9069         }
9070
9071         return dhd_check_hang(net, dhdp, ret);
9072 }
9073
9074 /* Return instance */
9075 int dhd_get_instance(dhd_pub_t *dhdp)
9076 {
9077         return dhdp->info->unit;
9078 }
9079
9080
9081 #ifdef PROP_TXSTATUS
9082
9083 void dhd_wlfc_plat_init(void *dhd)
9084 {
9085         return;
9086 }
9087
9088 void dhd_wlfc_plat_deinit(void *dhd)
9089 {
9090         return;
9091 }
9092
9093 bool dhd_wlfc_skip_fc(void)
9094 {
9095         return FALSE;
9096 }
9097 #endif /* PROP_TXSTATUS */
9098
9099 #ifdef BCMDBGFS
9100
9101 #include <linux/debugfs.h>
9102
9103 extern uint32 dhd_readregl(void *bp, uint32 addr);
9104 extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data);
9105
9106 typedef struct dhd_dbgfs {
9107         struct dentry   *debugfs_dir;
9108         struct dentry   *debugfs_mem;
9109         dhd_pub_t       *dhdp;
9110         uint32          size;
9111 } dhd_dbgfs_t;
9112
9113 dhd_dbgfs_t g_dbgfs;
9114
9115 static int
9116 dhd_dbg_state_open(struct inode *inode, struct file *file)
9117 {
9118         file->private_data = inode->i_private;
9119         return 0;
9120 }
9121
9122 static ssize_t
9123 dhd_dbg_state_read(struct file *file, char __user *ubuf,
9124                        size_t count, loff_t *ppos)
9125 {
9126         ssize_t rval;
9127         uint32 tmp;
9128         loff_t pos = *ppos;
9129         size_t ret;
9130
9131         if (pos < 0)
9132                 return -EINVAL;
9133         if (pos >= g_dbgfs.size || !count)
9134                 return 0;
9135         if (count > g_dbgfs.size - pos)
9136                 count = g_dbgfs.size - pos;
9137
9138         /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */
9139         tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3));
9140
9141         ret = copy_to_user(ubuf, &tmp, 4);
9142         if (ret == count)
9143                 return -EFAULT;
9144
9145         count -= ret;
9146         *ppos = pos + count;
9147         rval = count;
9148
9149         return rval;
9150 }
9151
9152
9153 static ssize_t
9154 dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos)
9155 {
9156         loff_t pos = *ppos;
9157         size_t ret;
9158         uint32 buf;
9159
9160         if (pos < 0)
9161                 return -EINVAL;
9162         if (pos >= g_dbgfs.size || !count)
9163                 return 0;
9164         if (count > g_dbgfs.size - pos)
9165                 count = g_dbgfs.size - pos;
9166
9167         ret = copy_from_user(&buf, ubuf, sizeof(uint32));
9168         if (ret == count)
9169                 return -EFAULT;
9170
9171         /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */
9172         dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf);
9173
9174         return count;
9175 }
9176
9177
9178 loff_t
9179 dhd_debugfs_lseek(struct file *file, loff_t off, int whence)
9180 {
9181         loff_t pos = -1;
9182
9183         switch (whence) {
9184                 case 0:
9185                         pos = off;
9186                         break;
9187                 case 1:
9188                         pos = file->f_pos + off;
9189                         break;
9190                 case 2:
9191                         pos = g_dbgfs.size - off;
9192         }
9193         return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos);
9194 }
9195
9196 static const struct file_operations dhd_dbg_state_ops = {
9197         .read   = dhd_dbg_state_read,
9198         .write  = dhd_debugfs_write,
9199         .open   = dhd_dbg_state_open,
9200         .llseek = dhd_debugfs_lseek
9201 };
9202
9203 static void dhd_dbg_create(void)
9204 {
9205         if (g_dbgfs.debugfs_dir) {
9206                 g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir,
9207                         NULL, &dhd_dbg_state_ops);
9208         }
9209 }
9210
9211 void dhd_dbg_init(dhd_pub_t *dhdp)
9212 {
9213         int err;
9214
9215         g_dbgfs.dhdp = dhdp;
9216         g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */
9217
9218         g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0);
9219         if (IS_ERR(g_dbgfs.debugfs_dir)) {
9220                 err = PTR_ERR(g_dbgfs.debugfs_dir);
9221                 g_dbgfs.debugfs_dir = NULL;
9222                 return;
9223         }
9224
9225         dhd_dbg_create();
9226
9227         return;
9228 }
9229
9230 void dhd_dbg_remove(void)
9231 {
9232         debugfs_remove(g_dbgfs.debugfs_mem);
9233         debugfs_remove(g_dbgfs.debugfs_dir);
9234
9235         bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs));
9236
9237 }
9238 #endif /* ifdef BCMDBGFS */
9239
9240 #ifdef WLMEDIA_HTSF
9241
9242 static
9243 void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf)
9244 {
9245         dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
9246         struct sk_buff *skb;
9247         uint32 htsf = 0;
9248         uint16 dport = 0, oldmagic = 0xACAC;
9249         char *p1;
9250         htsfts_t ts;
9251
9252         /*  timestamp packet  */
9253
9254         p1 = (char*) PKTDATA(dhdp->osh, pktbuf);
9255
9256         if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) {
9257 /*              memcpy(&proto, p1+26, 4);       */
9258                 memcpy(&dport, p1+40, 2);
9259 /*      proto = ((ntoh32(proto))>> 16) & 0xFF;  */
9260                 dport = ntoh16(dport);
9261         }
9262
9263         /* timestamp only if  icmp or udb iperf with port 5555 */
9264 /*      if (proto == 17 && dport == tsport) { */
9265         if (dport >= tsport && dport <= tsport + 20) {
9266
9267                 skb = (struct sk_buff *) pktbuf;
9268
9269                 htsf = dhd_get_htsf(dhd, 0);
9270                 memset(skb->data + 44, 0, 2); /* clear checksum */
9271                 memcpy(skb->data+82, &oldmagic, 2);
9272                 memcpy(skb->data+84, &htsf, 4);
9273
9274                 memset(&ts, 0, sizeof(htsfts_t));
9275                 ts.magic  = HTSFMAGIC;
9276                 ts.prio   = PKTPRIO(pktbuf);
9277                 ts.seqnum = htsf_seqnum++;
9278                 ts.c10    = get_cycles();
9279                 ts.t10    = htsf;
9280                 ts.endmagic = HTSFENDMAGIC;
9281
9282                 memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts));
9283         }
9284 }
9285
9286 static void dhd_dump_htsfhisto(histo_t *his, char *s)
9287 {
9288         int pktcnt = 0, curval = 0, i;
9289         for (i = 0; i < (NUMBIN-2); i++) {
9290                 curval += 500;
9291                 printf("%d ",  his->bin[i]);
9292                 pktcnt += his->bin[i];
9293         }
9294         printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt,
9295                 his->bin[NUMBIN-1], s);
9296 }
9297
9298 static
9299 void sorttobin(int value, histo_t *histo)
9300 {
9301         int i, binval = 0;
9302
9303         if (value < 0) {
9304                 histo->bin[NUMBIN-1]++;
9305                 return;
9306         }
9307         if (value > histo->bin[NUMBIN-2])  /* store the max value  */
9308                 histo->bin[NUMBIN-2] = value;
9309
9310         for (i = 0; i < (NUMBIN-2); i++) {
9311                 binval += 500; /* 500m s bins */
9312                 if (value <= binval) {
9313                         histo->bin[i]++;
9314                         return;
9315                 }
9316         }
9317         histo->bin[NUMBIN-3]++;
9318 }
9319
9320 static
9321 void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf)
9322 {
9323         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
9324         struct sk_buff *skb;
9325         char *p1;
9326         uint16 old_magic;
9327         int d1, d2, d3, end2end;
9328         htsfts_t *htsf_ts;
9329         uint32 htsf;
9330
9331         skb = PKTTONATIVE(dhdp->osh, pktbuf);
9332         p1 = (char*)PKTDATA(dhdp->osh, pktbuf);
9333
9334         if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) {
9335                 memcpy(&old_magic, p1+78, 2);
9336                 htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4);
9337         }
9338         else
9339                 return;
9340
9341         if (htsf_ts->magic == HTSFMAGIC) {
9342                 htsf_ts->tE0 = dhd_get_htsf(dhd, 0);
9343                 htsf_ts->cE0 = get_cycles();
9344         }
9345
9346         if (old_magic == 0xACAC) {
9347
9348                 tspktcnt++;
9349                 htsf = dhd_get_htsf(dhd, 0);
9350                 memcpy(skb->data+92, &htsf, sizeof(uint32));
9351
9352                 memcpy(&ts[tsidx].t1, skb->data+80, 16);
9353
9354                 d1 = ts[tsidx].t2 - ts[tsidx].t1;
9355                 d2 = ts[tsidx].t3 - ts[tsidx].t2;
9356                 d3 = ts[tsidx].t4 - ts[tsidx].t3;
9357                 end2end = ts[tsidx].t4 - ts[tsidx].t1;
9358
9359                 sorttobin(d1, &vi_d1);
9360                 sorttobin(d2, &vi_d2);
9361                 sorttobin(d3, &vi_d3);
9362                 sorttobin(end2end, &vi_d4);
9363
9364                 if (end2end > 0 && end2end >  maxdelay) {
9365                         maxdelay = end2end;
9366                         maxdelaypktno = tspktcnt;
9367                         memcpy(&maxdelayts, &ts[tsidx], 16);
9368                 }
9369                 if (++tsidx >= TSMAX)
9370                         tsidx = 0;
9371         }
9372 }
9373
9374 uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx)
9375 {
9376         uint32 htsf = 0, cur_cycle, delta, delta_us;
9377         uint32    factor, baseval, baseval2;
9378         cycles_t t;
9379
9380         t = get_cycles();
9381         cur_cycle = t;
9382
9383         if (cur_cycle >  dhd->htsf.last_cycle)
9384                 delta = cur_cycle -  dhd->htsf.last_cycle;
9385         else {
9386                 delta = cur_cycle + (0xFFFFFFFF -  dhd->htsf.last_cycle);
9387         }
9388
9389         delta = delta >> 4;
9390
9391         if (dhd->htsf.coef) {
9392                 /* times ten to get the first digit */
9393                 factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1);
9394                 baseval  = (delta*10)/factor;
9395                 baseval2 = (delta*10)/(factor+1);
9396                 delta_us  = (baseval -  (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10);
9397                 htsf = (delta_us << 4) +  dhd->htsf.last_tsf + HTSF_BUS_DELAY;
9398         }
9399         else {
9400                 DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n"));
9401         }
9402
9403         return htsf;
9404 }
9405
9406 static void dhd_dump_latency(void)
9407 {
9408         int i, max = 0;
9409         int d1, d2, d3, d4, d5;
9410
9411         printf("T1       T2       T3       T4           d1  d2   t4-t1     i    \n");
9412         for (i = 0; i < TSMAX; i++) {
9413                 d1 = ts[i].t2 - ts[i].t1;
9414                 d2 = ts[i].t3 - ts[i].t2;
9415                 d3 = ts[i].t4 - ts[i].t3;
9416                 d4 = ts[i].t4 - ts[i].t1;
9417                 d5 = ts[max].t4-ts[max].t1;
9418                 if (d4 > d5 && d4 > 0)  {
9419                         max = i;
9420                 }
9421                 printf("%08X %08X %08X %08X \t%d %d %d   %d i=%d\n",
9422                         ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4,
9423                         d1, d2, d3, d4, i);
9424         }
9425
9426         printf("current idx = %d \n", tsidx);
9427
9428         printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt);
9429         printf("%08X %08X %08X %08X \t%d %d %d   %d\n",
9430         maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4,
9431         maxdelayts.t2 - maxdelayts.t1,
9432         maxdelayts.t3 - maxdelayts.t2,
9433         maxdelayts.t4 - maxdelayts.t3,
9434         maxdelayts.t4 - maxdelayts.t1);
9435 }
9436
9437
9438 static int
9439 dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx)
9440 {
9441         wl_ioctl_t ioc;
9442         char buf[32];
9443         int ret;
9444         uint32 s1, s2;
9445
9446         struct tsf {
9447                 uint32 low;
9448                 uint32 high;
9449         } tsf_buf;
9450
9451         memset(&ioc, 0, sizeof(ioc));
9452         memset(&tsf_buf, 0, sizeof(tsf_buf));
9453
9454         ioc.cmd = WLC_GET_VAR;
9455         ioc.buf = buf;
9456         ioc.len = (uint)sizeof(buf);
9457         ioc.set = FALSE;
9458
9459         strncpy(buf, "tsf", sizeof(buf) - 1);
9460         buf[sizeof(buf) - 1] = '\0';
9461         s1 = dhd_get_htsf(dhd, 0);
9462         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
9463                 if (ret == -EIO) {
9464                         DHD_ERROR(("%s: tsf is not supported by device\n",
9465                                 dhd_ifname(&dhd->pub, ifidx)));
9466                         return -EOPNOTSUPP;
9467                 }
9468                 return ret;
9469         }
9470         s2 = dhd_get_htsf(dhd, 0);
9471
9472         memcpy(&tsf_buf, buf, sizeof(tsf_buf));
9473         printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ",
9474                 tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1,
9475                 dhd->htsf.coefdec2, s2-tsf_buf.low);
9476         printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle);
9477         return 0;
9478 }
9479
9480 void htsf_update(dhd_info_t *dhd, void *data)
9481 {
9482         static ulong  cur_cycle = 0, prev_cycle = 0;
9483         uint32 htsf, tsf_delta = 0;
9484         uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp;
9485         ulong b, a;
9486         cycles_t t;
9487
9488         /* cycles_t in inlcude/mips/timex.h */
9489
9490         t = get_cycles();
9491
9492         prev_cycle = cur_cycle;
9493         cur_cycle = t;
9494
9495         if (cur_cycle > prev_cycle)
9496                 cyc_delta = cur_cycle - prev_cycle;
9497         else {
9498                 b = cur_cycle;
9499                 a = prev_cycle;
9500                 cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle);
9501         }
9502
9503         if (data == NULL)
9504                 printf(" tsf update ata point er is null \n");
9505
9506         memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t));
9507         memcpy(&cur_tsf, data, sizeof(tsf_t));
9508
9509         if (cur_tsf.low == 0) {
9510                 DHD_INFO((" ---- 0 TSF, do not update, return\n"));
9511                 return;
9512         }
9513
9514         if (cur_tsf.low > prev_tsf.low)
9515                 tsf_delta = (cur_tsf.low - prev_tsf.low);
9516         else {
9517                 DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n",
9518                  cur_tsf.low, prev_tsf.low));
9519                 if (cur_tsf.high > prev_tsf.high) {
9520                         tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low);
9521                         DHD_INFO((" ---- Wrap around tsf coutner  adjusted TSF=%08X\n", tsf_delta));
9522                 }
9523                 else
9524                         return; /* do not update */
9525         }
9526
9527         if (tsf_delta)  {
9528                 hfactor = cyc_delta / tsf_delta;
9529                 tmp  =  (cyc_delta - (hfactor * tsf_delta))*10;
9530                 dec1 =  tmp/tsf_delta;
9531                 dec2 =  ((tmp - dec1*tsf_delta)*10) / tsf_delta;
9532                 tmp  =  (tmp   - (dec1*tsf_delta))*10;
9533                 dec3 =  ((tmp - dec2*tsf_delta)*10) / tsf_delta;
9534
9535                 if (dec3 > 4) {
9536                         if (dec2 == 9) {
9537                                 dec2 = 0;
9538                                 if (dec1 == 9) {
9539                                         dec1 = 0;
9540                                         hfactor++;
9541                                 }
9542                                 else {
9543                                         dec1++;
9544                                 }
9545                         }
9546                         else
9547                                 dec2++;
9548                 }
9549         }
9550
9551         if (hfactor) {
9552                 htsf = ((cyc_delta * 10)  / (hfactor*10+dec1)) + prev_tsf.low;
9553                 dhd->htsf.coef = hfactor;
9554                 dhd->htsf.last_cycle = cur_cycle;
9555                 dhd->htsf.last_tsf = cur_tsf.low;
9556                 dhd->htsf.coefdec1 = dec1;
9557                 dhd->htsf.coefdec2 = dec2;
9558         }
9559         else {
9560                 htsf = prev_tsf.low;
9561         }
9562 }
9563
9564 #endif /* WLMEDIA_HTSF */
9565
9566 #ifdef CUSTOM_SET_CPUCORE
9567 void dhd_set_cpucore(dhd_pub_t *dhd, int set)
9568 {
9569         int e_dpc = 0, e_rxf = 0, retry_set = 0;
9570
9571         if (!(dhd->chan_isvht80)) {
9572                 DHD_ERROR(("%s: chan_status(%d) cpucore!!!\n", __FUNCTION__, dhd->chan_isvht80));
9573                 return;
9574         }
9575
9576         if (DPC_CPUCORE) {
9577                 do {
9578                         if (set == TRUE) {
9579                                 e_dpc = set_cpus_allowed_ptr(dhd->current_dpc,
9580                                         cpumask_of(DPC_CPUCORE));
9581                         } else {
9582                                 e_dpc = set_cpus_allowed_ptr(dhd->current_dpc,
9583                                         cpumask_of(PRIMARY_CPUCORE));
9584                         }
9585                         if (retry_set++ > MAX_RETRY_SET_CPUCORE) {
9586                                 DHD_ERROR(("%s: dpc(%d) invalid cpu!\n", __FUNCTION__, e_dpc));
9587                                 return;
9588                         }
9589                         if (e_dpc < 0)
9590                                 OSL_SLEEP(1);
9591                 } while (e_dpc < 0);
9592         }
9593         if (RXF_CPUCORE) {
9594                 do {
9595                         if (set == TRUE) {
9596                                 e_rxf = set_cpus_allowed_ptr(dhd->current_rxf,
9597                                         cpumask_of(RXF_CPUCORE));
9598                         } else {
9599                                 e_rxf = set_cpus_allowed_ptr(dhd->current_rxf,
9600                                         cpumask_of(PRIMARY_CPUCORE));
9601                         }
9602                         if (retry_set++ > MAX_RETRY_SET_CPUCORE) {
9603                                 DHD_ERROR(("%s: rxf(%d) invalid cpu!\n", __FUNCTION__, e_rxf));
9604                                 return;
9605                         }
9606                         if (e_rxf < 0)
9607                                 OSL_SLEEP(1);
9608                 } while (e_rxf < 0);
9609         }
9610 #ifdef DHD_OF_SUPPORT
9611         interrupt_set_cpucore(set);
9612 #endif /* DHD_OF_SUPPORT */
9613         DHD_TRACE(("%s: set(%d) cpucore success!\n", __FUNCTION__, set));
9614
9615         return;
9616 }
9617 #endif /* CUSTOM_SET_CPUCORE */
9618
9619 /* Get interface specific ap_isolate configuration */
9620 int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx)
9621 {
9622         dhd_info_t *dhd = dhdp->info;
9623         dhd_if_t *ifp;
9624
9625         ASSERT(idx < DHD_MAX_IFS);
9626
9627         ifp = dhd->iflist[idx];
9628
9629         return ifp->ap_isolate;
9630 }
9631
9632 /* Set interface specific ap_isolate configuration */
9633 int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val)
9634 {
9635         dhd_info_t *dhd = dhdp->info;
9636         dhd_if_t *ifp;
9637
9638         ASSERT(idx < DHD_MAX_IFS);
9639
9640         ifp = dhd->iflist[idx];
9641
9642         ifp->ap_isolate = val;
9643
9644         return 0;
9645 }
9646
9647 #if defined(DHD_DEBUG)
9648 void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size)
9649 {
9650         dhd_dump_t *dump = NULL;
9651         dump = MALLOC(dhdp->osh, sizeof(dhd_dump_t));
9652         dump->buf = buf;
9653         dump->bufsize = size;
9654         dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dump,
9655                 DHD_WQ_WORK_SOC_RAM_DUMP, dhd_mem_dump, DHD_WORK_PRIORITY_HIGH);
9656 }
9657
9658 static void
9659 dhd_mem_dump(void *handle, void *event_info, u8 event)
9660 {
9661         dhd_info_t *dhd = handle;
9662         dhd_dump_t *dump = event_info;
9663
9664         if (!dhd || !dump)
9665                 return;
9666
9667         if (write_to_file(&dhd->pub, dump->buf, dump->bufsize)) {
9668                 DHD_ERROR(("%s: writing SoC_RAM dump to the file failed\n", __FUNCTION__));
9669         }
9670         MFREE(dhd->pub.osh, dump, sizeof(dhd_dump_t));
9671 }
9672 #endif /* DHD_DEBUG */
9673
9674 #ifdef DHD_WMF
9675 /* Returns interface specific WMF configuration */
9676 dhd_wmf_t* dhd_wmf_conf(dhd_pub_t *dhdp, uint32 idx)
9677 {
9678         dhd_info_t *dhd = dhdp->info;
9679         dhd_if_t *ifp;
9680
9681         ASSERT(idx < DHD_MAX_IFS);
9682
9683         ifp = dhd->iflist[idx];
9684         return &ifp->wmf;
9685 }
9686 #endif /* DHD_WMF */
9687
9688
9689 #ifdef DHD_UNICAST_DHCP
9690 static int
9691 dhd_get_pkt_ether_type(dhd_pub_t *pub, void *pktbuf,
9692         uint8 **data_ptr, int *len_ptr, uint16 *et_ptr, bool *snap_ptr)
9693 {
9694         uint8 *frame = PKTDATA(pub->osh, pktbuf);
9695         int length = PKTLEN(pub->osh, pktbuf);
9696         uint8 *pt;                      /* Pointer to type field */
9697         uint16 ethertype;
9698         bool snap = FALSE;
9699         /* Process Ethernet II or SNAP-encapsulated 802.3 frames */
9700         if (length < ETHER_HDR_LEN) {
9701                 DHD_ERROR(("dhd: %s: short eth frame (%d)\n",
9702                            __FUNCTION__, length));
9703                 return BCME_ERROR;
9704         } else if (ntoh16_ua(frame + ETHER_TYPE_OFFSET) >= ETHER_TYPE_MIN) {
9705                 /* Frame is Ethernet II */
9706                 pt = frame + ETHER_TYPE_OFFSET;
9707         } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN &&
9708                    !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) {
9709                 pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN;
9710                 snap = TRUE;
9711         } else {
9712                 DHD_INFO(("DHD: %s: non-SNAP 802.3 frame\n",
9713                            __FUNCTION__));
9714                 return BCME_ERROR;
9715         }
9716
9717         ethertype = ntoh16_ua(pt);
9718
9719         /* Skip VLAN tag, if any */
9720         if (ethertype == ETHER_TYPE_8021Q) {
9721                 pt += VLAN_TAG_LEN;
9722
9723                 if ((pt + ETHER_TYPE_LEN) > (frame + length)) {
9724                         DHD_ERROR(("dhd: %s: short VLAN frame (%d)\n",
9725                                   __FUNCTION__, length));
9726                         return BCME_ERROR;
9727                 }
9728
9729                 ethertype = ntoh16_ua(pt);
9730         }
9731
9732         *data_ptr = pt + ETHER_TYPE_LEN;
9733         *len_ptr = length - (pt + ETHER_TYPE_LEN - frame);
9734         *et_ptr = ethertype;
9735         *snap_ptr = snap;
9736         return BCME_OK;
9737 }
9738
9739 static int
9740 dhd_get_pkt_ip_type(dhd_pub_t *pub, void *pktbuf,
9741         uint8 **data_ptr, int *len_ptr, uint8 *prot_ptr)
9742 {
9743         struct ipv4_hdr *iph;           /* IP frame pointer */
9744         int iplen;                      /* IP frame length */
9745         uint16 ethertype, iphdrlen, ippktlen;
9746         uint16 iph_frag;
9747         uint8 prot;
9748         bool snap;
9749
9750         if (dhd_get_pkt_ether_type(pub, pktbuf, (uint8 **)&iph,
9751             &iplen, &ethertype, &snap) != 0)
9752                 return BCME_ERROR;
9753
9754         if (ethertype != ETHER_TYPE_IP) {
9755                 return BCME_ERROR;
9756         }
9757
9758         /* We support IPv4 only */
9759         if (iplen < IPV4_OPTIONS_OFFSET || (IP_VER(iph) != IP_VER_4)) {
9760                 return BCME_ERROR;
9761         }
9762
9763         /* Header length sanity */
9764         iphdrlen = IPV4_HLEN(iph);
9765
9766         /*
9767          * Packet length sanity; sometimes we receive eth-frame size bigger
9768          * than the IP content, which results in a bad tcp chksum
9769          */
9770         ippktlen = ntoh16(iph->tot_len);
9771         if (ippktlen < iplen) {
9772
9773                 DHD_INFO(("%s: extra frame length ignored\n",
9774                           __FUNCTION__));
9775                 iplen = ippktlen;
9776         } else if (ippktlen > iplen) {
9777                 DHD_ERROR(("dhd: %s: truncated IP packet (%d)\n",
9778                            __FUNCTION__, ippktlen - iplen));
9779                 return BCME_ERROR;
9780         }
9781
9782         if (iphdrlen < IPV4_OPTIONS_OFFSET || iphdrlen > iplen) {
9783                 DHD_ERROR(("DHD: %s: IP-header-len (%d) out of range (%d-%d)\n",
9784                            __FUNCTION__, iphdrlen, IPV4_OPTIONS_OFFSET, iplen));
9785                 return BCME_ERROR;
9786         }
9787
9788         /*
9789          * We don't handle fragmented IP packets.  A first frag is indicated by the MF
9790          * (more frag) bit and a subsequent frag is indicated by a non-zero frag offset.
9791          */
9792         iph_frag = ntoh16(iph->frag);
9793
9794         if ((iph_frag & IPV4_FRAG_MORE) || (iph_frag & IPV4_FRAG_OFFSET_MASK) != 0) {
9795                 DHD_INFO(("DHD:%s: IP fragment not handled\n",
9796                            __FUNCTION__));
9797                 return BCME_ERROR;
9798         }
9799
9800         prot = IPV4_PROT(iph);
9801
9802         *data_ptr = (((uint8 *)iph) + iphdrlen);
9803         *len_ptr = iplen - iphdrlen;
9804         *prot_ptr = prot;
9805         return BCME_OK;
9806 }
9807
9808 /** check the packet type, if it is DHCP ACK/REPLY, convert into unicast packet */
9809 static
9810 int dhd_convert_dhcp_broadcast_ack_to_unicast(dhd_pub_t *pub, void *pktbuf, int ifidx)
9811 {
9812         dhd_sta_t* stainfo;
9813         uint8 *eh = PKTDATA(pub->osh, pktbuf);
9814         uint8 *udph;
9815         uint8 *dhcp;
9816         uint8 *chaddr;
9817         int udpl;
9818         int dhcpl;
9819         uint16 port;
9820         uint8 prot;
9821
9822         if (!ETHER_ISMULTI(eh + ETHER_DEST_OFFSET))
9823             return BCME_ERROR;
9824         if (dhd_get_pkt_ip_type(pub, pktbuf, &udph, &udpl, &prot) != 0)
9825                 return BCME_ERROR;
9826         if (prot != IP_PROT_UDP)
9827                 return BCME_ERROR;
9828         /* check frame length, at least UDP_HDR_LEN */
9829         if (udpl < UDP_HDR_LEN) {
9830                 DHD_ERROR(("DHD: %s: short UDP frame, ignored\n",
9831                     __FUNCTION__));
9832                 return BCME_ERROR;
9833         }
9834         port = ntoh16_ua(udph + UDP_DEST_PORT_OFFSET);
9835         /* only process DHCP packets from server to client */
9836         if (port != DHCP_PORT_CLIENT)
9837                 return BCME_ERROR;
9838
9839         dhcp = udph + UDP_HDR_LEN;
9840         dhcpl = udpl - UDP_HDR_LEN;
9841
9842         if (dhcpl < DHCP_CHADDR_OFFSET + ETHER_ADDR_LEN) {
9843                 DHD_ERROR(("DHD: %s: short DHCP frame, ignored\n",
9844                     __FUNCTION__));
9845                 return BCME_ERROR;
9846         }
9847         /* only process DHCP reply(offer/ack) packets */
9848         if (*(dhcp + DHCP_TYPE_OFFSET) != DHCP_TYPE_REPLY)
9849                 return BCME_ERROR;
9850         chaddr = dhcp + DHCP_CHADDR_OFFSET;
9851         stainfo = dhd_find_sta(pub, ifidx, chaddr);
9852         if (stainfo) {
9853                 bcopy(chaddr, eh + ETHER_DEST_OFFSET, ETHER_ADDR_LEN);
9854                 return BCME_OK;
9855         }
9856         return BCME_ERROR;
9857 }
9858 #endif /* DHD_UNICAST_DHD */
9859 #ifdef DHD_L2_FILTER
9860 /* Check if packet type is ICMP ECHO */
9861 static
9862 int dhd_l2_filter_block_ping(dhd_pub_t *pub, void *pktbuf, int ifidx)
9863 {
9864         struct bcmicmp_hdr *icmph;
9865         int udpl;
9866         uint8 prot;
9867
9868         if (dhd_get_pkt_ip_type(pub, pktbuf, (uint8 **)&icmph, &udpl, &prot) != 0)
9869                 return BCME_ERROR;
9870         if (prot == IP_PROT_ICMP) {
9871                 if (icmph->type == ICMP_TYPE_ECHO_REQUEST)
9872                         return BCME_OK;
9873         }
9874         return BCME_ERROR;
9875 }
9876 #endif /* DHD_L2_FILTER */
9877
9878 int
9879 dhd_set_slpauto_mode(struct net_device *dev, s32 val)
9880 {
9881 #ifdef BCMSDIO
9882         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
9883         int ret;
9884
9885         if (!dhd)
9886                 return -1;
9887
9888         DHD_ERROR(("Setting dhd auto sleep(dhd_slpauto) to %s\n",
9889                         val ? "enable" : "disable"));
9890         dhd_os_sdlock(&dhd->pub);
9891         val = htod32(val);
9892         ret = dhd_slpauto_config(&dhd->pub, val);
9893         dhd_os_sdunlock(&dhd->pub);
9894
9895         return ret;
9896 #else
9897         return BCME_UNSUPPORTED;
9898 #endif
9899 }
9900
9901 #if defined(SET_RPS_CPUS) || defined(ARGOS_RPS_CPU_CTL)
9902 int dhd_rps_cpus_enable(struct net_device *net, int enable)
9903 {
9904         dhd_info_t *dhd = DHD_DEV_INFO(net);
9905         dhd_if_t *ifp;
9906         int ifidx;
9907         char * RPS_CPU_SETBUF;
9908
9909         ifidx = dhd_net2idx(dhd, net);
9910         if (ifidx == DHD_BAD_IF) {
9911                 DHD_ERROR(("%s bad ifidx\n", __FUNCTION__));
9912                 return -ENODEV;
9913         }
9914
9915         if (ifidx == PRIMARY_INF) {
9916                 if (dhd->pub.op_mode == DHD_FLAG_IBSS_MODE) {
9917                         DHD_INFO(("%s : set for IBSS.\n", __FUNCTION__));
9918                         RPS_CPU_SETBUF = RPS_CPUS_MASK_IBSS;
9919                 } else {
9920                         DHD_INFO(("%s : set for BSS.\n", __FUNCTION__));
9921                         RPS_CPU_SETBUF = RPS_CPUS_MASK;
9922                 }
9923         } else if (ifidx == VIRTUAL_INF) {
9924                 DHD_INFO(("%s : set for P2P.\n", __FUNCTION__));
9925                 RPS_CPU_SETBUF = RPS_CPUS_MASK_P2P;
9926         } else {
9927                 DHD_ERROR(("%s : Invalid index : %d.\n", __FUNCTION__, ifidx));
9928                 return -EINVAL;
9929         }
9930
9931         ifp = dhd->iflist[ifidx];
9932         if (ifp) {
9933                 if (enable) {
9934                         DHD_INFO(("%s : set rps_cpus as [%s]\n", __FUNCTION__, RPS_CPU_SETBUF));
9935                         custom_rps_map_set(ifp->net->_rx, RPS_CPU_SETBUF, strlen(RPS_CPU_SETBUF));
9936                 } else {
9937                         custom_rps_map_clear(ifp->net->_rx);
9938                 }
9939         } else {
9940                 DHD_ERROR(("%s : ifp is NULL!!\n", __FUNCTION__));
9941                 return -ENODEV;
9942         }
9943         return BCME_OK;
9944 }
9945
9946 int custom_rps_map_set(struct netdev_rx_queue *queue, char *buf, size_t len)
9947 {
9948         struct rps_map *old_map, *map;
9949         cpumask_var_t mask;
9950         int err, cpu, i;
9951         static DEFINE_SPINLOCK(rps_map_lock);
9952
9953         DHD_INFO(("%s : Entered.\n", __FUNCTION__));
9954
9955         if (!alloc_cpumask_var(&mask, GFP_KERNEL)) {
9956                 DHD_ERROR(("%s : alloc_cpumask_var fail.\n", __FUNCTION__));
9957                 return -ENOMEM;
9958         }
9959
9960         err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits);
9961         if (err) {
9962                 free_cpumask_var(mask);
9963                 DHD_ERROR(("%s : bitmap_parse fail.\n", __FUNCTION__));
9964                 return err;
9965         }
9966
9967         map = kzalloc(max_t(unsigned int,
9968                 RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES),
9969                 GFP_KERNEL);
9970         if (!map) {
9971                 free_cpumask_var(mask);
9972                 DHD_ERROR(("%s : map malloc fail.\n", __FUNCTION__));
9973                 return -ENOMEM;
9974         }
9975
9976         i = 0;
9977         for_each_cpu(cpu, mask)
9978                 map->cpus[i++] = cpu;
9979
9980         if (i)
9981                 map->len = i;
9982         else {
9983                 kfree(map);
9984                 map = NULL;
9985                 free_cpumask_var(mask);
9986                 DHD_ERROR(("%s : mapping cpu fail.\n", __FUNCTION__));
9987                 return -1;
9988         }
9989
9990         spin_lock(&rps_map_lock);
9991         old_map = rcu_dereference_protected(queue->rps_map,
9992                 lockdep_is_held(&rps_map_lock));
9993         rcu_assign_pointer(queue->rps_map, map);
9994         spin_unlock(&rps_map_lock);
9995
9996         if (map)
9997                 static_key_slow_inc(&rps_needed);
9998         if (old_map) {
9999                 kfree_rcu(old_map, rcu);
10000                 static_key_slow_dec(&rps_needed);
10001         }
10002         free_cpumask_var(mask);
10003
10004         DHD_INFO(("%s : Done. mapping cpu nummber : %d\n", __FUNCTION__, map->len));
10005         return map->len;
10006 }
10007
10008 void custom_rps_map_clear(struct netdev_rx_queue *queue)
10009 {
10010         struct rps_map *map;
10011
10012         DHD_INFO(("%s : Entered.\n", __FUNCTION__));
10013
10014         map = rcu_dereference_protected(queue->rps_map, 1);
10015         if (map) {
10016                 RCU_INIT_POINTER(queue->rps_map, NULL);
10017                 kfree_rcu(map, rcu);
10018                 DHD_INFO(("%s : rps_cpus map clear.\n", __FUNCTION__));
10019         }
10020 }
10021 #endif /* SET_RPS_CPUS || ARGOS_RPS_CPU_CTL */
10022
10023
10024 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
10025 void
10026 SDA_setSharedMemory4Send(unsigned int buffer_id,
10027                          unsigned char *buffer, unsigned int buffer_size,
10028                          unsigned int packet_size, unsigned int headroom_size)
10029 {
10030         dhd_info_t *dhd = dhd_global;
10031
10032         sda_packet_length = packet_size;
10033
10034         ASSERT(dhd);
10035         if (dhd == NULL)
10036                 return;
10037 }
10038
10039 void
10040 SDA_registerCallback4SendDone(SDA_SendDoneCallBack packet_cb)
10041 {
10042         dhd_info_t *dhd = dhd_global;
10043
10044         ASSERT(dhd);
10045         if (dhd == NULL)
10046                 return;
10047 }
10048
10049
10050 unsigned long long
10051 SDA_getTsf(unsigned char vif_id)
10052 {
10053         dhd_info_t *dhd = dhd_global;
10054         uint64 tsf_val;
10055         char buf[WLC_IOCTL_SMLEN];
10056         int ifidx = 0;
10057
10058         struct tsf {
10059                 uint32 low;
10060                 uint32 high;
10061         } tsf_buf;
10062
10063         memset(buf, 0, sizeof(buf));
10064
10065         if (vif_id == 0) /* wlan0 tsf */
10066                 ifidx = dhd_ifname2idx(dhd, "wlan0");
10067         else if (vif_id == 1) /* p2p0 tsf */
10068                 ifidx = dhd_ifname2idx(dhd, "p2p0");
10069
10070         bcm_mkiovar("tsf_bss", 0, 0, buf, sizeof(buf));
10071
10072         if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_GET_VAR, buf, sizeof(buf), FALSE, ifidx) < 0) {
10073                 DHD_ERROR(("%s wl ioctl error\n", __FUNCTION__));
10074                 return 0;
10075         }
10076
10077         memcpy(&tsf_buf, buf, sizeof(tsf_buf));
10078         tsf_val = (uint64)tsf_buf.high;
10079         DHD_TRACE(("%s tsf high 0x%08x, low 0x%08x\n",
10080                    __FUNCTION__, tsf_buf.high, tsf_buf.low));
10081
10082         return ((tsf_val << 32) | tsf_buf.low);
10083 }
10084 EXPORT_SYMBOL(SDA_getTsf);
10085
10086 unsigned int
10087 SDA_syncTsf(void)
10088 {
10089         dhd_info_t *dhd = dhd_global;
10090         int tsf_sync = 1;
10091         char iovbuf[WLC_IOCTL_SMLEN];
10092
10093         bcm_mkiovar("wa_tsf_sync", (char *)&tsf_sync, 4, iovbuf, sizeof(iovbuf));
10094         dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
10095
10096         DHD_TRACE(("%s\n", __FUNCTION__));
10097         return 0;
10098 }
10099
10100 extern struct net_device *wl0dot1_dev;
10101
10102 void
10103 BCMFASTPATH SDA_function4Send(uint buffer_id, void *packet, uint packet_size)
10104 {
10105         struct sk_buff *skb;
10106         sda_packet_t *shm_packet = packet;
10107         dhd_info_t *dhd = dhd_global;
10108         int cnt;
10109
10110         static unsigned int cnt_t = 1;
10111
10112         ASSERT(dhd);
10113         if (dhd == NULL)
10114                 return;
10115
10116         if (dhd->is_wlanaudio_blist) {
10117                 for (cnt = 0; cnt < MAX_WLANAUDIO_BLACKLIST; cnt++) {
10118                         if (dhd->wlanaudio_blist[cnt].is_blacklist == true) {
10119                                 if (!bcmp(dhd->wlanaudio_blist[cnt].blacklist_addr.octet,
10120                                           shm_packet->headroom.ether_dhost, ETHER_ADDR_LEN))
10121                                         return;
10122                         }
10123                 }
10124         }
10125
10126         if ((cnt_t % 10000) == 0)
10127                 cnt_t = 0;
10128
10129         cnt_t++;
10130
10131         /* packet_size may be smaller than SDA_SHM_PKT_SIZE, remaining will be garbage */
10132 #define TXOFF 26
10133         skb = __dev_alloc_skb(TXOFF + sda_packet_length - SDA_PKT_HEADER_SIZE, GFP_ATOMIC);
10134
10135         skb_reserve(skb, TXOFF - SDA_HEADROOM_SIZE);
10136         skb_put(skb, sda_packet_length - SDA_PKT_HEADER_SIZE + SDA_HEADROOM_SIZE);
10137         skb->priority = PRIO_8021D_VO; /* PRIO_8021D_VO or PRIO_8021D_VI */
10138
10139         /* p2p_net  */
10140         skb->dev = wl0dot1_dev;
10141         shm_packet->txTsf = 0x0;
10142         shm_packet->rxTsf = 0x0;
10143         memcpy(skb->data, &shm_packet->headroom,
10144                sda_packet_length - OFFSETOF(sda_packet_t, headroom));
10145         shm_packet->desc.ready_to_copy = 0;
10146
10147         dhd_start_xmit(skb, skb->dev);
10148 }
10149
10150 void
10151 SDA_registerCallback4Recv(unsigned char *pBufferTotal,
10152                           unsigned int BufferTotalSize)
10153 {
10154         dhd_info_t *dhd = dhd_global;
10155
10156         ASSERT(dhd);
10157         if (dhd == NULL)
10158                 return;
10159 }
10160
10161
10162 void
10163 SDA_setSharedMemory4Recv(unsigned char *pBufferTotal,
10164                          unsigned int BufferTotalSize,
10165                          unsigned int BufferUnitSize,
10166                          unsigned int Headroomsize)
10167 {
10168         dhd_info_t *dhd = dhd_global;
10169
10170         ASSERT(dhd);
10171         if (dhd == NULL)
10172                 return;
10173 }
10174
10175
10176 void
10177 SDA_function4RecvDone(unsigned char * pBuffer, unsigned int BufferSize)
10178 {
10179         dhd_info_t *dhd = dhd_global;
10180
10181         ASSERT(dhd);
10182         if (dhd == NULL)
10183                 return;
10184 }
10185
10186 EXPORT_SYMBOL(SDA_setSharedMemory4Send);
10187 EXPORT_SYMBOL(SDA_registerCallback4SendDone);
10188 EXPORT_SYMBOL(SDA_syncTsf);
10189 EXPORT_SYMBOL(SDA_function4Send);
10190 EXPORT_SYMBOL(SDA_registerCallback4Recv);
10191 EXPORT_SYMBOL(SDA_setSharedMemory4Recv);
10192 EXPORT_SYMBOL(SDA_function4RecvDone);
10193
10194 #endif /* CUSTOMER_HW20 && WLANAUDIO */