net: wireless: bcmdhd: bump thread priority
[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-2014, Broadcom Corporation
6  * 
7  *      Unless you and Broadcom execute a separate written software license
8  * agreement governing use of this software, this software is licensed to you
9  * under the terms of the GNU General Public License version 2 (the "GPL"),
10  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11  * following added to such license:
12  * 
13  *      As a special exception, the copyright holders of this software give you
14  * permission to link this software with independent modules, and to copy and
15  * distribute the resulting executable under terms of your choice, provided that
16  * you also meet, for each linked independent module, the terms and conditions of
17  * the license of that module.  An independent module is a module which is not
18  * derived from this software.  The special exception does not apply to any
19  * modifications of the software.
20  * 
21  *      Notwithstanding the above, under no circumstances may you combine this
22  * software in any way with any other Broadcom software provided under a license
23  * other than the GPL, without Broadcom's express prior written consent.
24  *
25  * $Id: dhd_linux.c 490850 2014-07-12 14:54:04Z $
26  */
27
28 #include <typedefs.h>
29 #include <linuxver.h>
30 #include <osl.h>
31 #ifdef SHOW_LOGTRACE
32 #include <linux/syscalls.h>
33 #include <event_log.h>
34 #endif /* SHOW_LOGTRACE */
35
36
37 #include <linux/init.h>
38 #include <linux/kernel.h>
39 #ifdef ENCRYPTED_NVRAM
40 #include <linux/crypto.h>
41 #endif
42 #include <linux/slab.h>
43 #include <linux/skbuff.h>
44 #include <linux/netdevice.h>
45 #include <linux/inetdevice.h>
46 #include <linux/rtnetlink.h>
47 #include <linux/etherdevice.h>
48 #include <linux/random.h>
49 #include <linux/spinlock.h>
50 #include <linux/ethtool.h>
51 #include <linux/fcntl.h>
52 #include <linux/fs.h>
53 #include <linux/ip.h>
54 #include <linux/reboot.h>
55 #include <linux/notifier.h>
56 #include <net/addrconf.h>
57 #ifdef ENABLE_ADAPTIVE_SCHED
58 #include <linux/cpufreq.h>
59 #endif /* ENABLE_ADAPTIVE_SCHED */
60
61 #include <asm/uaccess.h>
62 #include <asm/unaligned.h>
63
64 #include <epivers.h>
65 #include <bcmutils.h>
66 #include <bcmendian.h>
67 #include <bcmdevs.h>
68
69 #include <proto/ethernet.h>
70 #include <proto/bcmevent.h>
71 #include <proto/vlan.h>
72 #include <proto/bcmudp.h>
73 #include <proto/bcmdhcp.h>
74 #ifdef DHD_L2_FILTER
75 #include <proto/bcmicmp.h>
76 #endif
77 #include <proto/802.3.h>
78
79 #include <dngl_stats.h>
80 #include <dhd_linux_wq.h>
81 #include <dhd.h>
82 #include <dhd_linux.h>
83 #ifdef PCIE_FULL_DONGLE
84 #include <dhd_flowring.h>
85 #endif
86 #include <dhd_bus.h>
87 #include <dhd_proto.h>
88 #include <dhd_dbg.h>
89 /* Used for the bottom half, so same priority as the other irqthread */
90 #define DHD_DEFAULT_RT_PRIORITY (MAX_USER_RT_PRIO / 2)
91 #ifdef CONFIG_HAS_WAKELOCK
92 #include <linux/wakelock.h>
93 #endif
94 #ifdef WL_CFG80211
95 #include <wl_cfg80211.h>
96 #endif
97 #ifdef PNO_SUPPORT
98 #include <dhd_pno.h>
99 #endif
100
101 #ifdef CONFIG_COMPAT
102 #include <linux/compat.h>
103 #endif
104
105 #ifdef DHD_WMF
106 #include <dhd_wmf_linux.h>
107 #endif /* DHD_WMF */
108
109 #ifdef DHDTCPACK_SUPPRESS
110 #include <dhd_ip.h>
111 #endif /* DHDTCPACK_SUPPRESS */
112
113 #ifdef CONFIG_BCMDHD_CUSTOM_SYSFS_TEGRA
114 #include "dhd_custom_sysfs_tegra.h"
115
116 #define RX_CAPTURE(skb)\
117         {\
118                 tegra_sysfs_histogram_tcpdump_rx(skb, __func__, __LINE__);\
119         }\
120
121 #define DPC_CAPTURE(void)\
122         {\
123                 tegra_sysfs_dpc_pkt();\
124         } \
125
126 #else
127
128 #define RX_CAPTURE(skb)
129
130 #define DPC_CAPTURE(void)
131
132 #endif
133
134 #ifdef WLMEDIA_HTSF
135 #include <linux/time.h>
136 #include <htsf.h>
137
138 #define HTSF_MINLEN 200    /* min. packet length to timestamp */
139 #define HTSF_BUS_DELAY 150 /* assume a fix propagation in us  */
140 #define TSMAX  1000        /* max no. of timing record kept   */
141 #define NUMBIN 34
142
143 static uint32 tsidx = 0;
144 static uint32 htsf_seqnum = 0;
145 uint32 tsfsync;
146 struct timeval tsync;
147 static uint32 tsport = 5010;
148
149 typedef struct histo_ {
150         uint32 bin[NUMBIN];
151 } histo_t;
152
153 #if !ISPOWEROF2(DHD_SDALIGN)
154 #error DHD_SDALIGN is not a power of 2!
155 #endif
156
157 static histo_t vi_d1, vi_d2, vi_d3, vi_d4;
158 #endif /* WLMEDIA_HTSF */
159
160
161
162 #if defined(SOFTAP)
163 extern bool ap_cfg_running;
164 extern bool ap_fw_loaded;
165 #endif
166
167
168 #ifdef ENABLE_ADAPTIVE_SCHED
169 #define DEFAULT_CPUFREQ_THRESH          1000000 /* threshold frequency : 1000000 = 1GHz */
170 #ifndef CUSTOM_CPUFREQ_THRESH
171 #define CUSTOM_CPUFREQ_THRESH   DEFAULT_CPUFREQ_THRESH
172 #endif /* CUSTOM_CPUFREQ_THRESH */
173 #endif /* ENABLE_ADAPTIVE_SCHED */
174
175 /* enable HOSTIP cache update from the host side when an eth0:N is up */
176 #define AOE_IP_ALIAS_SUPPORT 1
177
178 #ifdef BCM_FD_AGGR
179 #include <bcm_rpc.h>
180 #include <bcm_rpc_tp.h>
181 #endif
182 #ifdef PROP_TXSTATUS
183 #include <wlfc_proto.h>
184 #include <dhd_wlfc.h>
185 #endif
186
187 #include <wl_android.h>
188
189 /* Maximum STA per radio */
190 #define DHD_MAX_STA     32
191
192
193 const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 };
194 const uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
195 #define WME_PRIO2AC(prio)  wme_fifo2ac[prio2fifo[(prio)]]
196
197 #ifdef ARP_OFFLOAD_SUPPORT
198 void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx);
199 static int dhd_inetaddr_notifier_call(struct notifier_block *this,
200         unsigned long event, void *ptr);
201 static struct notifier_block dhd_inetaddr_notifier = {
202         .notifier_call = dhd_inetaddr_notifier_call
203 };
204 /* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
205  * created in kernel notifier link list (with 'next' pointing to itself)
206  */
207 static bool dhd_inetaddr_notifier_registered = FALSE;
208 #endif /* ARP_OFFLOAD_SUPPORT */
209
210 #ifdef CONFIG_IPV6
211 static int dhd_inet6addr_notifier_call(struct notifier_block *this,
212         unsigned long event, void *ptr);
213 static struct notifier_block dhd_inet6addr_notifier = {
214         .notifier_call = dhd_inet6addr_notifier_call
215 };
216 /* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
217  * created in kernel notifier link list (with 'next' pointing to itself)
218  */
219 static bool dhd_inet6addr_notifier_registered = FALSE;
220 #endif
221
222 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
223 #include <linux/suspend.h>
224 volatile bool dhd_mmc_suspend = FALSE;
225 DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
226 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
227
228 #if defined(OOB_INTR_ONLY)
229 extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable);
230 #endif 
231 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
232 static void dhd_hang_process(void *dhd_info, void *event_data, u8 event);
233 #endif 
234 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
235 MODULE_LICENSE("GPL v2");
236 #endif /* LinuxVer */
237
238 #include <dhd_bus.h>
239
240 #ifdef BCM_FD_AGGR
241 #define DBUS_RX_BUFFER_SIZE_DHD(net)    (BCM_RPC_TP_DNGL_AGG_MAX_BYTE)
242 #else
243 #ifndef PROP_TXSTATUS
244 #define DBUS_RX_BUFFER_SIZE_DHD(net)    (net->mtu + net->hard_header_len + dhd->pub.hdrlen)
245 #else
246 #define DBUS_RX_BUFFER_SIZE_DHD(net)    (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128)
247 #endif
248 #endif /* BCM_FD_AGGR */
249
250 #ifdef PROP_TXSTATUS
251 extern bool dhd_wlfc_skip_fc(void);
252 extern void dhd_wlfc_plat_init(void *dhd);
253 extern void dhd_wlfc_plat_deinit(void *dhd);
254 #endif /* PROP_TXSTATUS */
255 extern int dhd_slpauto_config(dhd_pub_t *dhd, s32 val);
256
257 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15)
258 const char *
259 print_tainted()
260 {
261         return "";
262 }
263 #endif  /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */
264
265 /* Linux wireless extension support */
266 #if defined(WL_WIRELESS_EXT)
267 #include <wl_iw.h>
268 extern wl_iw_extra_params_t  g_wl_iw_params;
269 #endif /* defined(WL_WIRELESS_EXT) */
270
271 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
272 #include <linux/earlysuspend.h>
273 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */
274
275 extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
276
277 #ifdef PKT_FILTER_SUPPORT
278 extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
279 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
280 extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id);
281 #endif
282
283
284 #ifdef READ_MACADDR
285 extern int dhd_read_macaddr(struct dhd_info *dhd);
286 #else
287 static inline int dhd_read_macaddr(struct dhd_info *dhd) { return 0; }
288 #endif
289 #ifdef WRITE_MACADDR
290 extern int dhd_write_macaddr(struct ether_addr *mac);
291 #else
292 static inline int dhd_write_macaddr(struct ether_addr *mac) { return 0; }
293 #endif
294
295
296
297 static int dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused);
298 static struct notifier_block dhd_reboot_notifier = {
299                 .notifier_call = dhd_reboot_callback,
300                 .priority = 1,
301 };
302
303
304 typedef struct dhd_if_event {
305         struct list_head        list;
306         wl_event_data_if_t      event;
307         char                    name[IFNAMSIZ+1];
308         uint8                   mac[ETHER_ADDR_LEN];
309 } dhd_if_event_t;
310
311 /* Interface control information */
312 typedef struct dhd_if {
313         struct dhd_info *info;                  /* back pointer to dhd_info */
314         /* OS/stack specifics */
315         struct net_device *net;
316         int                             idx;                    /* iface idx in dongle */
317         uint                    subunit;                /* subunit */
318         uint8                   mac_addr[ETHER_ADDR_LEN];       /* assigned MAC address */
319         bool                    set_macaddress;
320         bool                    set_multicast;
321         uint8                   bssidx;                 /* bsscfg index for the interface */
322         bool                    attached;               /* Delayed attachment when unset */
323         bool                    txflowcontrol;  /* Per interface flow control indicator */
324         char                    name[IFNAMSIZ+1]; /* linux interface name */
325         struct net_device_stats stats;
326 #ifdef DHD_WMF
327         dhd_wmf_t               wmf;            /* per bsscfg wmf setting */
328 #endif /* DHD_WMF */
329 #ifdef PCIE_FULL_DONGLE
330         struct list_head sta_list;              /* sll of associated stations */
331 #if !defined(BCM_GMAC3)
332         spinlock_t      sta_list_lock;          /* lock for manipulating sll */
333 #endif /* ! BCM_GMAC3 */
334 #endif /* PCIE_FULL_DONGLE */
335         uint32  ap_isolate;                     /* ap-isolation settings */
336 } dhd_if_t;
337
338 #ifdef WLMEDIA_HTSF
339 typedef struct {
340         uint32 low;
341         uint32 high;
342 } tsf_t;
343
344 typedef struct {
345         uint32 last_cycle;
346         uint32 last_sec;
347         uint32 last_tsf;
348         uint32 coef;     /* scaling factor */
349         uint32 coefdec1; /* first decimal  */
350         uint32 coefdec2; /* second decimal */
351 } htsf_t;
352
353 typedef struct {
354         uint32 t1;
355         uint32 t2;
356         uint32 t3;
357         uint32 t4;
358 } tstamp_t;
359
360 static tstamp_t ts[TSMAX];
361 static tstamp_t maxdelayts;
362 static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0;
363
364 #endif  /* WLMEDIA_HTSF */
365
366 struct ipv6_work_info_t {
367         uint8                   if_idx;
368         char                    ipv6_addr[16];
369         unsigned long           event;
370 };
371
372 /* When Perimeter locks are deployed, any blocking calls must be preceeded
373  * with a PERIM UNLOCK and followed by a PERIM LOCK.
374  * Examples of blocking calls are: schedule_timeout(), down_interruptible(),
375  * wait_event_timeout().
376  */
377
378 /* Local private structure (extension of pub) */
379 typedef struct dhd_info {
380 #if defined(WL_WIRELESS_EXT)
381         wl_iw_t         iw;             /* wireless extensions state (must be first) */
382 #endif /* defined(WL_WIRELESS_EXT) */
383         dhd_pub_t pub;
384         dhd_if_t *iflist[DHD_MAX_IFS]; /* for supporting multiple interfaces */
385
386         void *adapter;                  /* adapter information, interrupt, fw path etc. */
387         char fw_path[PATH_MAX];         /* path to firmware image */
388         char nv_path[PATH_MAX];         /* path to nvram vars file */
389
390         struct semaphore proto_sem;
391 #ifdef PROP_TXSTATUS
392         spinlock_t      wlfc_spinlock;
393
394 #endif /* PROP_TXSTATUS */
395 #ifdef WLMEDIA_HTSF
396         htsf_t  htsf;
397 #endif
398         wait_queue_head_t ioctl_resp_wait;
399         uint32  default_wd_interval;
400
401         struct timer_list timer;
402         bool wd_timer_valid;
403         struct tasklet_struct tasklet;
404         spinlock_t      sdlock;
405         spinlock_t      txqlock;
406         spinlock_t      dhd_lock;
407
408         struct semaphore sdsem;
409         tsk_ctl_t       thr_dpc_ctl;
410         tsk_ctl_t       thr_wdt_ctl;
411
412         tsk_ctl_t       thr_rxf_ctl;
413         spinlock_t      rxf_lock;
414         bool            rxthread_enabled;
415
416         /* Wakelocks */
417 #if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
418         struct wake_lock wl_wifi;   /* Wifi wakelock */
419         struct wake_lock wl_rxwake; /* Wifi rx wakelock */
420         struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */
421         struct wake_lock wl_wdwake; /* Wifi wd wakelock */
422 #endif
423
424 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
425         /* net_device interface lock, prevent race conditions among net_dev interface
426          * calls and wifi_on or wifi_off
427          */
428         struct mutex dhd_net_if_mutex;
429         struct mutex dhd_suspend_mutex;
430 #endif
431         spinlock_t wakelock_spinlock;
432         uint32 wakelock_counter;
433         int wakelock_wd_counter;
434         int wakelock_rx_timeout_enable;
435         int wakelock_ctrl_timeout_enable;
436         bool waive_wakelock;
437         uint32 wakelock_before_waive;
438
439         /* Thread to issue ioctl for multicast */
440         wait_queue_head_t ctrl_wait;
441         atomic_t pend_8021x_cnt;
442         dhd_attach_states_t dhd_state;
443 #ifdef SHOW_LOGTRACE
444         dhd_event_log_t event_data;
445 #endif /* SHOW_LOGTRACE */
446
447 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
448         struct early_suspend early_suspend;
449 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
450
451 #ifdef ARP_OFFLOAD_SUPPORT
452         u32 pend_ipaddr;
453 #endif /* ARP_OFFLOAD_SUPPORT */
454 #ifdef BCM_FD_AGGR
455         void *rpc_th;
456         void *rpc_osh;
457         struct timer_list rpcth_timer;
458         bool rpcth_timer_active;
459         bool fdaggr;
460 #endif
461 #ifdef DHDTCPACK_SUPPRESS
462         spinlock_t      tcpack_lock;
463 #endif /* DHDTCPACK_SUPPRESS */
464         void                    *dhd_deferred_wq;
465 #ifdef DEBUG_CPU_FREQ
466         struct notifier_block freq_trans;
467         int __percpu *new_freq;
468 #endif
469         unsigned int unit;
470         struct notifier_block pm_notifier;
471 } dhd_info_t;
472
473 #define DHDIF_FWDER(dhdif)      FALSE
474
475 /* Flag to indicate if we should download firmware on driver load */
476 uint dhd_download_fw_on_driverload = TRUE;
477
478 /* Definitions to provide path to the firmware and nvram
479  * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt"
480  */
481 char firmware_path[MOD_PARAM_PATHLEN];
482 char nvram_path[MOD_PARAM_PATHLEN];
483
484 /* backup buffer for firmware and nvram path */
485 char fw_bak_path[MOD_PARAM_PATHLEN];
486 char nv_bak_path[MOD_PARAM_PATHLEN];
487
488 /* information string to keep firmware, chio, cheip version info visiable from log */
489 char info_string[MOD_PARAM_INFOLEN];
490 module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444);
491 int op_mode = 0;
492 int disable_proptx = 0;
493 module_param(op_mode, int, 0644);
494 extern int wl_control_wl_start(struct net_device *dev);
495 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC)
496 struct semaphore dhd_registration_sem;
497 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
498
499 /* deferred handlers */
500 static void dhd_ifadd_event_handler(void *handle, void *event_info, u8 event);
501 static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event);
502 static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event);
503 static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event);
504 #ifdef CONFIG_IPV6
505 static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event);
506 #endif
507
508 #ifdef WL_CFG80211
509 extern void dhd_netdev_free(struct net_device *ndev);
510 #endif /* WL_CFG80211 */
511
512 /* Error bits */
513 module_param(dhd_msg_level, int, 0);
514
515 #ifdef ARP_OFFLOAD_SUPPORT
516 /* ARP offload enable */
517 uint dhd_arp_enable = TRUE;
518 module_param(dhd_arp_enable, uint, 0);
519
520 /* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */
521
522 uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY;
523
524 module_param(dhd_arp_mode, uint, 0);
525 #endif /* ARP_OFFLOAD_SUPPORT */
526
527 /* Disable Prop tx */
528 module_param(disable_proptx, int, 0644);
529 /* load firmware and/or nvram values from the filesystem */
530 module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660);
531 module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660);
532
533 /* Watchdog interval */
534
535 /* extend watchdog expiration to 2 seconds when DPC is running */
536 #define WATCHDOG_EXTEND_INTERVAL (2000)
537
538 uint dhd_watchdog_ms = CUSTOM_DHD_WATCHDOG_MS;
539 module_param(dhd_watchdog_ms, uint, 0);
540
541 #if defined(DHD_DEBUG)
542 /* Console poll interval */
543 uint dhd_console_ms = 0;
544 module_param(dhd_console_ms, uint, 0644);
545 #endif /* defined(DHD_DEBUG) */
546
547
548 uint dhd_slpauto = TRUE;
549 module_param(dhd_slpauto, uint, 0);
550
551 #ifdef PKT_FILTER_SUPPORT
552 /* Global Pkt filter enable control */
553 uint dhd_pkt_filter_enable = TRUE;
554 module_param(dhd_pkt_filter_enable, uint, 0);
555 #endif
556
557 /* Pkt filter init setup */
558 uint dhd_pkt_filter_init = 0;
559 module_param(dhd_pkt_filter_init, uint, 0);
560
561 /* Pkt filter mode control */
562 uint dhd_master_mode = TRUE;
563 module_param(dhd_master_mode, uint, 0);
564
565 int dhd_watchdog_prio = 0;
566 module_param(dhd_watchdog_prio, int, 0);
567
568 /* DPC thread priority */
569 int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING;
570 module_param(dhd_dpc_prio, int, 0);
571
572 /* RX frame thread priority */
573 int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING;
574 module_param(dhd_rxf_prio, int, 0);
575
576 #if !defined(BCMDHDUSB)
577 extern int dhd_dongle_ramsize;
578 module_param(dhd_dongle_ramsize, int, 0);
579 #endif /* BCMDHDUSB */
580
581 /* Keep track of number of instances */
582 static int dhd_found = 0;
583 static int instance_base = 0; /* Starting instance number */
584 module_param(instance_base, int, 0644);
585
586
587 /* DHD Perimiter lock only used in router with bypass forwarding. */
588 #define DHD_PERIM_RADIO_INIT()              do { /* noop */ } while (0)
589 #define DHD_PERIM_LOCK_TRY(unit, flag)      do { /* noop */ } while (0)
590 #define DHD_PERIM_UNLOCK_TRY(unit, flag)    do { /* noop */ } while (0)
591 #define DHD_PERIM_LOCK_ALL()                do { /* noop */ } while (0)
592 #define DHD_PERIM_UNLOCK_ALL()              do { /* noop */ } while (0)
593
594 #ifdef PCIE_FULL_DONGLE
595 #if defined(BCM_GMAC3)
596 #define DHD_IF_STA_LIST_LOCK_INIT(ifp)      do { /* noop */ } while (0)
597 #define DHD_IF_STA_LIST_LOCK(ifp, flags)    ({ BCM_REFERENCE(flags); })
598 #define DHD_IF_STA_LIST_UNLOCK(ifp, flags)  ({ BCM_REFERENCE(flags); })
599 #else /* ! BCM_GMAC3 */
600 #define DHD_IF_STA_LIST_LOCK_INIT(ifp) spin_lock_init(&(ifp)->sta_list_lock)
601 #define DHD_IF_STA_LIST_LOCK(ifp, flags) \
602         spin_lock_irqsave(&(ifp)->sta_list_lock, (flags))
603 #define DHD_IF_STA_LIST_UNLOCK(ifp, flags) \
604         spin_unlock_irqrestore(&(ifp)->sta_list_lock, (flags))
605 #endif /* ! BCM_GMAC3 */
606 #endif /* PCIE_FULL_DONGLE */
607
608 /* Control fw roaming */
609 uint dhd_roam_disable = 0;
610
611 /* Control radio state */
612 uint dhd_radio_up = 1;
613
614 /* Network inteface name */
615 char iface_name[IFNAMSIZ] = {'\0'};
616 module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
617
618 /* The following are specific to the SDIO dongle */
619
620 /* IOCTL response timeout */
621 int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT;
622
623 /* Idle timeout for backplane clock */
624 int dhd_idletime = DHD_IDLETIME_TICKS;
625 module_param(dhd_idletime, int, 0);
626
627 /* Use polling */
628 uint dhd_poll = FALSE;
629 module_param(dhd_poll, uint, 0);
630
631 /* Use interrupts */
632 uint dhd_intr = TRUE;
633 module_param(dhd_intr, uint, 0);
634
635 /* SDIO Drive Strength (in milliamps) */
636 uint dhd_sdiod_drive_strength = 6;
637 module_param(dhd_sdiod_drive_strength, uint, 0);
638
639 #ifdef BCMSDIO
640 /* Tx/Rx bounds */
641 extern uint dhd_txbound;
642 extern uint dhd_rxbound;
643 module_param(dhd_txbound, uint, 0);
644 module_param(dhd_rxbound, uint, 0);
645
646 /* Deferred transmits */
647 extern uint dhd_deferred_tx;
648 module_param(dhd_deferred_tx, uint, 0);
649
650 #ifdef BCMDBGFS
651 extern void dhd_dbg_init(dhd_pub_t *dhdp);
652 extern void dhd_dbg_remove(void);
653 #endif /* BCMDBGFS */
654
655 #endif /* BCMSDIO */
656
657
658 #ifdef SDTEST
659 /* Echo packet generator (pkts/s) */
660 uint dhd_pktgen = 0;
661 module_param(dhd_pktgen, uint, 0);
662
663 /* Echo packet len (0 => sawtooth, max 2040) */
664 uint dhd_pktgen_len = 0;
665 module_param(dhd_pktgen_len, uint, 0);
666 #endif /* SDTEST */
667
668
669 extern char dhd_version[];
670
671 int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
672 static void dhd_net_if_lock_local(dhd_info_t *dhd);
673 static void dhd_net_if_unlock_local(dhd_info_t *dhd);
674 static void dhd_suspend_lock(dhd_pub_t *dhdp);
675 static void dhd_suspend_unlock(dhd_pub_t *dhdp);
676
677 #ifdef WLMEDIA_HTSF
678 void htsf_update(dhd_info_t *dhd, void *data);
679 tsf_t prev_tsf, cur_tsf;
680
681 uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx);
682 static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx);
683 static void dhd_dump_latency(void);
684 static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf);
685 static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf);
686 static void dhd_dump_htsfhisto(histo_t *his, char *s);
687 #endif /* WLMEDIA_HTSF */
688
689 /* Monitor interface */
690 int dhd_monitor_init(void *dhd_pub);
691 int dhd_monitor_uninit(void);
692
693
694 #if defined(WL_WIRELESS_EXT)
695 struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
696 #endif /* defined(WL_WIRELESS_EXT) */
697
698 static void dhd_dpc(ulong data);
699 /* forward decl */
700 extern int dhd_wait_pend8021x(struct net_device *dev);
701 void dhd_os_wd_timer_extend(void *bus, bool extend);
702
703 #ifdef TOE
704 #ifndef BDC
705 #error TOE requires BDC
706 #endif /* !BDC */
707 static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol);
708 static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol);
709 #endif /* TOE */
710
711 static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
712                              wl_event_msg_t *event_ptr, void **data_ptr);
713 #ifdef DHD_UNICAST_DHCP
714 static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
715 static int dhd_get_pkt_ip_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr,
716         int *len_ptr, uint8 *prot_ptr);
717 static int dhd_get_pkt_ether_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr,
718         int *len_ptr, uint16 *et_ptr, bool *snap_ptr);
719
720 static int dhd_convert_dhcp_broadcast_ack_to_unicast(dhd_pub_t *pub, void *pktbuf, int ifidx);
721 #endif /* DHD_UNICAST_DHCP */
722 #ifdef DHD_L2_FILTER
723 static int dhd_l2_filter_block_ping(dhd_pub_t *pub, void *pktbuf, int ifidx);
724 #endif
725 #if defined(CONFIG_PM_SLEEP)
726 static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored)
727 {
728         int ret = NOTIFY_DONE;
729         bool suspend = FALSE;
730         dhd_info_t *dhdinfo = (dhd_info_t*)container_of(nfb, struct dhd_info, pm_notifier);
731
732         BCM_REFERENCE(dhdinfo);
733         switch (action) {
734         case PM_HIBERNATION_PREPARE:
735         case PM_SUSPEND_PREPARE:
736                 suspend = TRUE;
737                 break;
738         case PM_POST_HIBERNATION:
739         case PM_POST_SUSPEND:
740                 suspend = FALSE;
741                 break;
742         }
743
744         /* FIXME: dhd_wlfc_suspend acquires wd wakelock and calling
745            in this function is breaking LP0. So moving this function
746            call to dhd_set_suspend. Need to enable it after fixing
747            wd wakelock issue. */
748 #if 0
749 #if defined(SUPPORT_P2P_GO_PS)
750 #ifdef PROP_TXSTATUS
751         if (suspend) {
752                 DHD_OS_WAKE_LOCK_WAIVE(&dhdinfo->pub);
753                 dhd_wlfc_suspend(&dhdinfo->pub);
754                 DHD_OS_WAKE_LOCK_RESTORE(&dhdinfo->pub);
755         } else
756                 dhd_wlfc_resume(&dhdinfo->pub);
757 #endif
758 #endif /* defined(SUPPORT_P2P_GO_PS) */
759 #endif
760
761 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \
762         KERNEL_VERSION(2, 6, 39))
763         dhd_mmc_suspend = suspend;
764         smp_mb();
765 #endif
766
767         return ret;
768 }
769
770 static struct notifier_block dhd_pm_notifier = {
771         .notifier_call = dhd_pm_callback,
772         .priority = 10
773 };
774 /* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
775  * created in kernel notifier link list (with 'next' pointing to itself)
776  */
777 static bool dhd_pm_notifier_registered = FALSE;
778
779 extern int register_pm_notifier(struct notifier_block *nb);
780 extern int unregister_pm_notifier(struct notifier_block *nb);
781 #endif /* CONFIG_PM_SLEEP */
782
783 /* Request scheduling of the bus rx frame */
784 static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb);
785 static void dhd_os_rxflock(dhd_pub_t *pub);
786 static void dhd_os_rxfunlock(dhd_pub_t *pub);
787
788 /** priv_link is the link between netdev and the dhdif and dhd_info structs. */
789 typedef struct dhd_dev_priv {
790         dhd_info_t * dhd; /* cached pointer to dhd_info in netdevice priv */
791         dhd_if_t   * ifp; /* cached pointer to dhd_if in netdevice priv */
792         int          ifidx; /* interface index */
793 } dhd_dev_priv_t;
794
795 #define DHD_DEV_PRIV_SIZE       (sizeof(dhd_dev_priv_t))
796 #define DHD_DEV_PRIV(dev)       ((dhd_dev_priv_t *)DEV_PRIV(dev))
797 #define DHD_DEV_INFO(dev)       (((dhd_dev_priv_t *)DEV_PRIV(dev))->dhd)
798 #define DHD_DEV_IFP(dev)        (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifp)
799 #define DHD_DEV_IFIDX(dev)      (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifidx)
800
801 /** Clear the dhd net_device's private structure. */
802 static inline void
803 dhd_dev_priv_clear(struct net_device * dev)
804 {
805         dhd_dev_priv_t * dev_priv;
806         ASSERT(dev != (struct net_device *)NULL);
807         dev_priv = DHD_DEV_PRIV(dev);
808         dev_priv->dhd = (dhd_info_t *)NULL;
809         dev_priv->ifp = (dhd_if_t *)NULL;
810         dev_priv->ifidx = DHD_BAD_IF;
811 }
812
813 /** Setup the dhd net_device's private structure. */
814 static inline void
815 dhd_dev_priv_save(struct net_device * dev, dhd_info_t * dhd, dhd_if_t * ifp,
816                   int ifidx)
817 {
818         dhd_dev_priv_t * dev_priv;
819         ASSERT(dev != (struct net_device *)NULL);
820         dev_priv = DHD_DEV_PRIV(dev);
821         dev_priv->dhd = dhd;
822         dev_priv->ifp = ifp;
823         dev_priv->ifidx = ifidx;
824 }
825
826 #ifdef PCIE_FULL_DONGLE
827
828 /** Dummy objects are defined with state representing bad|down.
829  * Performance gains from reducing branch conditionals, instruction parallelism,
830  * dual issue, reducing load shadows, avail of larger pipelines.
831  * Use DHD_XXX_NULL instead of (dhd_xxx_t *)NULL, whenever an object pointer
832  * is accessed via the dhd_sta_t.
833  */
834
835 /* Dummy dhd_info object */
836 dhd_info_t dhd_info_null = {
837 #if defined(BCM_GMAC3)
838         .fwdh = FWDER_NULL,
839 #endif
840         .pub = {
841                  .info = &dhd_info_null,
842 #ifdef DHDTCPACK_SUPPRESS
843                  .tcpack_sup_mode = TCPACK_SUP_REPLACE,
844 #endif /* DHDTCPACK_SUPPRESS */
845                  .up = FALSE, .busstate = DHD_BUS_DOWN
846         }
847 };
848 #define DHD_INFO_NULL (&dhd_info_null)
849 #define DHD_PUB_NULL  (&dhd_info_null.pub)
850
851 /* Dummy netdevice object */
852 struct net_device dhd_net_dev_null = {
853         .reg_state = NETREG_UNREGISTERED
854 };
855 #define DHD_NET_DEV_NULL (&dhd_net_dev_null)
856
857 /* Dummy dhd_if object */
858 dhd_if_t dhd_if_null = {
859 #if defined(BCM_GMAC3)
860         .fwdh = FWDER_NULL,
861 #endif
862 #ifdef WMF
863         .wmf = { .wmf_enable = TRUE },
864 #endif
865         .info = DHD_INFO_NULL,
866         .net = DHD_NET_DEV_NULL,
867         .idx = DHD_BAD_IF
868 };
869 #define DHD_IF_NULL  (&dhd_if_null)
870
871 #define DHD_STA_NULL ((dhd_sta_t *)NULL)
872
873 /** Interface STA list management. */
874
875 /** Fetch the dhd_if object, given the interface index in the dhd. */
876 static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx);
877
878 /** Alloc/Free a dhd_sta object from the dhd instances' sta_pool. */
879 static void dhd_sta_free(dhd_pub_t *pub, dhd_sta_t *sta);
880 static dhd_sta_t * dhd_sta_alloc(dhd_pub_t * dhdp);
881
882 /* Delete a dhd_sta or flush all dhd_sta in an interface's sta_list. */
883 static void dhd_if_del_sta_list(dhd_if_t * ifp);
884 static void     dhd_if_flush_sta(dhd_if_t * ifp);
885
886 /* Construct/Destruct a sta pool. */
887 static int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta);
888 static void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta);
889
890
891 /* Return interface pointer */
892 static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx)
893 {
894         ASSERT(ifidx < DHD_MAX_IFS);
895         return dhdp->info->iflist[ifidx];
896 }
897
898 /** Reset a dhd_sta object and free into the dhd pool. */
899 static void
900 dhd_sta_free(dhd_pub_t * dhdp, dhd_sta_t * sta)
901 {
902         int prio;
903
904         ASSERT((sta != DHD_STA_NULL) && (sta->idx != ID16_INVALID));
905
906         ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL));
907         id16_map_free(dhdp->staid_allocator, sta->idx);
908         for (prio = 0; prio < (int)NUMPRIO; prio++)
909                 sta->flowid[prio] = FLOWID_INVALID;
910         sta->ifp = DHD_IF_NULL; /* dummy dhd_if object */
911         sta->ifidx = DHD_BAD_IF;
912         bzero(sta->ea.octet, ETHER_ADDR_LEN);
913         INIT_LIST_HEAD(&sta->list);
914         sta->idx = ID16_INVALID; /* implying free */
915 }
916
917 /** Allocate a dhd_sta object from the dhd pool. */
918 static dhd_sta_t *
919 dhd_sta_alloc(dhd_pub_t * dhdp)
920 {
921         uint16 idx;
922         dhd_sta_t * sta;
923         dhd_sta_pool_t * sta_pool;
924
925         ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL));
926
927         idx = id16_map_alloc(dhdp->staid_allocator);
928         if (idx == ID16_INVALID) {
929                 DHD_ERROR(("%s: cannot get free staid\n", __FUNCTION__));
930                 return DHD_STA_NULL;
931         }
932
933         sta_pool = (dhd_sta_pool_t *)(dhdp->sta_pool);
934         sta = &sta_pool[idx];
935
936         ASSERT((sta->idx == ID16_INVALID) &&
937                (sta->ifp == DHD_IF_NULL) && (sta->ifidx == DHD_BAD_IF));
938         sta->idx = idx; /* implying allocated */
939
940         return sta;
941 }
942
943 /** Delete all STAs in an interface's STA list. */
944 static void
945 dhd_if_del_sta_list(dhd_if_t *ifp)
946 {
947         dhd_sta_t *sta, *next;
948         unsigned long flags;
949
950         DHD_IF_STA_LIST_LOCK(ifp, flags);
951
952         list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
953 #if defined(BCM_GMAC3)
954                 if (ifp->fwdh) {
955                         /* Remove sta from WOFA forwarder. */
956                         fwder_deassoc(ifp->fwdh, (uint16 *)(sta->ea.octet), (wofa_t)sta);
957                 }
958 #endif /* BCM_GMAC3 */
959                 list_del(&sta->list);
960                 dhd_sta_free(&ifp->info->pub, sta);
961         }
962
963         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
964
965         return;
966 }
967
968 /** Router/GMAC3: Flush all station entries in the forwarder's WOFA database. */
969 static void
970 dhd_if_flush_sta(dhd_if_t * ifp)
971 {
972 #if defined(BCM_GMAC3)
973
974         if (ifp && (ifp->fwdh != FWDER_NULL)) {
975                 dhd_sta_t *sta, *next;
976                 unsigned long flags;
977
978                 DHD_IF_STA_LIST_LOCK(ifp, flags);
979
980                 list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
981                         /* Remove any sta entry from WOFA forwarder. */
982                         fwder_flush(ifp->fwdh, (wofa_t)sta);
983                 }
984
985                 DHD_IF_STA_LIST_UNLOCK(ifp, flags);
986         }
987 #endif /* BCM_GMAC3 */
988 }
989
990 /** Construct a pool of dhd_sta_t objects to be used by interfaces. */
991 static int
992 dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta)
993 {
994         int idx, sta_pool_memsz;
995         dhd_sta_t * sta;
996         dhd_sta_pool_t * sta_pool;
997         void * staid_allocator;
998
999         ASSERT(dhdp != (dhd_pub_t *)NULL);
1000         ASSERT((dhdp->staid_allocator == NULL) && (dhdp->sta_pool == NULL));
1001
1002         /* dhd_sta objects per radio are managed in a table. id#0 reserved. */
1003         staid_allocator = id16_map_init(dhdp->osh, max_sta, 1);
1004         if (staid_allocator == NULL) {
1005                 DHD_ERROR(("%s: sta id allocator init failure\n", __FUNCTION__));
1006                 return BCME_ERROR;
1007         }
1008
1009         /* Pre allocate a pool of dhd_sta objects (one extra). */
1010         sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); /* skip idx 0 */
1011         sta_pool = (dhd_sta_pool_t *)MALLOC(dhdp->osh, sta_pool_memsz);
1012         if (sta_pool == NULL) {
1013                 DHD_ERROR(("%s: sta table alloc failure\n", __FUNCTION__));
1014                 id16_map_fini(dhdp->osh, staid_allocator);
1015                 return BCME_ERROR;
1016         }
1017
1018         dhdp->sta_pool = sta_pool;
1019         dhdp->staid_allocator = staid_allocator;
1020
1021         /* Initialize all sta(s) for the pre-allocated free pool. */
1022         bzero((uchar *)sta_pool, sta_pool_memsz);
1023         for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */
1024                 sta = &sta_pool[idx];
1025                 sta->idx = id16_map_alloc(staid_allocator);
1026                 ASSERT(sta->idx <= max_sta);
1027         }
1028         /* Now place them into the pre-allocated free pool. */
1029         for (idx = 1; idx <= max_sta; idx++) {
1030                 sta = &sta_pool[idx];
1031                 dhd_sta_free(dhdp, sta);
1032         }
1033
1034         return BCME_OK;
1035 }
1036
1037 /** Destruct the pool of dhd_sta_t objects.
1038  * Caller must ensure that no STA objects are currently associated with an if.
1039  */
1040 static void
1041 dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta)
1042 {
1043         dhd_sta_pool_t * sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool;
1044
1045         if (sta_pool) {
1046                 int idx;
1047                 int sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t));
1048                 for (idx = 1; idx <= max_sta; idx++) {
1049                         ASSERT(sta_pool[idx].ifp == DHD_IF_NULL);
1050                         ASSERT(sta_pool[idx].idx == ID16_INVALID);
1051                 }
1052                 MFREE(dhdp->osh, dhdp->sta_pool, sta_pool_memsz);
1053                 dhdp->sta_pool = NULL;
1054         }
1055
1056         id16_map_fini(dhdp->osh, dhdp->staid_allocator);
1057         dhdp->staid_allocator = NULL;
1058 }
1059
1060 /** Find STA with MAC address ea in an interface's STA list. */
1061 dhd_sta_t *
1062 dhd_find_sta(void *pub, int ifidx, void *ea)
1063 {
1064         dhd_sta_t *sta;
1065         dhd_if_t *ifp;
1066         unsigned long flags;
1067
1068         ASSERT(ea != NULL);
1069         ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
1070
1071         DHD_IF_STA_LIST_LOCK(ifp, flags);
1072
1073         list_for_each_entry(sta, &ifp->sta_list, list) {
1074                 if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) {
1075                         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1076                         return sta;
1077                 }
1078         }
1079
1080         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1081
1082         return DHD_STA_NULL;
1083 }
1084
1085 /** Add STA into the interface's STA list. */
1086 dhd_sta_t *
1087 dhd_add_sta(void *pub, int ifidx, void *ea)
1088 {
1089         dhd_sta_t *sta;
1090         dhd_if_t *ifp;
1091         unsigned long flags;
1092
1093         ASSERT(ea != NULL);
1094         ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
1095
1096         sta = dhd_sta_alloc((dhd_pub_t *)pub);
1097         if (sta == DHD_STA_NULL) {
1098                 DHD_ERROR(("%s: Alloc failed\n", __FUNCTION__));
1099                 return DHD_STA_NULL;
1100         }
1101
1102         memcpy(sta->ea.octet, ea, ETHER_ADDR_LEN);
1103
1104         /* link the sta and the dhd interface */
1105         sta->ifp = ifp;
1106         sta->ifidx = ifidx;
1107         INIT_LIST_HEAD(&sta->list);
1108
1109         DHD_IF_STA_LIST_LOCK(ifp, flags);
1110
1111         list_add_tail(&sta->list, &ifp->sta_list);
1112
1113 #if defined(BCM_GMAC3)
1114         if (ifp->fwdh) {
1115                 ASSERT(ISALIGNED(ea, 2));
1116                 /* Add sta to WOFA forwarder. */
1117                 fwder_reassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta);
1118         }
1119 #endif /* BCM_GMAC3 */
1120
1121         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1122
1123         return sta;
1124 }
1125
1126 /** Delete STA from the interface's STA list. */
1127 void
1128 dhd_del_sta(void *pub, int ifidx, void *ea)
1129 {
1130         dhd_sta_t *sta, *next;
1131         dhd_if_t *ifp;
1132         unsigned long flags;
1133
1134         ASSERT(ea != NULL);
1135         ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
1136
1137         DHD_IF_STA_LIST_LOCK(ifp, flags);
1138
1139         list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
1140                 if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) {
1141 #if defined(BCM_GMAC3)
1142                         if (ifp->fwdh) { /* Found a sta, remove from WOFA forwarder. */
1143                                 ASSERT(ISALIGNED(ea, 2));
1144                                 fwder_deassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta);
1145                         }
1146 #endif /* BCM_GMAC3 */
1147                         list_del(&sta->list);
1148                         dhd_sta_free(&ifp->info->pub, sta);
1149                 }
1150         }
1151
1152         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1153
1154         return;
1155 }
1156
1157 /** Add STA if it doesn't exist. Not reentrant. */
1158 dhd_sta_t*
1159 dhd_findadd_sta(void *pub, int ifidx, void *ea)
1160 {
1161         dhd_sta_t *sta;
1162
1163         sta = dhd_find_sta(pub, ifidx, ea);
1164
1165         if (!sta) {
1166                 /* Add entry */
1167                 sta = dhd_add_sta(pub, ifidx, ea);
1168         }
1169
1170         return sta;
1171 }
1172 #else
1173 static inline void dhd_if_flush_sta(dhd_if_t * ifp) { }
1174 static inline void dhd_if_del_sta_list(dhd_if_t *ifp) {}
1175 static inline int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta) { return BCME_OK; }
1176 static inline void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta) {}
1177 dhd_sta_t *dhd_findadd_sta(void *pub, int ifidx, void *ea) { return NULL; }
1178 void dhd_del_sta(void *pub, int ifidx, void *ea) {}
1179 #endif /* PCIE_FULL_DONGLE */
1180
1181
1182 /* Returns dhd iflist index correspondig the the bssidx provided by apps */
1183 int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx)
1184 {
1185         dhd_if_t *ifp;
1186         dhd_info_t *dhd = dhdp->info;
1187         int i;
1188
1189         ASSERT(bssidx < DHD_MAX_IFS);
1190         ASSERT(dhdp);
1191
1192         for (i = 0; i < DHD_MAX_IFS; i++) {
1193                 ifp = dhd->iflist[i];
1194                 if (ifp && (ifp->bssidx == bssidx)) {
1195                         DHD_TRACE(("Index manipulated for %s from %d to %d\n",
1196                                 ifp->name, bssidx, i));
1197                         break;
1198                 }
1199         }
1200         return i;
1201 }
1202
1203 static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb)
1204 {
1205         uint32 store_idx;
1206         uint32 sent_idx;
1207
1208         if (!skb) {
1209                 DHD_ERROR(("dhd_rxf_enqueue: NULL skb!!!\n"));
1210                 return BCME_ERROR;
1211         }
1212
1213         dhd_os_rxflock(dhdp);
1214         store_idx = dhdp->store_idx;
1215         sent_idx = dhdp->sent_idx;
1216         if (dhdp->skbbuf[store_idx] != NULL) {
1217                 /* Make sure the previous packets are processed */
1218                 dhd_os_rxfunlock(dhdp);
1219 #ifdef RXF_DEQUEUE_ON_BUSY
1220                 DHD_TRACE(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n",
1221                         skb, store_idx, sent_idx));
1222                 return BCME_BUSY;
1223 #else /* RXF_DEQUEUE_ON_BUSY */
1224                 DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n",
1225                         skb, store_idx, sent_idx));
1226                 /* removed msleep here, should use wait_event_timeout if we
1227                  * want to give rx frame thread a chance to run
1228                  */
1229 #if defined(WAIT_DEQUEUE)
1230                 OSL_SLEEP(1);
1231 #endif
1232                 return BCME_ERROR;
1233 #endif /* RXF_DEQUEUE_ON_BUSY */
1234         }
1235         DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n",
1236                 skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1)));
1237         dhdp->skbbuf[store_idx] = skb;
1238         dhdp->store_idx = (store_idx + 1) & (MAXSKBPEND - 1);
1239         dhd_os_rxfunlock(dhdp);
1240
1241         return BCME_OK;
1242 }
1243
1244 static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp)
1245 {
1246         uint32 store_idx;
1247         uint32 sent_idx;
1248         void *skb;
1249
1250         dhd_os_rxflock(dhdp);
1251
1252         store_idx = dhdp->store_idx;
1253         sent_idx = dhdp->sent_idx;
1254         skb = dhdp->skbbuf[sent_idx];
1255
1256         if (skb == NULL) {
1257                 dhd_os_rxfunlock(dhdp);
1258                 DHD_ERROR(("dhd_rxf_dequeue: Dequeued packet is NULL, store idx %d sent idx %d\n",
1259                         store_idx, sent_idx));
1260                 return NULL;
1261         }
1262
1263         dhdp->skbbuf[sent_idx] = NULL;
1264         dhdp->sent_idx = (sent_idx + 1) & (MAXSKBPEND - 1);
1265
1266         DHD_TRACE(("dhd_rxf_dequeue: netif_rx_ni(%p), sent idx %d\n",
1267                 skb, sent_idx));
1268
1269         dhd_os_rxfunlock(dhdp);
1270
1271         return skb;
1272 }
1273
1274 int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost)
1275 {
1276         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
1277
1278         if (prepost) { /* pre process */
1279                 dhd_read_macaddr(dhd);
1280         } else { /* post process */
1281                 dhd_write_macaddr(&dhd->pub.mac);
1282         }
1283
1284         return 0;
1285 }
1286
1287 #if defined(PKT_FILTER_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER)
1288 static bool
1289 _turn_on_arp_filter(dhd_pub_t *dhd, int op_mode)
1290 {
1291         bool _apply = FALSE;
1292         /* In case of IBSS mode, apply arp pkt filter */
1293         if (op_mode & DHD_FLAG_IBSS_MODE) {
1294                 _apply = TRUE;
1295                 goto exit;
1296         }
1297         /* In case of P2P GO or GC, apply pkt filter to pass arp pkt to host */
1298         if ((dhd->arp_version == 1) &&
1299                 (op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) {
1300                 _apply = TRUE;
1301                 goto exit;
1302         }
1303
1304 exit:
1305         return _apply;
1306 }
1307 #endif /* PKT_FILTER_SUPPORT && !GAN_LITE_NAT_KEEPALIVE_FILTER */
1308
1309 void dhd_set_packet_filter(dhd_pub_t *dhd)
1310 {
1311 #ifdef PKT_FILTER_SUPPORT
1312         int i;
1313
1314         DHD_TRACE(("%s: enter\n", __FUNCTION__));
1315         if (dhd_pkt_filter_enable) {
1316                 for (i = 0; i < dhd->pktfilter_count; i++) {
1317                         dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
1318                 }
1319         }
1320 #endif /* PKT_FILTER_SUPPORT */
1321 }
1322
1323 void dhd_enable_packet_filter(int value, dhd_pub_t *dhd)
1324 {
1325 #ifdef PKT_FILTER_SUPPORT
1326         int i;
1327
1328         DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value));
1329         /* 1 - Enable packet filter, only allow unicast packet to send up */
1330         /* 0 - Disable packet filter */
1331         if (dhd_pkt_filter_enable && (!value ||
1332             (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress)))
1333             {
1334                 for (i = 0; i < dhd->pktfilter_count; i++) {
1335 #ifndef GAN_LITE_NAT_KEEPALIVE_FILTER
1336                         if (value && (i == DHD_ARP_FILTER_NUM) &&
1337                                 !_turn_on_arp_filter(dhd, dhd->op_mode)) {
1338                                 DHD_TRACE(("Do not turn on ARP white list pkt filter:"
1339                                         "val %d, cnt %d, op_mode 0x%x\n",
1340                                         value, i, dhd->op_mode));
1341                                 continue;
1342                         }
1343 #endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */
1344                         dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
1345                                 value, dhd_master_mode);
1346                 }
1347         }
1348 #endif /* PKT_FILTER_SUPPORT */
1349 }
1350
1351 static int dhd_set_suspend(int value, dhd_pub_t *dhd)
1352 {
1353 #ifndef SUPPORT_PM2_ONLY
1354         int power_mode = PM_MAX;
1355 #endif /* SUPPORT_PM2_ONLY */
1356         /* wl_pkt_filter_enable_t       enable_parm; */
1357         char iovbuf[32];
1358         int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */
1359 #ifndef ENABLE_FW_ROAM_SUSPEND
1360         uint roamvar = 1;
1361 #endif /* ENABLE_FW_ROAM_SUSPEND */
1362         uint nd_ra_filter = 0;
1363         int ret = 0;
1364
1365         if (!dhd)
1366                 return -ENODEV;
1367
1368         DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n",
1369                 __FUNCTION__, value, dhd->in_suspend));
1370
1371         dhd_suspend_lock(dhd);
1372
1373 #ifdef CUSTOM_SET_CPUCORE
1374         DHD_TRACE(("%s set cpucore(suspend%d)\n", __FUNCTION__, value));
1375         /* set specific cpucore */
1376         dhd_set_cpucore(dhd, TRUE);
1377 #endif /* CUSTOM_SET_CPUCORE */
1378         if (dhd->up) {
1379                 if (value && dhd->in_suspend) {
1380 #ifdef PKT_FILTER_SUPPORT
1381                                 dhd->early_suspended = 1;
1382 #endif
1383 #ifdef CONFIG_BCMDHD_CUSTOM_SYSFS_TEGRA
1384                                 tegra_sysfs_suspend();
1385 #endif
1386                                 /* Kernel suspended */
1387                                 DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__));
1388
1389 #ifndef SUPPORT_PM2_ONLY
1390                                 dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
1391                                                  sizeof(power_mode), TRUE, 0);
1392 #endif /* SUPPORT_PM2_ONLY */
1393
1394                                 /* Enable packet filter, only allow unicast packet to send up */
1395                                 dhd_enable_packet_filter(1, dhd);
1396
1397
1398                                 /* If DTIM skip is set up as default, force it to wake
1399                                  * each third DTIM for better power savings.  Note that
1400                                  * one side effect is a chance to miss BC/MC packet.
1401                                  */
1402                                 bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd);
1403                                 bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
1404                                         4, iovbuf, sizeof(iovbuf));
1405                                 if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf),
1406                                         TRUE, 0) < 0)
1407                                         DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__));
1408
1409 #ifndef ENABLE_FW_ROAM_SUSPEND
1410                                 /* Disable firmware roaming during suspend */
1411                                 bcm_mkiovar("roam_off", (char *)&roamvar, 4,
1412                                         iovbuf, sizeof(iovbuf));
1413                                 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1414 #endif /* ENABLE_FW_ROAM_SUSPEND */
1415                                 if (FW_SUPPORTED(dhd, ndoe)) {
1416                                         /* enable IPv6 RA filter in  firmware during suspend */
1417                                         nd_ra_filter = 1;
1418                                         bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4,
1419                                                 iovbuf, sizeof(iovbuf));
1420                                         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
1421                                                 sizeof(iovbuf), TRUE, 0)) < 0)
1422                                                 DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
1423                                                         ret));
1424                                 }
1425 #if defined(SUPPORT_P2P_GO_PS)
1426 #ifdef PROP_TXSTATUS
1427                                 DHD_OS_WAKE_LOCK_WAIVE(dhd);
1428                                 dhd_wlfc_suspend(dhd);
1429                                 DHD_OS_WAKE_LOCK_RESTORE(dhd);
1430 #endif
1431 #endif /* defined(SUPPORT_P2P_GO_PS) */
1432                         } else {
1433 #ifdef PKT_FILTER_SUPPORT
1434                                 dhd->early_suspended = 0;
1435 #endif
1436 #ifdef CONFIG_BCMDHD_CUSTOM_SYSFS_TEGRA
1437                                 tegra_sysfs_resume();
1438 #endif
1439                                 /* Kernel resumed  */
1440                                 DHD_ERROR(("%s: Remove extra suspend setting \n", __FUNCTION__));
1441
1442 #ifndef SUPPORT_PM2_ONLY
1443                                 power_mode = PM_FAST;
1444                                 dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
1445                                                  sizeof(power_mode), TRUE, 0);
1446 #endif /* SUPPORT_PM2_ONLY */
1447 #ifdef PKT_FILTER_SUPPORT
1448                                 /* disable pkt filter */
1449                                 dhd_enable_packet_filter(0, dhd);
1450 #endif /* PKT_FILTER_SUPPORT */
1451
1452                                 /* restore pre-suspend setting for dtim_skip */
1453                                 bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
1454                                         4, iovbuf, sizeof(iovbuf));
1455
1456                                 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1457 #ifndef ENABLE_FW_ROAM_SUSPEND
1458                                 roamvar = dhd_roam_disable;
1459                                 bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf,
1460                                         sizeof(iovbuf));
1461                                 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1462 #endif /* ENABLE_FW_ROAM_SUSPEND */
1463                                 if (FW_SUPPORTED(dhd, ndoe)) {
1464                                         /* disable IPv6 RA filter in  firmware during suspend */
1465                                         nd_ra_filter = 0;
1466                                         bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4,
1467                                                 iovbuf, sizeof(iovbuf));
1468                                         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
1469                                                 sizeof(iovbuf), TRUE, 0)) < 0)
1470                                                 DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
1471                                                         ret));
1472                                 }
1473 #if defined(SUPPORT_P2P_GO_PS)
1474 #ifdef PROP_TXSTATUS
1475                                 dhd_wlfc_resume(dhd);
1476 #endif
1477 #endif /* defined(SUPPORT_P2P_GO_PS) */
1478
1479                         }
1480         }
1481         dhd_suspend_unlock(dhd);
1482
1483         return 0;
1484 }
1485
1486 static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force)
1487 {
1488         dhd_pub_t *dhdp = &dhd->pub;
1489         int ret = 0;
1490
1491         DHD_OS_WAKE_LOCK(dhdp);
1492         DHD_PERIM_LOCK(dhdp);
1493
1494         /* Set flag when early suspend was called */
1495         dhdp->in_suspend = val;
1496         if ((force || !dhdp->suspend_disable_flag) &&
1497                 dhd_support_sta_mode(dhdp))
1498         {
1499                 ret = dhd_set_suspend(val, dhdp);
1500         }
1501
1502         DHD_PERIM_UNLOCK(dhdp);
1503         DHD_OS_WAKE_UNLOCK(dhdp);
1504         return ret;
1505 }
1506
1507 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
1508 static void dhd_early_suspend(struct early_suspend *h)
1509 {
1510         struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
1511         DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__));
1512
1513         if (dhd)
1514                 dhd_suspend_resume_helper(dhd, 1, 0);
1515 }
1516
1517 static void dhd_late_resume(struct early_suspend *h)
1518 {
1519         struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
1520         DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__));
1521
1522         if (dhd)
1523                 dhd_suspend_resume_helper(dhd, 0, 0);
1524 }
1525 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
1526
1527 /*
1528  * Generalized timeout mechanism.  Uses spin sleep with exponential back-off until
1529  * the sleep time reaches one jiffy, then switches over to task delay.  Usage:
1530  *
1531  *      dhd_timeout_start(&tmo, usec);
1532  *      while (!dhd_timeout_expired(&tmo))
1533  *              if (poll_something())
1534  *                      break;
1535  *      if (dhd_timeout_expired(&tmo))
1536  *              fatal();
1537  */
1538
1539 void
1540 dhd_timeout_start(dhd_timeout_t *tmo, uint usec)
1541 {
1542         tmo->limit = usec;
1543         tmo->increment = 0;
1544         tmo->elapsed = 0;
1545         tmo->tick = jiffies_to_usecs(1);
1546 }
1547
1548 int
1549 dhd_timeout_expired(dhd_timeout_t *tmo)
1550 {
1551         /* Does nothing the first call */
1552         if (tmo->increment == 0) {
1553                 tmo->increment = 1;
1554                 return 0;
1555         }
1556
1557         if (tmo->elapsed >= tmo->limit)
1558                 return 1;
1559
1560         /* Add the delay that's about to take place */
1561         tmo->elapsed += tmo->increment;
1562
1563         if ((!CAN_SLEEP()) || tmo->increment < tmo->tick) {
1564                 OSL_DELAY(tmo->increment);
1565                 tmo->increment *= 2;
1566                 if (tmo->increment > tmo->tick)
1567                         tmo->increment = tmo->tick;
1568         } else {
1569                 wait_queue_head_t delay_wait;
1570                 DECLARE_WAITQUEUE(wait, current);
1571                 init_waitqueue_head(&delay_wait);
1572                 add_wait_queue(&delay_wait, &wait);
1573                 set_current_state(TASK_INTERRUPTIBLE);
1574                 (void)schedule_timeout(1);
1575                 remove_wait_queue(&delay_wait, &wait);
1576                 set_current_state(TASK_RUNNING);
1577         }
1578
1579         return 0;
1580 }
1581
1582 int
1583 dhd_net2idx(dhd_info_t *dhd, struct net_device *net)
1584 {
1585         int i = 0;
1586
1587         ASSERT(dhd);
1588         while (i < DHD_MAX_IFS) {
1589                 if (dhd->iflist[i] && dhd->iflist[i]->net && (dhd->iflist[i]->net == net))
1590                         return i;
1591                 i++;
1592         }
1593
1594         return DHD_BAD_IF;
1595 }
1596
1597 struct net_device * dhd_idx2net(void *pub, int ifidx)
1598 {
1599         struct dhd_pub *dhd_pub = (struct dhd_pub *)pub;
1600         struct dhd_info *dhd_info;
1601
1602         if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS)
1603                 return NULL;
1604         dhd_info = dhd_pub->info;
1605         if (dhd_info && dhd_info->iflist[ifidx])
1606                 return dhd_info->iflist[ifidx]->net;
1607         return NULL;
1608 }
1609
1610 int
1611 dhd_ifname2idx(dhd_info_t *dhd, char *name)
1612 {
1613         int i = DHD_MAX_IFS;
1614
1615         ASSERT(dhd);
1616
1617         if (name == NULL || *name == '\0')
1618                 return 0;
1619
1620         while (--i > 0)
1621                 if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ))
1622                                 break;
1623
1624         DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name));
1625
1626         return i;       /* default - the primary interface */
1627 }
1628
1629 int
1630 dhd_ifidx2hostidx(dhd_info_t *dhd, int ifidx)
1631 {
1632         int i = DHD_MAX_IFS;
1633
1634         ASSERT(dhd);
1635
1636         if (ifidx < 0 || ifidx >= DHD_MAX_IFS) {
1637                 DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx));
1638                 return 0;       /* default - the primary interface */
1639         }
1640
1641         while (--i > 0)
1642                 if (dhd->iflist[i] && (dhd->iflist[i]->idx == ifidx))
1643                                 break;
1644
1645         DHD_TRACE(("%s: return hostidx %d for ifidx %d\n", __FUNCTION__, i, ifidx));
1646
1647         return i;       /* default - the primary interface */
1648 }
1649
1650 char *
1651 dhd_ifname(dhd_pub_t *dhdp, int ifidx)
1652 {
1653         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
1654
1655         ASSERT(dhd);
1656
1657         if (ifidx < 0 || ifidx >= DHD_MAX_IFS) {
1658                 DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx));
1659                 return "<if_bad>";
1660         }
1661
1662         if (dhd->iflist[ifidx] == NULL) {
1663                 DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx));
1664                 return "<if_null>";
1665         }
1666
1667         if (dhd->iflist[ifidx]->net)
1668                 return dhd->iflist[ifidx]->net->name;
1669
1670         return "<if_none>";
1671 }
1672
1673 uint8 *
1674 dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx)
1675 {
1676         int i;
1677         dhd_info_t *dhd = (dhd_info_t *)dhdp;
1678
1679         ASSERT(dhd);
1680         for (i = 0; i < DHD_MAX_IFS; i++)
1681         if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx)
1682                 return dhd->iflist[i]->mac_addr;
1683
1684         return NULL;
1685 }
1686
1687
1688 static void
1689 _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
1690 {
1691         struct net_device *dev;
1692 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
1693         struct netdev_hw_addr *ha;
1694 #else
1695         struct dev_mc_list *mclist;
1696 #endif
1697         uint32 allmulti, cnt;
1698
1699         wl_ioctl_t ioc;
1700         char *buf, *bufp;
1701         uint buflen;
1702         int ret;
1703
1704                         ASSERT(dhd && dhd->iflist[ifidx]);
1705                         if (dhd == NULL || dhd->iflist[ifidx] == NULL)
1706                                 return;
1707                         dev = dhd->iflist[ifidx]->net;
1708                         if (!dev)
1709                                 return;
1710 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1711                         netif_addr_lock_bh(dev);
1712 #endif
1713 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
1714                         cnt = netdev_mc_count(dev);
1715 #else
1716                         cnt = dev->mc_count;
1717 #endif /* LINUX_VERSION_CODE */
1718
1719 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1720                         netif_addr_unlock_bh(dev);
1721 #endif
1722
1723                         /* Determine initial value of allmulti flag */
1724         allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE;
1725
1726         /* Send down the multicast list first. */
1727
1728
1729         buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN);
1730         if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) {
1731                 DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n",
1732                            dhd_ifname(&dhd->pub, ifidx), cnt));
1733                 return;
1734         }
1735
1736         strncpy(bufp, "mcast_list", buflen - 1);
1737         bufp[buflen - 1] = '\0';
1738         bufp += strlen("mcast_list") + 1;
1739
1740         cnt = htol32(cnt);
1741         memcpy(bufp, &cnt, sizeof(cnt));
1742         bufp += sizeof(cnt);
1743
1744
1745 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1746                         netif_addr_lock_bh(dev);
1747 #endif
1748 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
1749                         netdev_for_each_mc_addr(ha, dev) {
1750                                 if (!cnt)
1751                                         break;
1752                                 memcpy(bufp, ha->addr, ETHER_ADDR_LEN);
1753                                 bufp += ETHER_ADDR_LEN;
1754                                 cnt--;
1755         }
1756 #else
1757         for (mclist = dev->mc_list; (mclist && (cnt > 0));
1758                 cnt--, mclist = mclist->next) {
1759                                 memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN);
1760                                 bufp += ETHER_ADDR_LEN;
1761                         }
1762 #endif /* LINUX_VERSION_CODE */
1763
1764 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1765                         netif_addr_unlock_bh(dev);
1766 #endif
1767
1768         memset(&ioc, 0, sizeof(ioc));
1769         ioc.cmd = WLC_SET_VAR;
1770         ioc.buf = buf;
1771         ioc.len = buflen;
1772         ioc.set = TRUE;
1773
1774         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
1775         if (ret < 0) {
1776                 DHD_ERROR(("%s: set mcast_list failed, cnt %d\n",
1777                         dhd_ifname(&dhd->pub, ifidx), cnt));
1778                 allmulti = cnt ? TRUE : allmulti;
1779         }
1780
1781         MFREE(dhd->pub.osh, buf, buflen);
1782
1783         /* Now send the allmulti setting.  This is based on the setting in the
1784          * net_device flags, but might be modified above to be turned on if we
1785          * were trying to set some addresses and dongle rejected it...
1786          */
1787
1788         buflen = sizeof("allmulti") + sizeof(allmulti);
1789         if (!(buf = MALLOC(dhd->pub.osh, buflen))) {
1790                 DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx)));
1791                 return;
1792         }
1793         allmulti = htol32(allmulti);
1794
1795         if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) {
1796                 DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
1797                            dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen));
1798                 MFREE(dhd->pub.osh, buf, buflen);
1799                 return;
1800         }
1801
1802
1803         memset(&ioc, 0, sizeof(ioc));
1804         ioc.cmd = WLC_SET_VAR;
1805         ioc.buf = buf;
1806         ioc.len = buflen;
1807         ioc.set = TRUE;
1808
1809         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
1810         if (ret < 0) {
1811                 DHD_ERROR(("%s: set allmulti %d failed\n",
1812                            dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
1813         }
1814
1815         MFREE(dhd->pub.osh, buf, buflen);
1816
1817         /* Finally, pick up the PROMISC flag as well, like the NIC driver does */
1818
1819         allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE;
1820
1821         allmulti = htol32(allmulti);
1822
1823         memset(&ioc, 0, sizeof(ioc));
1824         ioc.cmd = WLC_SET_PROMISC;
1825         ioc.buf = &allmulti;
1826         ioc.len = sizeof(allmulti);
1827         ioc.set = TRUE;
1828
1829         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
1830         if (ret < 0) {
1831                 DHD_ERROR(("%s: set promisc %d failed\n",
1832                            dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
1833         }
1834 }
1835
1836 int
1837 _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr)
1838 {
1839         char buf[32];
1840         wl_ioctl_t ioc;
1841         int ret;
1842
1843         if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) {
1844                 DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx)));
1845                 return -1;
1846         }
1847         memset(&ioc, 0, sizeof(ioc));
1848         ioc.cmd = WLC_SET_VAR;
1849         ioc.buf = buf;
1850         ioc.len = 32;
1851         ioc.set = TRUE;
1852
1853         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
1854         if (ret < 0) {
1855                 DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)));
1856         } else {
1857                 memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
1858                 if (ifidx == 0)
1859                         memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN);
1860         }
1861
1862         return ret;
1863 }
1864
1865 #ifdef SOFTAP
1866 extern struct net_device *ap_net_dev;
1867 extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */
1868 #endif
1869
1870 static void
1871 dhd_ifadd_event_handler(void *handle, void *event_info, u8 event)
1872 {
1873         dhd_info_t *dhd = handle;
1874         dhd_if_event_t *if_event = event_info;
1875         struct net_device *ndev;
1876         int ifidx, bssidx;
1877         int ret;
1878 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
1879         struct wireless_dev *vwdev, *primary_wdev;
1880         struct net_device *primary_ndev;
1881 #endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
1882
1883         if (event != DHD_WQ_WORK_IF_ADD) {
1884                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
1885                 return;
1886         }
1887
1888         if (!dhd) {
1889                 DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
1890                 return;
1891         }
1892
1893         if (!if_event) {
1894                 DHD_ERROR(("%s: event data is null \n", __FUNCTION__));
1895                 return;
1896         }
1897
1898         dhd_net_if_lock_local(dhd);
1899         DHD_OS_WAKE_LOCK(&dhd->pub);
1900         DHD_PERIM_LOCK(&dhd->pub);
1901
1902         ifidx = if_event->event.ifidx;
1903         bssidx = if_event->event.bssidx;
1904         DHD_TRACE(("%s: registering if with ifidx %d\n", __FUNCTION__, ifidx));
1905
1906         ndev = dhd_allocate_if(&dhd->pub, ifidx, if_event->name,
1907                 if_event->mac, bssidx, TRUE);
1908         if (!ndev) {
1909                 DHD_ERROR(("%s: net device alloc failed  \n", __FUNCTION__));
1910                 goto done;
1911         }
1912
1913 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
1914         vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
1915         if (unlikely(!vwdev)) {
1916                 WL_ERR(("Could not allocate wireless device\n"));
1917                 goto done;
1918         }
1919         primary_ndev = dhd->pub.info->iflist[0]->net;
1920         primary_wdev = ndev_to_wdev(primary_ndev);
1921         vwdev->wiphy = primary_wdev->wiphy;
1922         vwdev->iftype = if_event->event.role;
1923         vwdev->netdev = ndev;
1924         ndev->ieee80211_ptr = vwdev;
1925         SET_NETDEV_DEV(ndev, wiphy_dev(vwdev->wiphy));
1926         DHD_ERROR(("virtual interface(%s) is created\n", if_event->name));
1927 #endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
1928
1929         DHD_PERIM_UNLOCK(&dhd->pub);
1930         ret = dhd_register_if(&dhd->pub, ifidx, TRUE);
1931         DHD_PERIM_LOCK(&dhd->pub);
1932         if (ret != BCME_OK) {
1933                 DHD_ERROR(("%s: dhd_register_if failed\n", __FUNCTION__));
1934                         dhd_remove_if(&dhd->pub, ifidx, TRUE);
1935         }
1936 #ifdef PCIE_FULL_DONGLE
1937         /* Turn on AP isolation in the firmware for interfaces operating in AP mode */
1938         if (FW_SUPPORTED((&dhd->pub), ap) && (if_event->event.role != WLC_E_IF_ROLE_STA)) {
1939                 char iovbuf[WLC_IOCTL_SMLEN];
1940                 uint32 var_int =  1;
1941
1942                 memset(iovbuf, 0, sizeof(iovbuf));
1943                 bcm_mkiovar("ap_isolate", (char *)&var_int, 4, iovbuf, sizeof(iovbuf));
1944                 dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, ifidx);
1945         }
1946 #endif /* PCIE_FULL_DONGLE */
1947 done:
1948         MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
1949
1950         DHD_PERIM_UNLOCK(&dhd->pub);
1951         DHD_OS_WAKE_UNLOCK(&dhd->pub);
1952         dhd_net_if_unlock_local(dhd);
1953 }
1954
1955 static void
1956 dhd_ifdel_event_handler(void *handle, void *event_info, u8 event)
1957 {
1958         dhd_info_t *dhd = handle;
1959         int ifidx;
1960         dhd_if_event_t *if_event = event_info;
1961
1962
1963         if (event != DHD_WQ_WORK_IF_DEL) {
1964                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
1965                 return;
1966         }
1967
1968         if (!dhd) {
1969                 DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
1970                 return;
1971         }
1972
1973         if (!if_event) {
1974                 DHD_ERROR(("%s: event data is null \n", __FUNCTION__));
1975                 return;
1976         }
1977
1978         dhd_net_if_lock_local(dhd);
1979         DHD_OS_WAKE_LOCK(&dhd->pub);
1980         DHD_PERIM_LOCK(&dhd->pub);
1981
1982         ifidx = if_event->event.ifidx;
1983         DHD_TRACE(("Removing interface with idx %d\n", ifidx));
1984
1985         dhd_remove_if(&dhd->pub, ifidx, TRUE);
1986
1987         MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
1988
1989         DHD_PERIM_UNLOCK(&dhd->pub);
1990         DHD_OS_WAKE_UNLOCK(&dhd->pub);
1991         dhd_net_if_unlock_local(dhd);
1992 }
1993
1994 static void
1995 dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event)
1996 {
1997         dhd_info_t *dhd = handle;
1998         dhd_if_t *ifp = event_info;
1999
2000         if (event != DHD_WQ_WORK_SET_MAC) {
2001                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
2002         }
2003
2004         if (!dhd) {
2005                 DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
2006                 return;
2007         }
2008
2009         dhd_net_if_lock_local(dhd);
2010         DHD_OS_WAKE_LOCK(&dhd->pub);
2011         DHD_PERIM_LOCK(&dhd->pub);
2012
2013 #ifdef SOFTAP
2014         {
2015                 unsigned long flags;
2016                 bool in_ap = FALSE;
2017                 DHD_GENERAL_LOCK(&dhd->pub, flags);
2018                 in_ap = (ap_net_dev != NULL);
2019                 DHD_GENERAL_UNLOCK(&dhd->pub, flags);
2020
2021                 if (in_ap)  {
2022                         DHD_ERROR(("attempt to set MAC for %s in AP Mode, blocked. \n",
2023                                    ifp->net->name));
2024                         goto done;
2025                 }
2026         }
2027 #endif /* SOFTAP */
2028
2029         if (ifp == NULL || !dhd->pub.up) {
2030                 DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__));
2031                 goto done;
2032         }
2033
2034         DHD_ERROR(("%s: MACID is overwritten\n", __FUNCTION__));
2035         ifp->set_macaddress = FALSE;
2036         if (_dhd_set_mac_address(dhd, ifp->idx, ifp->mac_addr) == 0)
2037                 DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__));
2038         else
2039                 DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__));
2040
2041 done:
2042         DHD_PERIM_UNLOCK(&dhd->pub);
2043         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2044         dhd_net_if_unlock_local(dhd);
2045 }
2046
2047 static void
2048 dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event)
2049 {
2050         dhd_info_t *dhd = handle;
2051         dhd_if_t *ifp = event_info;
2052         int ifidx;
2053
2054         if (event != DHD_WQ_WORK_SET_MCAST_LIST) {
2055                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
2056                 return;
2057         }
2058
2059         if (!dhd) {
2060                 DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
2061                 return;
2062         }
2063
2064         dhd_net_if_lock_local(dhd);
2065         DHD_OS_WAKE_LOCK(&dhd->pub);
2066         DHD_PERIM_LOCK(&dhd->pub);
2067
2068 #ifdef SOFTAP
2069         {
2070                 bool in_ap = FALSE;
2071                 unsigned long flags;
2072                 DHD_GENERAL_LOCK(&dhd->pub, flags);
2073                 in_ap = (ap_net_dev != NULL);
2074                 DHD_GENERAL_UNLOCK(&dhd->pub, flags);
2075
2076                 if (in_ap)  {
2077                         DHD_ERROR(("set MULTICAST list for %s in AP Mode, blocked. \n",
2078                                    ifp->net->name));
2079                         ifp->set_multicast = FALSE;
2080                         goto done;
2081                 }
2082         }
2083 #endif /* SOFTAP */
2084
2085         if (ifp == NULL || !dhd->pub.up) {
2086                 DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__));
2087                 goto done;
2088         }
2089
2090         ifidx = ifp->idx;
2091
2092
2093         _dhd_set_multicast_list(dhd, ifidx);
2094         DHD_INFO(("%s: set multicast list for if %d\n", __FUNCTION__, ifidx));
2095
2096 done:
2097         DHD_PERIM_UNLOCK(&dhd->pub);
2098         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2099         dhd_net_if_unlock_local(dhd);
2100 }
2101
2102 static int
2103 dhd_set_mac_address(struct net_device *dev, void *addr)
2104 {
2105         int ret = 0;
2106
2107         dhd_info_t *dhd = DHD_DEV_INFO(dev);
2108         struct sockaddr *sa = (struct sockaddr *)addr;
2109         int ifidx;
2110         dhd_if_t *dhdif;
2111
2112         ifidx = dhd_net2idx(dhd, dev);
2113         if (ifidx == DHD_BAD_IF)
2114                 return -1;
2115
2116         dhdif = dhd->iflist[ifidx];
2117
2118         dhd_net_if_lock_local(dhd);
2119         memcpy(dhdif->mac_addr, sa->sa_data, ETHER_ADDR_LEN);
2120         dhdif->set_macaddress = TRUE;
2121         dhd_net_if_unlock_local(dhd);
2122         dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhdif, DHD_WQ_WORK_SET_MAC,
2123                 dhd_set_mac_addr_handler, DHD_WORK_PRIORITY_LOW);
2124         return ret;
2125 }
2126
2127 static void
2128 dhd_set_multicast_list(struct net_device *dev)
2129 {
2130         dhd_info_t *dhd = DHD_DEV_INFO(dev);
2131         int ifidx;
2132
2133         ifidx = dhd_net2idx(dhd, dev);
2134         if (ifidx == DHD_BAD_IF)
2135                 return;
2136
2137         dhd->iflist[ifidx]->set_multicast = TRUE;
2138         dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhd->iflist[ifidx],
2139                 DHD_WQ_WORK_SET_MCAST_LIST, dhd_set_mcast_list_handler, DHD_WORK_PRIORITY_LOW);
2140 }
2141
2142 #ifdef PROP_TXSTATUS
2143 int
2144 dhd_os_wlfc_block(dhd_pub_t *pub)
2145 {
2146         dhd_info_t *di = (dhd_info_t *)(pub->info);
2147         ASSERT(di != NULL);
2148         spin_lock_bh(&di->wlfc_spinlock);
2149         return 1;
2150 }
2151
2152 int
2153 dhd_os_wlfc_unblock(dhd_pub_t *pub)
2154 {
2155         dhd_info_t *di = (dhd_info_t *)(pub->info);
2156
2157         ASSERT(di != NULL);
2158         spin_unlock_bh(&di->wlfc_spinlock);
2159         return 1;
2160 }
2161
2162 #endif /* PROP_TXSTATUS */
2163
2164 int BCMFASTPATH
2165 dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
2166 {
2167         int ret = BCME_OK;
2168         dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
2169         struct ether_header *eh = NULL;
2170         int temp_prio;
2171
2172         DHD_INFO(("skb->prio = %d\n", PKTPRIO(pktbuf)));
2173
2174         /* Reject if down */
2175         if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) {
2176                 /* free the packet here since the caller won't */
2177                 PKTFREE(dhdp->osh, pktbuf, TRUE);
2178                 return -ENODEV;
2179         }
2180
2181 #ifdef PCIE_FULL_DONGLE
2182         if (dhdp->busstate == DHD_BUS_SUSPEND) {
2183                 DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__));
2184                 PKTFREE(dhdp->osh, pktbuf, TRUE);
2185                 return -EBUSY;
2186         }
2187 #endif /* PCIE_FULL_DONGLE */
2188
2189 #ifdef DHD_UNICAST_DHCP
2190         /* if dhcp_unicast is enabled, we need to convert the */
2191         /* broadcast DHCP ACK/REPLY packets to Unicast. */
2192         if (dhdp->dhcp_unicast) {
2193             dhd_convert_dhcp_broadcast_ack_to_unicast(dhdp, pktbuf, ifidx);
2194         }
2195 #endif /* DHD_UNICAST_DHCP */
2196         /* Update multicast statistic */
2197         if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) {
2198                 uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
2199                 eh = (struct ether_header *)pktdata;
2200
2201                 if (ETHER_ISMULTI(eh->ether_dhost))
2202                         dhdp->tx_multicast++;
2203                 if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X)
2204                         atomic_inc(&dhd->pend_8021x_cnt);
2205         } else {
2206                         PKTFREE(dhd->pub.osh, pktbuf, TRUE);
2207                         return BCME_ERROR;
2208         }
2209
2210 #ifdef DHDTCPACK_SUPPRESS
2211         /* If this packet has replaced another packet and got freed, just return */
2212         if (dhd_tcpack_suppress(dhdp, pktbuf))
2213                 return ret;
2214 #endif /* DHDTCPACK_SUPPRESS */
2215
2216         /* Look into the packet and update the packet priority */
2217         temp_prio = PKTPRIO(pktbuf);
2218         if (temp_prio & 0x100)
2219                 PKTSETPRIO(pktbuf, temp_prio & 0xFF);
2220 #ifndef PKTPRIO_OVERRIDE
2221         if (PKTPRIO(pktbuf) == 0)
2222 #endif 
2223                 pktsetprio(pktbuf, FALSE);
2224
2225
2226 #ifdef PCIE_FULL_DONGLE
2227         /*
2228          * Lkup the per interface hash table, for a matching flowring. If one is not
2229          * available, allocate a unique flowid and add a flowring entry.
2230          * The found or newly created flowid is placed into the pktbuf's tag.
2231          */
2232         ret = dhd_flowid_update(dhdp, ifidx, dhdp->flow_prio_map[(PKTPRIO(pktbuf))], pktbuf);
2233         if (ret != BCME_OK) {
2234                 PKTCFREE(dhd->pub.osh, pktbuf, TRUE);
2235                 return ret;
2236         }
2237 #endif
2238
2239 #ifdef PROP_TXSTATUS
2240         if (dhd_wlfc_is_supported(dhdp)) {
2241                 /* store the interface ID */
2242                 DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx);
2243
2244                 /* store destination MAC in the tag as well */
2245                 DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost);
2246
2247                 /* decide which FIFO this packet belongs to */
2248                 if (ETHER_ISMULTI(eh->ether_dhost))
2249                         /* one additional queue index (highest AC + 1) is used for bc/mc queue */
2250                         DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT);
2251                 else
2252                         DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf)));
2253         } else
2254 #endif /* PROP_TXSTATUS */
2255         /* If the protocol uses a data header, apply it */
2256         dhd_prot_hdrpush(dhdp, ifidx, pktbuf);
2257
2258         /* Use bus module to send data frame */
2259 #ifdef WLMEDIA_HTSF
2260         dhd_htsf_addtxts(dhdp, pktbuf);
2261 #endif
2262 #ifdef PROP_TXSTATUS
2263         {
2264                 if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_bus_txdata,
2265                         dhdp->bus, pktbuf, TRUE) == WLFC_UNSUPPORTED) {
2266                         /* non-proptxstatus way */
2267 #ifdef BCMPCIE
2268                         ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx);
2269 #else
2270                         ret = dhd_bus_txdata(dhdp->bus, pktbuf);
2271 #endif /* BCMPCIE */
2272                 }
2273         }
2274 #else
2275 #ifdef BCMPCIE
2276         ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx);
2277 #else
2278         ret = dhd_bus_txdata(dhdp->bus, pktbuf);
2279 #endif /* BCMPCIE */
2280 #endif /* PROP_TXSTATUS */
2281
2282         return ret;
2283 }
2284
2285 int BCMFASTPATH
2286 dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
2287 {
2288         int ret;
2289         uint datalen;
2290         void *pktbuf;
2291         dhd_info_t *dhd = DHD_DEV_INFO(net);
2292         dhd_if_t *ifp = NULL;
2293         int ifidx;
2294 #ifdef WLMEDIA_HTSF
2295         uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz;
2296 #else
2297         uint8 htsfdlystat_sz = 0;
2298 #endif
2299 #ifdef DHD_WMF
2300         struct ether_header *eh;
2301         uint8 *iph;
2302 #endif /* DHD_WMF */
2303
2304         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2305
2306         DHD_OS_WAKE_LOCK(&dhd->pub);
2307         DHD_PERIM_LOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2308
2309         /* Reject if down */
2310         if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) {
2311                 DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n",
2312                         __FUNCTION__, dhd->pub.up, dhd->pub.busstate));
2313                 netif_stop_queue(net);
2314                 /* Send Event when bus down detected during data session */
2315                 if (dhd->pub.up) {
2316                         DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__));
2317                         net_os_send_hang_message(net);
2318                 }
2319                 DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2320                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2321 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
2322                 return -ENODEV;
2323 #else
2324                 return NETDEV_TX_BUSY;
2325 #endif
2326         }
2327
2328         ifp = DHD_DEV_IFP(net);
2329         ifidx = DHD_DEV_IFIDX(net);
2330
2331         ASSERT(ifidx == dhd_net2idx(dhd, net));
2332         ASSERT((ifp != NULL) && (ifp == dhd->iflist[ifidx]));
2333
2334         if (ifidx == DHD_BAD_IF) {
2335                 DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx));
2336                 netif_stop_queue(net);
2337                 DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2338                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2339 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
2340                 return -ENODEV;
2341 #else
2342                 return NETDEV_TX_BUSY;
2343 #endif
2344         }
2345
2346         /* re-align socket buffer if "skb->data" is odd address */
2347         if (((unsigned long)(skb->data)) & 0x1) {
2348                 unsigned char *data = skb->data;
2349                 uint32 length = skb->len;
2350                 PKTPUSH(dhd->pub.osh, skb, 1);
2351                 memmove(skb->data, data, length);
2352                 PKTSETLEN(dhd->pub.osh, skb, length);
2353         }
2354
2355         datalen  = PKTLEN(dhd->pub.osh, skb);
2356
2357         /* Make sure there's enough room for any header */
2358
2359         if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) {
2360                 struct sk_buff *skb2;
2361
2362                 DHD_INFO(("%s: insufficient headroom\n",
2363                           dhd_ifname(&dhd->pub, ifidx)));
2364                 dhd->pub.tx_realloc++;
2365
2366                 skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz);
2367
2368                 dev_kfree_skb(skb);
2369                 if ((skb = skb2) == NULL) {
2370                         DHD_ERROR(("%s: skb_realloc_headroom failed\n",
2371                                    dhd_ifname(&dhd->pub, ifidx)));
2372                         ret = -ENOMEM;
2373                         goto done;
2374                 }
2375         }
2376
2377 #ifdef CONFIG_BCMDHD_CUSTOM_SYSFS_TEGRA
2378         tegra_sysfs_histogram_tcpdump_tx(skb, __func__, __LINE__);
2379 #endif
2380
2381         /* Convert to packet */
2382         if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) {
2383                 DHD_ERROR(("%s: PKTFRMNATIVE failed\n",
2384                            dhd_ifname(&dhd->pub, ifidx)));
2385                 dev_kfree_skb_any(skb);
2386                 ret = -ENOMEM;
2387                 goto done;
2388         }
2389 #ifdef WLMEDIA_HTSF
2390         if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) {
2391                 uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf);
2392                 struct ether_header *eh = (struct ether_header *)pktdata;
2393
2394                 if (!ETHER_ISMULTI(eh->ether_dhost) &&
2395                         (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) {
2396                         eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS);
2397                 }
2398         }
2399 #endif
2400 #ifdef DHD_WMF
2401         eh = (struct ether_header *)PKTDATA(dhd->pub.osh, pktbuf);
2402         iph = (uint8 *)eh + ETHER_HDR_LEN;
2403
2404         /* WMF processing for multicast packets
2405          * Only IPv4 packets are handled
2406          */
2407         if (ifp->wmf.wmf_enable && (ntoh16(eh->ether_type) == ETHER_TYPE_IP) &&
2408                 (IP_VER(iph) == IP_VER_4) && (ETHER_ISMULTI(eh->ether_dhost) ||
2409                 ((IPV4_PROT(iph) == IP_PROT_IGMP) && dhd->pub.wmf_ucast_igmp))) {
2410 #if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP)
2411                 void *sdu_clone;
2412                 bool ucast_convert = FALSE;
2413 #ifdef DHD_UCAST_UPNP
2414                 uint32 dest_ip;
2415
2416                 dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET)));
2417                 ucast_convert = dhd->pub.wmf_ucast_upnp && MCAST_ADDR_UPNP_SSDP(dest_ip);
2418 #endif /* DHD_UCAST_UPNP */
2419 #ifdef DHD_IGMP_UCQUERY
2420                 ucast_convert |= dhd->pub.wmf_ucast_igmp_query &&
2421                         (IPV4_PROT(iph) == IP_PROT_IGMP) &&
2422                         (*(iph + IPV4_HLEN(iph)) == IGMPV2_HOST_MEMBERSHIP_QUERY);
2423 #endif /* DHD_IGMP_UCQUERY */
2424                 if (ucast_convert) {
2425                         dhd_sta_t *sta;
2426                         unsigned long flags;
2427
2428                         DHD_IF_STA_LIST_LOCK(ifp, flags);
2429
2430                         /* Convert upnp/igmp query to unicast for each assoc STA */
2431                         list_for_each_entry(sta, &ifp->sta_list, list) {
2432                                 if ((sdu_clone = PKTDUP(dhd->pub.osh, pktbuf)) == NULL) {
2433                                         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
2434                                         DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2435                                         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2436                                         return (WMF_NOP);
2437                                 }
2438                                 dhd_wmf_forward(ifp->wmf.wmfh, sdu_clone, 0, sta, 1);
2439                         }
2440
2441                         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
2442                         DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2443                         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2444
2445                         PKTFREE(dhd->pub.osh, pktbuf, TRUE);
2446                         return NETDEV_TX_OK;
2447                 } else
2448 #endif /* defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) */
2449                 {
2450                         /* There will be no STA info if the packet is coming from LAN host
2451                          * Pass as NULL
2452                          */
2453                         ret = dhd_wmf_packets_handle(&dhd->pub, pktbuf, NULL, ifidx, 0);
2454                         switch (ret) {
2455                         case WMF_TAKEN:
2456                         case WMF_DROP:
2457                                 /* Either taken by WMF or we should drop it.
2458                                  * Exiting send path
2459                                  */
2460                                 DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2461                                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2462                                 return NETDEV_TX_OK;
2463                         default:
2464                                 /* Continue the transmit path */
2465                                 break;
2466                         }
2467                 }
2468         }
2469 #endif /* DHD_WMF */
2470
2471         ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf);
2472
2473 done:
2474         if (ret) {
2475                 ifp->stats.tx_dropped++;
2476                 dhd->pub.tx_dropped++;
2477         }
2478         else {
2479                 dhd->pub.tx_packets++;
2480                 ifp->stats.tx_packets++;
2481                 ifp->stats.tx_bytes += datalen;
2482         }
2483
2484         DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2485         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2486
2487         /* Return ok: we always eat the packet */
2488 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
2489         return 0;
2490 #else
2491         return NETDEV_TX_OK;
2492 #endif
2493 }
2494
2495
2496 void
2497 dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state)
2498 {
2499         struct net_device *net;
2500         dhd_info_t *dhd = dhdp->info;
2501         int i;
2502
2503         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2504
2505         ASSERT(dhd);
2506
2507         if (ifidx == ALL_INTERFACES) {
2508                 /* Flow control on all active interfaces */
2509                 dhdp->txoff = state;
2510                 for (i = 0; i < DHD_MAX_IFS; i++) {
2511                         if (dhd->iflist[i]) {
2512                                 net = dhd->iflist[i]->net;
2513                                 if (state == ON)
2514                                         netif_stop_queue(net);
2515                                 else
2516                                         netif_wake_queue(net);
2517                         }
2518                 }
2519         }
2520         else {
2521                 if (dhd->iflist[ifidx]) {
2522                         net = dhd->iflist[ifidx]->net;
2523                         if (state == ON)
2524                                 netif_stop_queue(net);
2525                         else
2526                                 netif_wake_queue(net);
2527                 }
2528         }
2529 }
2530
2531 #ifdef DHD_RX_DUMP
2532 typedef struct {
2533         uint16 type;
2534         const char *str;
2535 } PKTTYPE_INFO;
2536
2537 static const PKTTYPE_INFO packet_type_info[] =
2538 {
2539         { ETHER_TYPE_IP, "IP" },
2540         { ETHER_TYPE_ARP, "ARP" },
2541         { ETHER_TYPE_BRCM, "BRCM" },
2542         { ETHER_TYPE_802_1X, "802.1X" },
2543         { ETHER_TYPE_WAI, "WAPI" },
2544         { 0, ""}
2545 };
2546
2547 static const char *_get_packet_type_str(uint16 type)
2548 {
2549         int i;
2550         int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1;
2551
2552         for (i = 0; i < n; i++) {
2553                 if (packet_type_info[i].type == type)
2554                         return packet_type_info[i].str;
2555         }
2556
2557         return packet_type_info[n].str;
2558 }
2559 #endif /* DHD_RX_DUMP */
2560
2561
2562 #ifdef DHD_WMF
2563 bool
2564 dhd_is_rxthread_enabled(dhd_pub_t *dhdp)
2565 {
2566         dhd_info_t *dhd = dhdp->info;
2567
2568         return dhd->rxthread_enabled;
2569 }
2570 #endif /* DHD_WMF */
2571
2572 void
2573 dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
2574 {
2575         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
2576         struct sk_buff *skb;
2577         uchar *eth;
2578         uint len;
2579         void *data, *pnext = NULL;
2580         int i;
2581         dhd_if_t *ifp;
2582         wl_event_msg_t event;
2583         int tout_rx = 0;
2584         int tout_ctrl = 0;
2585         void *skbhead = NULL;
2586         void *skbprev = NULL;
2587 #if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP)
2588         char *dump_data;
2589         uint16 protocol;
2590 #endif /* DHD_RX_DUMP || DHD_8021X_DUMP */
2591
2592         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2593
2594         for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) {
2595                 struct ether_header *eh;
2596
2597                 pnext = PKTNEXT(dhdp->osh, pktbuf);
2598                 PKTSETNEXT(dhdp->osh, pktbuf, NULL);
2599
2600                 ifp = dhd->iflist[ifidx];
2601                 if (ifp == NULL) {
2602                         DHD_ERROR(("%s: ifp is NULL. drop packet\n",
2603                                 __FUNCTION__));
2604                         PKTCFREE(dhdp->osh, pktbuf, FALSE);
2605                         continue;
2606                 }
2607
2608                 eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf);
2609
2610                 /* Dropping only data packets before registering net device to avoid kernel panic */
2611 #ifndef PROP_TXSTATUS_VSDB
2612                 if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) &&
2613                         (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) {
2614 #else
2615                 if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) &&
2616                         (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) {
2617 #endif /* PROP_TXSTATUS_VSDB */
2618                         DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n",
2619                         __FUNCTION__));
2620                         PKTCFREE(dhdp->osh, pktbuf, FALSE);
2621                         continue;
2622                 }
2623
2624
2625 #ifdef PROP_TXSTATUS
2626                 if (dhd_wlfc_is_header_only_pkt(dhdp, pktbuf)) {
2627                         /* WLFC may send header only packet when
2628                         there is an urgent message but no packet to
2629                         piggy-back on
2630                         */
2631                         PKTCFREE(dhdp->osh, pktbuf, FALSE);
2632                         continue;
2633                 }
2634 #endif
2635 #ifdef DHD_L2_FILTER
2636                 /* If block_ping is enabled drop the ping packet */
2637                 if (dhdp->block_ping) {
2638                         if (dhd_l2_filter_block_ping(dhdp, pktbuf, ifidx) == BCME_OK) {
2639                                 PKTFREE(dhdp->osh, pktbuf, FALSE);
2640                                 continue;
2641                         }
2642                 }
2643 #endif
2644 #ifdef DHD_WMF
2645                 /* WMF processing for multicast packets */
2646                 if (ifp->wmf.wmf_enable && (ETHER_ISMULTI(eh->ether_dhost))) {
2647                         dhd_sta_t *sta;
2648                         int ret;
2649
2650                         sta = dhd_find_sta(dhdp, ifidx, (void *)eh->ether_shost);
2651                         ret = dhd_wmf_packets_handle(dhdp, pktbuf, sta, ifidx, 1);
2652                         switch (ret) {
2653                                 case WMF_TAKEN:
2654                                         /* The packet is taken by WMF. Continue to next iteration */
2655                                         continue;
2656                                 case WMF_DROP:
2657                                         /* Packet DROP decision by WMF. Toss it */
2658                                         DHD_ERROR(("%s: WMF decides to drop packet\n",
2659                                                 __FUNCTION__));
2660                                         PKTCFREE(dhdp->osh, pktbuf, FALSE);
2661                                         continue;
2662                                 default:
2663                                         /* Continue the transmit path */
2664                                         break;
2665                         }
2666                 }
2667 #endif /* DHD_WMF */
2668 #ifdef DHDTCPACK_SUPPRESS
2669                 dhd_tcpdata_info_get(dhdp, pktbuf);
2670 #endif
2671                 skb = PKTTONATIVE(dhdp->osh, pktbuf);
2672
2673                 ifp = dhd->iflist[ifidx];
2674                 if (ifp == NULL)
2675                         ifp = dhd->iflist[0];
2676
2677                 ASSERT(ifp);
2678                 skb->dev = ifp->net;
2679
2680 #ifdef PCIE_FULL_DONGLE
2681                 if ((DHD_IF_ROLE_AP(dhdp, ifidx) || DHD_IF_ROLE_P2PGO(dhdp, ifidx)) &&
2682                         (!ifp->ap_isolate)) {
2683                         eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf);
2684                         if (ETHER_ISUCAST(eh->ether_dhost)) {
2685                                 if (dhd_find_sta(dhdp, ifidx, (void *)eh->ether_dhost)) {
2686                                                 dhd_sendpkt(dhdp, ifidx, pktbuf);
2687                                         continue;
2688                                 }
2689                         } else {
2690                                 void *npktbuf = PKTDUP(dhdp->osh, pktbuf);
2691                                 dhd_sendpkt(dhdp, ifidx, npktbuf);
2692                         }
2693                 }
2694 #endif /* PCIE_FULL_DONGLE */
2695
2696                 /* Get the protocol, maintain skb around eth_type_trans()
2697                  * The main reason for this hack is for the limitation of
2698                  * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len'
2699                  * to perform skb_pull inside vs ETH_HLEN. Since to avoid
2700                  * coping of the packet coming from the network stack to add
2701                  * BDC, Hardware header etc, during network interface registration
2702                  * we set the 'net->hard_header_len' to ETH_HLEN + extra space required
2703                  * for BDC, Hardware header etc. and not just the ETH_HLEN
2704                  */
2705                 eth = skb->data;
2706                 len = skb->len;
2707
2708 #if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP)
2709                 dump_data = skb->data;
2710                 protocol = (dump_data[12] << 8) | dump_data[13];
2711
2712                 if (protocol == ETHER_TYPE_802_1X) {
2713                         DHD_ERROR(("ETHER_TYPE_802_1X: "
2714                                 "ver %d, type %d, replay %d\n",
2715                                 dump_data[14], dump_data[15],
2716                                 dump_data[30]));
2717                 }
2718 #endif /* DHD_RX_DUMP || DHD_8021X_DUMP */
2719 #if defined(DHD_RX_DUMP)
2720                 DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol)));
2721                 if (protocol != ETHER_TYPE_BRCM) {
2722                         if (dump_data[0] == 0xFF) {
2723                                 DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__));
2724
2725                                 if ((dump_data[12] == 8) &&
2726                                         (dump_data[13] == 6)) {
2727                                         DHD_ERROR(("%s: ARP %d\n",
2728                                                 __FUNCTION__, dump_data[0x15]));
2729                                 }
2730                         } else if (dump_data[0] & 1) {
2731                                 DHD_ERROR(("%s: MULTICAST: " MACDBG "\n",
2732                                         __FUNCTION__, MAC2STRDBG(dump_data)));
2733                         }
2734 #ifdef DHD_RX_FULL_DUMP
2735                         {
2736                                 int k;
2737                                 for (k = 0; k < skb->len; k++) {
2738                                         DHD_ERROR(("%02X ", dump_data[k]));
2739                                         if ((k & 15) == 15)
2740                                                 DHD_ERROR(("\n"));
2741                                 }
2742                                 DHD_ERROR(("\n"));
2743                         }
2744 #endif /* DHD_RX_FULL_DUMP */
2745                 }
2746 #endif /* DHD_RX_DUMP */
2747
2748                 skb->protocol = eth_type_trans(skb, skb->dev);
2749
2750                 if (skb->pkt_type == PACKET_MULTICAST) {
2751                         dhd->pub.rx_multicast++;
2752                         ifp->stats.multicast++;
2753                 }
2754
2755                 skb->data = eth;
2756                 skb->len = len;
2757
2758 #ifdef WLMEDIA_HTSF
2759                 dhd_htsf_addrxts(dhdp, pktbuf);
2760 #endif
2761                 /* Strip header, count, deliver upward */
2762                 RX_CAPTURE(skb);
2763                 skb_pull(skb, ETH_HLEN);
2764
2765                 /* Process special event packets and then discard them */
2766                 memset(&event, 0, sizeof(event));
2767                 if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) {
2768                         dhd_wl_host_event(dhd, &ifidx,
2769 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
2770                         skb_mac_header(skb),
2771 #else
2772                         skb->mac.raw,
2773 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */
2774                         &event,
2775                         &data);
2776
2777                         wl_event_to_host_order(&event);
2778                         if (!tout_ctrl)
2779                                 tout_ctrl = DHD_PACKET_TIMEOUT_MS;
2780
2781 #if defined(PNO_SUPPORT)
2782                         if (event.event_type == WLC_E_PFN_NET_FOUND) {
2783                                 /* enforce custom wake lock to garantee that Kernel not suspended */
2784                                 tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS;
2785                         }
2786 #endif /* PNO_SUPPORT */
2787
2788 #ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT
2789                         PKTFREE(dhdp->osh, pktbuf, FALSE);
2790                         continue;
2791 #endif /* DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */
2792                 } else {
2793                         tout_rx = DHD_PACKET_TIMEOUT_MS;
2794
2795 #ifdef PROP_TXSTATUS
2796                         dhd_wlfc_save_rxpath_ac_time(dhdp, (uint8)PKTPRIO(skb));
2797 #endif /* PROP_TXSTATUS */
2798                 }
2799
2800                 ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
2801                 ifp = dhd->iflist[ifidx];
2802
2803                 if (ifp->net)
2804                         ifp->net->last_rx = jiffies;
2805
2806                 if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) {
2807                         dhdp->dstats.rx_bytes += skb->len;
2808                         dhdp->rx_packets++; /* Local count */
2809                         ifp->stats.rx_bytes += skb->len;
2810                         ifp->stats.rx_packets++;
2811                 }
2812
2813                 if (in_interrupt()) {
2814                         netif_rx(skb);
2815                 } else {
2816                         if (dhd->rxthread_enabled) {
2817                                 if (!skbhead)
2818                                         skbhead = skb;
2819                                 else
2820                                         PKTSETNEXT(dhdp->osh, skbprev, skb);
2821                                 skbprev = skb;
2822                         } else {
2823
2824                                 /* If the receive is not processed inside an ISR,
2825                                  * the softirqd must be woken explicitly to service
2826                                  * the NET_RX_SOFTIRQ.  In 2.6 kernels, this is handled
2827                                  * by netif_rx_ni(), but in earlier kernels, we need
2828                                  * to do it manually.
2829                                  */
2830 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
2831                                 netif_rx_ni(skb);
2832 #else
2833                                 ulong flags;
2834                                 netif_rx(skb);
2835                                 local_irq_save(flags);
2836                                 RAISE_RX_SOFTIRQ();
2837                                 local_irq_restore(flags);
2838 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
2839                         }
2840                 }
2841         }
2842
2843         if (dhd->rxthread_enabled && skbhead)
2844                 dhd_sched_rxf(dhdp, skbhead);
2845
2846         DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx);
2847         DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl);
2848 }
2849
2850 void
2851 dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx)
2852 {
2853         /* Linux version has nothing to do */
2854         return;
2855 }
2856
2857 void
2858 dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success)
2859 {
2860         dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
2861         struct ether_header *eh;
2862         uint16 type;
2863
2864         dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL);
2865
2866         eh = (struct ether_header *)PKTDATA(dhdp->osh, txp);
2867         type  = ntoh16(eh->ether_type);
2868
2869         if (type == ETHER_TYPE_802_1X)
2870                 atomic_dec(&dhd->pend_8021x_cnt);
2871
2872 }
2873
2874 static struct net_device_stats *
2875 dhd_get_stats(struct net_device *net)
2876 {
2877         dhd_info_t *dhd = DHD_DEV_INFO(net);
2878         dhd_if_t *ifp;
2879         int ifidx;
2880
2881         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2882
2883         ifidx = dhd_net2idx(dhd, net);
2884         if (ifidx == DHD_BAD_IF) {
2885                 DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__));
2886
2887                 memset(&net->stats, 0, sizeof(net->stats));
2888                 return &net->stats;
2889         }
2890
2891         ifp = dhd->iflist[ifidx];
2892         ASSERT(dhd && ifp);
2893
2894         if (dhd->pub.up) {
2895                 /* Use the protocol to get dongle stats */
2896                 dhd_prot_dstats(&dhd->pub);
2897         }
2898         return &ifp->stats;
2899 }
2900
2901 static int
2902 dhd_watchdog_thread(void *data)
2903 {
2904         tsk_ctl_t *tsk = (tsk_ctl_t *)data;
2905         dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
2906         /* This thread doesn't need any user-level access,
2907          * so get rid of all our resources
2908          */
2909         if (dhd_watchdog_prio > 0) {
2910                 struct sched_param param;
2911                 param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)?
2912                         dhd_watchdog_prio:(MAX_RT_PRIO-1);
2913                 setScheduler(current, SCHED_FIFO, &param);
2914         }
2915
2916         while (1)
2917                 if (down_interruptible (&tsk->sema) == 0) {
2918                         unsigned long flags;
2919                         unsigned long jiffies_at_start = jiffies;
2920                         unsigned long time_lapse;
2921
2922                         SMP_RD_BARRIER_DEPENDS();
2923                         if (tsk->terminated) {
2924                                 break;
2925                         }
2926
2927                         if (dhd->pub.dongle_reset == FALSE) {
2928                                 DHD_TIMER(("%s:\n", __FUNCTION__));
2929
2930                                 /* Call the bus module watchdog */
2931                                 dhd_bus_watchdog(&dhd->pub);
2932
2933
2934                                 DHD_GENERAL_LOCK(&dhd->pub, flags);
2935                                 /* Count the tick for reference */
2936                                 dhd->pub.tickcnt++;
2937                                 time_lapse = jiffies - jiffies_at_start;
2938
2939                                 /* Reschedule the watchdog */
2940                                 if (dhd->wd_timer_valid)
2941                                         mod_timer(&dhd->timer,
2942                                             jiffies +
2943                                             msecs_to_jiffies(dhd_watchdog_ms) -
2944                                             min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse));
2945                                         DHD_GENERAL_UNLOCK(&dhd->pub, flags);
2946                                 }
2947                 } else {
2948                         break;
2949         }
2950
2951         complete_and_exit(&tsk->completed, 0);
2952 }
2953
2954 static void dhd_watchdog(ulong data)
2955 {
2956         dhd_info_t *dhd = (dhd_info_t *)data;
2957         unsigned long flags;
2958
2959         if (dhd->pub.dongle_reset) {
2960                 return;
2961         }
2962
2963         if (dhd->thr_wdt_ctl.thr_pid >= 0) {
2964                 up(&dhd->thr_wdt_ctl.sema);
2965                 return;
2966         }
2967
2968         /* Call the bus module watchdog */
2969         dhd_bus_watchdog(&dhd->pub);
2970
2971         DHD_GENERAL_LOCK(&dhd->pub, flags);
2972         /* Count the tick for reference */
2973         dhd->pub.tickcnt++;
2974
2975         /* Reschedule the watchdog */
2976         if (dhd->wd_timer_valid)
2977                 mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms));
2978         DHD_GENERAL_UNLOCK(&dhd->pub, flags);
2979
2980 }
2981
2982 #ifdef ENABLE_ADAPTIVE_SCHED
2983 static void
2984 dhd_sched_policy(int prio)
2985 {
2986         struct sched_param param;
2987         if (cpufreq_quick_get(0) <= CUSTOM_CPUFREQ_THRESH) {
2988                 param.sched_priority = 0;
2989                 setScheduler(current, SCHED_NORMAL, &param);
2990         } else {
2991                 if (get_scheduler_policy(current) != SCHED_FIFO) {
2992                         param.sched_priority = DHD_DEFAULT_RT_PRIORITY;
2993                         setScheduler(current, SCHED_FIFO, &param);
2994                 }
2995         }
2996 }
2997 #endif /* ENABLE_ADAPTIVE_SCHED */
2998 #ifdef DEBUG_CPU_FREQ
2999 static int dhd_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
3000 {
3001         dhd_info_t *dhd = container_of(nb, struct dhd_info, freq_trans);
3002         struct cpufreq_freqs *freq = data;
3003         if (dhd) {
3004                 if (!dhd->new_freq)
3005                         goto exit;
3006                 if (val == CPUFREQ_POSTCHANGE) {
3007                         DHD_ERROR(("cpu freq is changed to %u kHZ on CPU %d\n",
3008                                 freq->new, freq->cpu));
3009                         *per_cpu_ptr(dhd->new_freq, freq->cpu) = freq->new;
3010                 }
3011         }
3012 exit:
3013         return 0;
3014 }
3015 #endif /* DEBUG_CPU_FREQ */
3016 static int
3017 dhd_dpc_thread(void *data)
3018 {
3019         unsigned long timeout;
3020         unsigned int loopcnt, count;
3021         tsk_ctl_t *tsk = (tsk_ctl_t *)data;
3022         dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
3023
3024         /* This thread doesn't need any user-level access,
3025          * so get rid of all our resources
3026          */
3027         if (dhd_dpc_prio > 0)
3028         {
3029                 struct sched_param param;
3030                 param.sched_priority = DHD_DEFAULT_RT_PRIORITY;
3031                 setScheduler(current, SCHED_FIFO, &param);
3032         }
3033
3034 #ifdef CUSTOM_DPC_CPUCORE
3035         set_cpus_allowed_ptr(current, cpumask_of(CUSTOM_DPC_CPUCORE));
3036 #endif
3037 #ifdef CUSTOM_SET_CPUCORE
3038         dhd->pub.current_dpc = current;
3039 #endif /* CUSTOM_SET_CPUCORE */
3040
3041         /* Run until signal received */
3042         while (1) {
3043                 if (!binary_sema_down(tsk)) {
3044 #ifdef ENABLE_ADAPTIVE_SCHED
3045                         dhd_sched_policy(dhd_dpc_prio);
3046 #endif /* ENABLE_ADAPTIVE_SCHED */
3047                         SMP_RD_BARRIER_DEPENDS();
3048                         if (tsk->terminated) {
3049                                 break;
3050                         }
3051
3052                         /* Call bus dpc unless it indicated down (then clean stop) */
3053                         if (dhd->pub.busstate != DHD_BUS_DOWN) {
3054                                 dhd_os_wd_timer_extend(&dhd->pub, TRUE);
3055                                 timeout = jiffies + msecs_to_jiffies(100);
3056                                 loopcnt = 0;
3057                                 count = 0;
3058                                 /* DPC_CAPTURE(); */
3059                                 while (dhd_bus_dpc(dhd->pub.bus)) {
3060                                         ++loopcnt;
3061                                         if (time_after(jiffies, timeout) &&
3062                                                 (loopcnt % 1000 == 0)) {
3063                                                 count++;
3064                                                 timeout = jiffies +
3065                                                         msecs_to_jiffies(100);
3066                                         }
3067                                         /* process all data */
3068                                 }
3069                                 if (count)
3070                                         DHD_ERROR(("%s is consuming too much time"
3071                                                 " Looped %u times for 1000 iterations in 100ms timeout\n",
3072                                                 __func__, count));
3073                                 dhd_os_wd_timer_extend(&dhd->pub, FALSE);
3074                                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3075
3076                         } else {
3077                                 if (dhd->pub.up)
3078                                         dhd_bus_stop(dhd->pub.bus, TRUE);
3079                                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3080                         }
3081                 }
3082                 else
3083                         break;
3084         }
3085
3086         complete_and_exit(&tsk->completed, 0);
3087 }
3088
3089 static int
3090 dhd_rxf_thread(void *data)
3091 {
3092         tsk_ctl_t *tsk = (tsk_ctl_t *)data;
3093         dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
3094 #if defined(WAIT_DEQUEUE)
3095 #define RXF_WATCHDOG_TIME 250 /* BARK_TIME(1000) /  */
3096         ulong watchdogTime = OSL_SYSUPTIME(); /* msec */
3097 #endif
3098         dhd_pub_t *pub = &dhd->pub;
3099
3100         /* This thread doesn't need any user-level access,
3101          * so get rid of all our resources
3102          */
3103         if (dhd_rxf_prio > 0)
3104         {
3105                 struct sched_param param;
3106                 param.sched_priority = DHD_DEFAULT_RT_PRIORITY;
3107                 setScheduler(current, SCHED_FIFO, &param);
3108         }
3109
3110         DAEMONIZE("dhd_rxf");
3111         /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below  */
3112
3113         /*  signal: thread has started */
3114         complete(&tsk->completed);
3115 #ifdef CUSTOM_SET_CPUCORE
3116         dhd->pub.current_rxf = current;
3117 #endif /* CUSTOM_SET_CPUCORE */
3118
3119         /* Run until signal received */
3120         while (1) {
3121                 if (down_interruptible(&tsk->sema) == 0) {
3122                         void *skb;
3123 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
3124                         ulong flags;
3125 #endif
3126 #ifdef ENABLE_ADAPTIVE_SCHED
3127                         dhd_sched_policy(dhd_rxf_prio);
3128 #endif /* ENABLE_ADAPTIVE_SCHED */
3129
3130                         SMP_RD_BARRIER_DEPENDS();
3131
3132                         if (tsk->terminated) {
3133                                 break;
3134                         }
3135                         skb = dhd_rxf_dequeue(pub);
3136
3137                         if (skb == NULL) {
3138                                 continue;
3139                         }
3140                         while (skb) {
3141                                 void *skbnext = PKTNEXT(pub->osh, skb);
3142                                 PKTSETNEXT(pub->osh, skb, NULL);
3143
3144 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
3145                                 netif_rx_ni(skb);
3146 #else
3147                                 netif_rx(skb);
3148                                 local_irq_save(flags);
3149                                 RAISE_RX_SOFTIRQ();
3150                                 local_irq_restore(flags);
3151
3152 #endif
3153                                 skb = skbnext;
3154                         }
3155 #if defined(WAIT_DEQUEUE)
3156                         if (OSL_SYSUPTIME() - watchdogTime > RXF_WATCHDOG_TIME) {
3157                                 OSL_SLEEP(1);
3158                                 watchdogTime = OSL_SYSUPTIME();
3159                         }
3160 #endif
3161
3162                         DHD_OS_WAKE_UNLOCK(pub);
3163                 }
3164                 else
3165                         break;
3166         }
3167
3168         complete_and_exit(&tsk->completed, 0);
3169 }
3170
3171 #ifdef BCMPCIE
3172 void dhd_dpc_kill(dhd_pub_t *dhdp)
3173 {
3174         dhd_info_t *dhd;
3175
3176         if (!dhdp)
3177                 return;
3178
3179         dhd = dhdp->info;
3180
3181         if (!dhd)
3182                 return;
3183
3184         tasklet_kill(&dhd->tasklet);
3185         DHD_ERROR(("%s: tasklet disabled\n", __FUNCTION__));
3186 }
3187 #endif /* BCMPCIE */
3188
3189 static void
3190 dhd_dpc(ulong data)
3191 {
3192         dhd_info_t *dhd;
3193
3194         dhd = (dhd_info_t *)data;
3195
3196         /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c]
3197          * down below , wake lock is set,
3198          * the tasklet is initialized in dhd_attach()
3199          */
3200         /* Call bus dpc unless it indicated down (then clean stop) */
3201         if (dhd->pub.busstate != DHD_BUS_DOWN) {
3202                 if (dhd_bus_dpc(dhd->pub.bus))
3203                         tasklet_schedule(&dhd->tasklet);
3204                 else
3205                         DHD_OS_WAKE_UNLOCK(&dhd->pub);
3206         } else {
3207                 dhd_bus_stop(dhd->pub.bus, TRUE);
3208                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3209         }
3210 }
3211
3212 void
3213 dhd_sched_dpc(dhd_pub_t *dhdp)
3214 {
3215         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
3216
3217         DHD_OS_WAKE_LOCK(dhdp);
3218         if (dhd->thr_dpc_ctl.thr_pid >= 0) {
3219                 /* If the semaphore does not get up,
3220                 * wake unlock should be done here
3221                 */
3222                 if (!binary_sema_up(&dhd->thr_dpc_ctl))
3223                         DHD_OS_WAKE_UNLOCK(dhdp);
3224                 return;
3225         } else {
3226                 tasklet_schedule(&dhd->tasklet);
3227         }
3228 }
3229
3230 static void
3231 dhd_sched_rxf(dhd_pub_t *dhdp, void *skb)
3232 {
3233         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
3234 #ifdef RXF_DEQUEUE_ON_BUSY
3235         int ret = BCME_OK;
3236         int retry = 2;
3237 #endif /* RXF_DEQUEUE_ON_BUSY */
3238
3239         DHD_OS_WAKE_LOCK(dhdp);
3240
3241         DHD_TRACE(("dhd_sched_rxf: Enter\n"));
3242 #ifdef RXF_DEQUEUE_ON_BUSY
3243         do {
3244                 ret = dhd_rxf_enqueue(dhdp, skb);
3245                 if (ret == BCME_OK || ret == BCME_ERROR)
3246                         break;
3247                 else
3248                         OSL_SLEEP(50); /* waiting for dequeueing */
3249         } while (retry-- > 0);
3250
3251         if (retry <= 0 && ret == BCME_BUSY) {
3252                 void *skbp = skb;
3253
3254                 while (skbp) {
3255                         void *skbnext = PKTNEXT(dhdp->osh, skbp);
3256                         PKTSETNEXT(dhdp->osh, skbp, NULL);
3257                         netif_rx_ni(skbp);
3258                         skbp = skbnext;
3259                 }
3260                 DHD_ERROR(("send skb to kernel backlog without rxf_thread\n"));
3261         }
3262         else {
3263                 if (dhd->thr_rxf_ctl.thr_pid >= 0) {
3264                         up(&dhd->thr_rxf_ctl.sema);
3265                 }
3266         }
3267 #else /* RXF_DEQUEUE_ON_BUSY */
3268         do {
3269                 if (dhd_rxf_enqueue(dhdp, skb) == BCME_OK)
3270                         break;
3271         } while (1);
3272         if (dhd->thr_rxf_ctl.thr_pid >= 0) {
3273                 up(&dhd->thr_rxf_ctl.sema);
3274         }
3275         return;
3276 #endif /* RXF_DEQUEUE_ON_BUSY */
3277 }
3278
3279 #ifdef TOE
3280 /* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */
3281 static int
3282 dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol)
3283 {
3284         wl_ioctl_t ioc;
3285         char buf[32];
3286         int ret;
3287
3288         memset(&ioc, 0, sizeof(ioc));
3289
3290         ioc.cmd = WLC_GET_VAR;
3291         ioc.buf = buf;
3292         ioc.len = (uint)sizeof(buf);
3293         ioc.set = FALSE;
3294
3295         strncpy(buf, "toe_ol", sizeof(buf) - 1);
3296         buf[sizeof(buf) - 1] = '\0';
3297         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
3298                 /* Check for older dongle image that doesn't support toe_ol */
3299                 if (ret == -EIO) {
3300                         DHD_ERROR(("%s: toe not supported by device\n",
3301                                 dhd_ifname(&dhd->pub, ifidx)));
3302                         return -EOPNOTSUPP;
3303                 }
3304
3305                 DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
3306                 return ret;
3307         }
3308
3309         memcpy(toe_ol, buf, sizeof(uint32));
3310         return 0;
3311 }
3312
3313 /* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */
3314 static int
3315 dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol)
3316 {
3317         wl_ioctl_t ioc;
3318         char buf[32];
3319         int toe, ret;
3320
3321         memset(&ioc, 0, sizeof(ioc));
3322
3323         ioc.cmd = WLC_SET_VAR;
3324         ioc.buf = buf;
3325         ioc.len = (uint)sizeof(buf);
3326         ioc.set = TRUE;
3327
3328         /* Set toe_ol as requested */
3329
3330         strncpy(buf, "toe_ol", sizeof(buf) - 1);
3331         buf[sizeof(buf) - 1] = '\0';
3332         memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32));
3333
3334         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
3335                 DHD_ERROR(("%s: could not set toe_ol: ret=%d\n",
3336                         dhd_ifname(&dhd->pub, ifidx), ret));
3337                 return ret;
3338         }
3339
3340         /* Enable toe globally only if any components are enabled. */
3341
3342         toe = (toe_ol != 0);
3343
3344         strcpy(buf, "toe");
3345         memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32));
3346
3347         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
3348                 DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
3349                 return ret;
3350         }
3351
3352         return 0;
3353 }
3354 #endif /* TOE */
3355
3356 #if defined(WL_CFG80211)
3357 void dhd_set_scb_probe(dhd_pub_t *dhd)
3358 {
3359 #define NUM_SCB_MAX_PROBE 3
3360         int ret = 0;
3361         wl_scb_probe_t scb_probe;
3362         char iovbuf[WL_EVENTING_MASK_LEN + 12];
3363
3364         memset(&scb_probe, 0, sizeof(wl_scb_probe_t));
3365
3366         if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)
3367                 return;
3368
3369         bcm_mkiovar("scb_probe", NULL, 0, iovbuf, sizeof(iovbuf));
3370
3371         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
3372                 DHD_ERROR(("%s: GET max_scb_probe failed\n", __FUNCTION__));
3373
3374         memcpy(&scb_probe, iovbuf, sizeof(wl_scb_probe_t));
3375
3376         scb_probe.scb_max_probe = NUM_SCB_MAX_PROBE;
3377
3378         bcm_mkiovar("scb_probe", (char *)&scb_probe,
3379                 sizeof(wl_scb_probe_t), iovbuf, sizeof(iovbuf));
3380         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
3381                 DHD_ERROR(("%s: max_scb_probe setting failed\n", __FUNCTION__));
3382 #undef NUM_SCB_MAX_PROBE
3383         return;
3384 }
3385 #endif /* WL_CFG80211 */
3386
3387 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
3388 static void
3389 dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
3390 {
3391         dhd_info_t *dhd = DHD_DEV_INFO(net);
3392
3393         snprintf(info->driver, sizeof(info->driver), "wl");
3394         snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version);
3395 }
3396
3397 struct ethtool_ops dhd_ethtool_ops = {
3398         .get_drvinfo = dhd_ethtool_get_drvinfo
3399 };
3400 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
3401
3402
3403 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
3404 static int
3405 dhd_ethtool(dhd_info_t *dhd, void *uaddr)
3406 {
3407         struct ethtool_drvinfo info;
3408         char drvname[sizeof(info.driver)];
3409         uint32 cmd;
3410 #ifdef TOE
3411         struct ethtool_value edata;
3412         uint32 toe_cmpnt, csum_dir;
3413         int ret;
3414 #endif
3415
3416         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3417
3418         /* all ethtool calls start with a cmd word */
3419         if (copy_from_user(&cmd, uaddr, sizeof (uint32)))
3420                 return -EFAULT;
3421
3422         switch (cmd) {
3423         case ETHTOOL_GDRVINFO:
3424                 /* Copy out any request driver name */
3425                 if (copy_from_user(&info, uaddr, sizeof(info)))
3426                         return -EFAULT;
3427                 strncpy(drvname, info.driver, sizeof(info.driver));
3428                 drvname[sizeof(info.driver)-1] = '\0';
3429
3430                 /* clear struct for return */
3431                 memset(&info, 0, sizeof(info));
3432                 info.cmd = cmd;
3433
3434                 /* if dhd requested, identify ourselves */
3435                 if (strcmp(drvname, "?dhd") == 0) {
3436                         snprintf(info.driver, sizeof(info.driver), "dhd");
3437                         strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1);
3438                         info.version[sizeof(info.version) - 1] = '\0';
3439                 }
3440
3441                 /* otherwise, require dongle to be up */
3442                 else if (!dhd->pub.up) {
3443                         DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__));
3444                         return -ENODEV;
3445                 }
3446
3447                 /* finally, report dongle driver type */
3448                 else if (dhd->pub.iswl)
3449                         snprintf(info.driver, sizeof(info.driver), "wl");
3450                 else
3451                         snprintf(info.driver, sizeof(info.driver), "xx");
3452
3453                 snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version);
3454                 if (copy_to_user(uaddr, &info, sizeof(info)))
3455                         return -EFAULT;
3456                 DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__,
3457                          (int)sizeof(drvname), drvname, info.driver));
3458                 break;
3459
3460 #ifdef TOE
3461         /* Get toe offload components from dongle */
3462         case ETHTOOL_GRXCSUM:
3463         case ETHTOOL_GTXCSUM:
3464                 if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
3465                         return ret;
3466
3467                 csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
3468
3469                 edata.cmd = cmd;
3470                 edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
3471
3472                 if (copy_to_user(uaddr, &edata, sizeof(edata)))
3473                         return -EFAULT;
3474                 break;
3475
3476         /* Set toe offload components in dongle */
3477         case ETHTOOL_SRXCSUM:
3478         case ETHTOOL_STXCSUM:
3479                 if (copy_from_user(&edata, uaddr, sizeof(edata)))
3480                         return -EFAULT;
3481
3482                 /* Read the current settings, update and write back */
3483                 if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
3484                         return ret;
3485
3486                 csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
3487
3488                 if (edata.data != 0)
3489                         toe_cmpnt |= csum_dir;
3490                 else
3491                         toe_cmpnt &= ~csum_dir;
3492
3493                 if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0)
3494                         return ret;
3495
3496                 /* If setting TX checksum mode, tell Linux the new mode */
3497                 if (cmd == ETHTOOL_STXCSUM) {
3498                         if (edata.data)
3499                                 dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM;
3500                         else
3501                                 dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM;
3502                 }
3503
3504                 break;
3505 #endif /* TOE */
3506
3507         default:
3508                 return -EOPNOTSUPP;
3509         }
3510
3511         return 0;
3512 }
3513 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
3514
3515 static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
3516 {
3517         dhd_info_t *dhd;
3518
3519         if (!dhdp) {
3520                 DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
3521                 return FALSE;
3522         }
3523
3524         if (!dhdp->up)
3525                 return FALSE;
3526
3527         dhd = (dhd_info_t *)dhdp->info;
3528 #if !defined(BCMPCIE)
3529         if (dhd->thr_dpc_ctl.thr_pid < 0) {
3530                 DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__));
3531                 return FALSE;
3532         }
3533 #endif 
3534
3535         if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) ||
3536                 ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) {
3537                 DHD_ERROR(("%s: Event HANG send up due to  re=%d te=%d e=%d s=%d\n", __FUNCTION__,
3538                         dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate));
3539                 net_os_send_hang_message(net);
3540                 return TRUE;
3541         }
3542         return FALSE;
3543 }
3544
3545 int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_buf)
3546 {
3547         int bcmerror = BCME_OK;
3548         int buflen = 0;
3549         struct net_device *net;
3550
3551         net = dhd_idx2net(pub, ifidx);
3552         if (!net) {
3553                 bcmerror = BCME_BADARG;
3554                 goto done;
3555         }
3556
3557         if (data_buf)
3558                 buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN);
3559
3560         /* check for local dhd ioctl and handle it */
3561         if (ioc->driver == DHD_IOCTL_MAGIC) {
3562                 bcmerror = dhd_ioctl((void *)pub, ioc, data_buf, buflen);
3563                 if (bcmerror)
3564                         pub->bcmerror = bcmerror;
3565                 goto done;
3566         }
3567
3568         /* send to dongle (must be up, and wl). */
3569         if (pub->busstate != DHD_BUS_DATA) {
3570                 bcmerror = BCME_DONGLE_DOWN;
3571                 goto done;
3572         }
3573
3574         if (!pub->iswl) {
3575                 bcmerror = BCME_DONGLE_DOWN;
3576                 goto done;
3577         }
3578
3579         /*
3580          * Flush the TX queue if required for proper message serialization:
3581          * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to
3582          * prevent M4 encryption and
3583          * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to
3584          * prevent disassoc frame being sent before WPS-DONE frame.
3585          */
3586         if (ioc->cmd == WLC_SET_KEY ||
3587             (ioc->cmd == WLC_SET_VAR && data_buf != NULL &&
3588              strncmp("wsec_key", data_buf, 9) == 0) ||
3589             (ioc->cmd == WLC_SET_VAR && data_buf != NULL &&
3590              strncmp("bsscfg:wsec_key", data_buf, 15) == 0) ||
3591             ioc->cmd == WLC_DISASSOC)
3592                 dhd_wait_pend8021x(net);
3593
3594 #ifdef WLMEDIA_HTSF
3595         if (data_buf) {
3596                 /*  short cut wl ioctl calls here  */
3597                 if (strcmp("htsf", data_buf) == 0) {
3598                         dhd_ioctl_htsf_get(dhd, 0);
3599                         return BCME_OK;
3600                 }
3601
3602                 if (strcmp("htsflate", data_buf) == 0) {
3603                         if (ioc->set) {
3604                                 memset(ts, 0, sizeof(tstamp_t)*TSMAX);
3605                                 memset(&maxdelayts, 0, sizeof(tstamp_t));
3606                                 maxdelay = 0;
3607                                 tspktcnt = 0;
3608                                 maxdelaypktno = 0;
3609                                 memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
3610                                 memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
3611                                 memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
3612                                 memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
3613                         } else {
3614                                 dhd_dump_latency();
3615                         }
3616                         return BCME_OK;
3617                 }
3618                 if (strcmp("htsfclear", data_buf) == 0) {
3619                         memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
3620                         memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
3621                         memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
3622                         memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
3623                         htsf_seqnum = 0;
3624                         return BCME_OK;
3625                 }
3626                 if (strcmp("htsfhis", data_buf) == 0) {
3627                         dhd_dump_htsfhisto(&vi_d1, "H to D");
3628                         dhd_dump_htsfhisto(&vi_d2, "D to D");
3629                         dhd_dump_htsfhisto(&vi_d3, "D to H");
3630                         dhd_dump_htsfhisto(&vi_d4, "H to H");
3631                         return BCME_OK;
3632                 }
3633                 if (strcmp("tsport", data_buf) == 0) {
3634                         if (ioc->set) {
3635                                 memcpy(&tsport, data_buf + 7, 4);
3636                         } else {
3637                                 DHD_ERROR(("current timestamp port: %d \n", tsport));
3638                         }
3639                         return BCME_OK;
3640                 }
3641         }
3642 #endif /* WLMEDIA_HTSF */
3643
3644         if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) &&
3645                 data_buf != NULL && strncmp("rpc_", data_buf, 4) == 0) {
3646 #ifdef BCM_FD_AGGR
3647                 bcmerror = dhd_fdaggr_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen);
3648 #else
3649                 bcmerror = BCME_UNSUPPORTED;
3650 #endif
3651                 goto done;
3652         }
3653         bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen);
3654
3655 done:
3656         dhd_check_hang(net, pub, bcmerror);
3657
3658         return bcmerror;
3659 }
3660
3661 static int
3662 dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
3663 {
3664         dhd_info_t *dhd = DHD_DEV_INFO(net);
3665         dhd_ioctl_t ioc;
3666         int bcmerror = 0;
3667         int ifidx;
3668         int ret;
3669         void *local_buf = NULL;
3670         u16 buflen = 0;
3671
3672         DHD_OS_WAKE_LOCK(&dhd->pub);
3673         DHD_PERIM_LOCK(&dhd->pub);
3674
3675         /* Interface up check for built-in type */
3676         if (!dhd_download_fw_on_driverload && dhd->pub.up == 0) {
3677                 DHD_ERROR(("%s: Interface is down \n", __FUNCTION__));
3678                 DHD_PERIM_UNLOCK(&dhd->pub);
3679                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3680                 return BCME_NOTUP;
3681         }
3682
3683         /* send to dongle only if we are not waiting for reload already */
3684         if (dhd->pub.hang_was_sent) {
3685                 DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__));
3686                 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS);
3687                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3688                 return OSL_ERROR(BCME_DONGLE_DOWN);
3689         }
3690
3691         ifidx = dhd_net2idx(dhd, net);
3692         DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd));
3693
3694         if (ifidx == DHD_BAD_IF) {
3695                 DHD_ERROR(("%s: BAD IF\n", __FUNCTION__));
3696                 DHD_PERIM_UNLOCK(&dhd->pub);
3697                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3698                 return -1;
3699         }
3700
3701 #if defined(WL_WIRELESS_EXT)
3702         /* linux wireless extensions */
3703         if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {
3704                 /* may recurse, do NOT lock */
3705                 ret = wl_iw_ioctl(net, ifr, cmd);
3706                 DHD_PERIM_UNLOCK(&dhd->pub);
3707                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3708                 return ret;
3709         }
3710 #endif /* defined(WL_WIRELESS_EXT) */
3711
3712 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
3713         if (cmd == SIOCETHTOOL) {
3714                 ret = dhd_ethtool(dhd, (void*)ifr->ifr_data);
3715                 DHD_PERIM_UNLOCK(&dhd->pub);
3716                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3717                 return ret;
3718         }
3719 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
3720
3721         if (cmd == SIOCDEVPRIVATE+1) {
3722                 ret = wl_android_priv_cmd(net, ifr, cmd);
3723                 dhd_check_hang(net, &dhd->pub, ret);
3724                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3725                 return ret;
3726         }
3727
3728         if (cmd != SIOCDEVPRIVATE) {
3729                 DHD_PERIM_UNLOCK(&dhd->pub);
3730                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3731                 return -EOPNOTSUPP;
3732         }
3733
3734         memset(&ioc, 0, sizeof(ioc));
3735
3736 #ifdef CONFIG_COMPAT
3737         if (is_compat_task()) {
3738                 compat_wl_ioctl_t compat_ioc;
3739                 if (copy_from_user(&compat_ioc, ifr->ifr_data, sizeof(compat_wl_ioctl_t))) {
3740                         bcmerror = BCME_BADADDR;
3741                         goto done;
3742                 }
3743                 ioc.cmd = compat_ioc.cmd;
3744                 ioc.buf = compat_ptr(compat_ioc.buf);
3745                 ioc.len = compat_ioc.len;
3746                 ioc.set = compat_ioc.set;
3747                 ioc.used = compat_ioc.used;
3748                 ioc.needed = compat_ioc.needed;
3749                 /* To differentiate between wl and dhd read 4 more byes */
3750                 if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t),
3751                         sizeof(uint)) != 0)) {
3752                         bcmerror = BCME_BADADDR;
3753                         goto done;
3754                 }
3755         } else
3756 #endif /* CONFIG_COMPAT */
3757         {
3758                 /* Copy the ioc control structure part of ioctl request */
3759                 if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) {
3760                         bcmerror = BCME_BADADDR;
3761                         goto done;
3762                 }
3763
3764                 /* To differentiate between wl and dhd read 4 more byes */
3765                 if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t),
3766                         sizeof(uint)) != 0)) {
3767                         bcmerror = BCME_BADADDR;
3768                         goto done;
3769                 }
3770         }
3771
3772         if (!capable(CAP_NET_ADMIN)) {
3773                 bcmerror = BCME_EPERM;
3774                 goto done;
3775         }
3776
3777         if (ioc.len > 0) {
3778                 buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN);
3779                 if (!(local_buf = MALLOC(dhd->pub.osh, buflen+1))) {
3780                         bcmerror = BCME_NOMEM;
3781                         goto done;
3782                 }
3783
3784                 DHD_PERIM_UNLOCK(&dhd->pub);
3785                 if (copy_from_user(local_buf, ioc.buf, buflen)) {
3786                         DHD_PERIM_LOCK(&dhd->pub);
3787                         bcmerror = BCME_BADADDR;
3788                         goto done;
3789                 }
3790                 DHD_PERIM_LOCK(&dhd->pub);
3791
3792                 *(char *)(local_buf + buflen) = '\0';
3793         }
3794
3795         bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf);
3796
3797         if (!bcmerror && buflen && local_buf && ioc.buf) {
3798                 DHD_PERIM_UNLOCK(&dhd->pub);
3799                 if (copy_to_user(ioc.buf, local_buf, buflen))
3800                         bcmerror = -EFAULT;
3801                 DHD_PERIM_LOCK(&dhd->pub);
3802         }
3803
3804 done:
3805         if (local_buf)
3806                 MFREE(dhd->pub.osh, local_buf, buflen+1);
3807
3808         DHD_PERIM_UNLOCK(&dhd->pub);
3809         DHD_OS_WAKE_UNLOCK(&dhd->pub);
3810
3811         return OSL_ERROR(bcmerror);
3812 }
3813
3814
3815
3816 static int
3817 dhd_stop(struct net_device *net)
3818 {
3819         int ifidx = 0;
3820         dhd_info_t *dhd = DHD_DEV_INFO(net);
3821         DHD_OS_WAKE_LOCK(&dhd->pub);
3822         DHD_PERIM_LOCK(&dhd->pub);
3823         DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net));
3824         if (dhd->pub.up == 0) {
3825                 goto exit;
3826         }
3827
3828         dhd_if_flush_sta(DHD_DEV_IFP(net));
3829
3830
3831         ifidx = dhd_net2idx(dhd, net);
3832         BCM_REFERENCE(ifidx);
3833
3834         /* Set state and stop OS transmissions */
3835         netif_stop_queue(net);
3836         dhd->pub.up = 0;
3837
3838 #ifdef WL_CFG80211
3839         if (ifidx == 0) {
3840                 wl_cfg80211_down(NULL);
3841
3842                 /*
3843                  * For CFG80211: Clean up all the left over virtual interfaces
3844                  * when the primary Interface is brought down. [ifconfig wlan0 down]
3845                  */
3846                 if (!dhd_download_fw_on_driverload) {
3847                         if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) &&
3848                                 (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
3849                                 int i;
3850
3851                                 dhd_net_if_lock_local(dhd);
3852                                 for (i = 1; i < DHD_MAX_IFS; i++)
3853                                         dhd_remove_if(&dhd->pub, i, FALSE);
3854                                 dhd_net_if_unlock_local(dhd);
3855                         }
3856                 }
3857         }
3858 #endif /* WL_CFG80211 */
3859
3860 #ifdef PROP_TXSTATUS
3861         dhd_wlfc_cleanup(&dhd->pub, NULL, 0);
3862 #endif
3863         /* Stop the protocol module */
3864         dhd_prot_stop(&dhd->pub);
3865
3866         OLD_MOD_DEC_USE_COUNT;
3867 exit:
3868 #if defined(WL_CFG80211)
3869         if (ifidx == 0 && !dhd_download_fw_on_driverload)
3870                 wl_android_wifi_off(net);
3871 #endif 
3872         dhd->pub.rxcnt_timeout = 0;
3873         dhd->pub.txcnt_timeout = 0;
3874
3875         dhd->pub.hang_was_sent = 0;
3876
3877         /* Clear country spec for for built-in type driver */
3878         if (!dhd_download_fw_on_driverload) {
3879                 dhd->pub.dhd_cspec.country_abbrev[0] = 0x00;
3880                 dhd->pub.dhd_cspec.rev = 0;
3881                 dhd->pub.dhd_cspec.ccode[0] = 0x00;
3882         }
3883
3884         DHD_PERIM_UNLOCK(&dhd->pub);
3885         DHD_OS_WAKE_UNLOCK(&dhd->pub);
3886         return 0;
3887 }
3888
3889 #if defined(WL_CFG80211) && (defined(USE_INITIAL_2G_SCAN) || \
3890         defined(USE_INITIAL_SHORT_DWELL_TIME))
3891 extern bool g_first_broadcast_scan;
3892 #endif /* OEM_ANDROID && WL_CFG80211 && (USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME) */
3893
3894 #ifdef WL11U
3895 static int dhd_interworking_enable(dhd_pub_t *dhd)
3896 {
3897         char iovbuf[WLC_IOCTL_SMLEN];
3898         uint32 enable = true;
3899         int ret = BCME_OK;
3900
3901         bcm_mkiovar("interworking", (char *)&enable, sizeof(enable), iovbuf, sizeof(iovbuf));
3902         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
3903                 DHD_ERROR(("%s: enableing interworking failed, ret=%d\n", __FUNCTION__, ret));
3904         }
3905
3906         if (ret == BCME_OK) {
3907                 /* basic capabilities for HS20 REL2 */
3908                 uint32 cap = WL_WNM_BSSTRANS | WL_WNM_NOTIF;
3909                 bcm_mkiovar("wnm", (char *)&cap, sizeof(cap), iovbuf, sizeof(iovbuf));
3910                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
3911                         iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
3912                         DHD_ERROR(("%s: failed to set WNM info, ret=%d\n", __FUNCTION__, ret));
3913                 }
3914         }
3915
3916         return ret;
3917 }
3918 #endif /* WL11u */
3919
3920 static int
3921 dhd_open(struct net_device *net)
3922 {
3923         dhd_info_t *dhd = DHD_DEV_INFO(net);
3924 #ifdef TOE
3925         uint32 toe_ol;
3926 #endif
3927         int ifidx;
3928         int32 ret = 0;
3929
3930
3931
3932
3933         DHD_OS_WAKE_LOCK(&dhd->pub);
3934         DHD_PERIM_LOCK(&dhd->pub);
3935         dhd->pub.dongle_trap_occured = 0;
3936         dhd->pub.hang_was_sent = 0;
3937
3938 #if !defined(WL_CFG80211)
3939         /*
3940          * Force start if ifconfig_up gets called before START command
3941          *  We keep WEXT's wl_control_wl_start to provide backward compatibility
3942          *  This should be removed in the future
3943          */
3944         ret = wl_control_wl_start(net);
3945         if (ret != 0) {
3946                 DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
3947                 ret = -1;
3948                 goto exit;
3949         }
3950
3951 #endif 
3952
3953         ifidx = dhd_net2idx(dhd, net);
3954         DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
3955
3956         if (ifidx < 0) {
3957                 DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__));
3958                 ret = -1;
3959                 goto exit;
3960         }
3961
3962         if (!dhd->iflist[ifidx]) {
3963                 DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__));
3964                 ret = -1;
3965                 goto exit;
3966         }
3967
3968         if (ifidx == 0) {
3969                 atomic_set(&dhd->pend_8021x_cnt, 0);
3970 #if defined(WL_CFG80211)
3971                 if (!dhd_download_fw_on_driverload) {
3972                         DHD_ERROR(("\n%s\n", dhd_version));
3973 #if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
3974                         g_first_broadcast_scan = TRUE;
3975 #endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
3976                         ret = wl_android_wifi_on(net);
3977                         if (ret != 0) {
3978                                 DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n",
3979                                         __FUNCTION__, ret));
3980                                 ret = -1;
3981                                 goto exit;
3982                         }
3983                 }
3984 #endif 
3985
3986                 if (dhd->pub.busstate != DHD_BUS_DATA) {
3987
3988                         /* try to bring up bus */
3989                         DHD_PERIM_UNLOCK(&dhd->pub);
3990                         ret = dhd_bus_start(&dhd->pub);
3991                         DHD_PERIM_LOCK(&dhd->pub);
3992                         if (ret) {
3993                                 DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
3994                                 ret = -1;
3995                                 goto exit;
3996                         }
3997
3998                 }
3999
4000                 /* dhd_sync_with_dongle has been called in dhd_bus_start or wl_android_wifi_on */
4001                 memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
4002
4003 #ifdef TOE
4004                 /* Get current TOE mode from dongle */
4005                 if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0)
4006                         dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM;
4007                 else
4008                         dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM;
4009 #endif /* TOE */
4010
4011 #if defined(WL_CFG80211)
4012                 if (unlikely(wl_cfg80211_up(NULL))) {
4013                         DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
4014                         ret = -1;
4015                         goto exit;
4016                 }
4017                 dhd_set_scb_probe(&dhd->pub);
4018 #endif /* WL_CFG80211 */
4019         }
4020
4021         /* Allow transmit calls */
4022         netif_start_queue(net);
4023         dhd->pub.up = 1;
4024
4025 #ifdef BCMDBGFS
4026         dhd_dbg_init(&dhd->pub);
4027 #endif
4028
4029         OLD_MOD_INC_USE_COUNT;
4030 exit:
4031         if (ret)
4032                 dhd_stop(net);
4033
4034         DHD_PERIM_UNLOCK(&dhd->pub);
4035         DHD_OS_WAKE_UNLOCK(&dhd->pub);
4036
4037
4038         return ret;
4039 }
4040
4041 int dhd_do_driver_init(struct net_device *net)
4042 {
4043         dhd_info_t *dhd = NULL;
4044
4045         if (!net) {
4046                 DHD_ERROR(("Primary Interface not initialized \n"));
4047                 return -EINVAL;
4048         }
4049
4050
4051         /*  && defined(OEM_ANDROID) && defined(BCMSDIO) */
4052         dhd = DHD_DEV_INFO(net);
4053
4054         /* If driver is already initialized, do nothing
4055          */
4056         if (dhd->pub.busstate == DHD_BUS_DATA) {
4057                 DHD_TRACE(("Driver already Inititalized. Nothing to do"));
4058                 return 0;
4059         }
4060
4061         if (dhd_open(net) < 0) {
4062                 DHD_ERROR(("Driver Init Failed \n"));
4063                 return -1;
4064         }
4065
4066         return 0;
4067 }
4068
4069 int
4070 dhd_event_ifadd(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac)
4071 {
4072
4073 #ifdef WL_CFG80211
4074         if (wl_cfg80211_notify_ifadd(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK)
4075                 return BCME_OK;
4076 #endif
4077
4078         /* handle IF event caused by wl commands, SoftAP, WEXT and
4079          * anything else. This has to be done asynchronously otherwise
4080          * DPC will be blocked (and iovars will timeout as DPC has no chance
4081          * to read the response back)
4082          */
4083         if (ifevent->ifidx > 0) {
4084                 dhd_if_event_t *if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t));
4085
4086                 memcpy(&if_event->event, ifevent, sizeof(if_event->event));
4087                 memcpy(if_event->mac, mac, ETHER_ADDR_LEN);
4088                 strncpy(if_event->name, name, IFNAMSIZ);
4089                 if_event->name[IFNAMSIZ - 1] = '\0';
4090                 dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event,
4091                         DHD_WQ_WORK_IF_ADD, dhd_ifadd_event_handler, DHD_WORK_PRIORITY_LOW);
4092         }
4093
4094         return BCME_OK;
4095 }
4096
4097 int
4098 dhd_event_ifdel(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac)
4099 {
4100         dhd_if_event_t *if_event;
4101
4102 #ifdef WL_CFG80211
4103         if (wl_cfg80211_notify_ifdel(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK)
4104                 return BCME_OK;
4105 #endif /* WL_CFG80211 */
4106
4107         /* handle IF event caused by wl commands, SoftAP, WEXT and
4108          * anything else
4109          */
4110         if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t));
4111         memcpy(&if_event->event, ifevent, sizeof(if_event->event));
4112         memcpy(if_event->mac, mac, ETHER_ADDR_LEN);
4113         strncpy(if_event->name, name, IFNAMSIZ);
4114         if_event->name[IFNAMSIZ - 1] = '\0';
4115         dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, DHD_WQ_WORK_IF_DEL,
4116                 dhd_ifdel_event_handler, DHD_WORK_PRIORITY_LOW);
4117
4118         return BCME_OK;
4119 }
4120
4121 /* unregister and free the existing net_device interface (if any) in iflist and
4122  * allocate a new one. the slot is reused. this function does NOT register the
4123  * new interface to linux kernel. dhd_register_if does the job
4124  */
4125 struct net_device*
4126 dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name,
4127         uint8 *mac, uint8 bssidx, bool need_rtnl_lock)
4128 {
4129         dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info;
4130         dhd_if_t *ifp;
4131
4132         ASSERT(dhdinfo && (ifidx < DHD_MAX_IFS));
4133         ifp = dhdinfo->iflist[ifidx];
4134
4135         if (ifp != NULL) {
4136                 if (ifp->net != NULL) {
4137                         DHD_ERROR(("%s: free existing IF %s\n", __FUNCTION__, ifp->net->name));
4138
4139                         dhd_dev_priv_clear(ifp->net); /* clear net_device private */
4140
4141                         /* in unregister_netdev case, the interface gets freed by net->destructor
4142                          * (which is set to free_netdev)
4143                          */
4144                         if (ifp->net->reg_state == NETREG_UNINITIALIZED) {
4145                                 free_netdev(ifp->net);
4146                         } else {
4147                                 netif_stop_queue(ifp->net);
4148                                 if (need_rtnl_lock)
4149                                         unregister_netdev(ifp->net);
4150                                 else
4151                                         unregister_netdevice(ifp->net);
4152                         }
4153                         ifp->net = NULL;
4154                 }
4155         } else {
4156                 ifp = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_t));
4157                 if (ifp == NULL) {
4158                         DHD_ERROR(("%s: OOM - dhd_if_t(%zu)\n", __FUNCTION__, sizeof(dhd_if_t)));
4159                         return NULL;
4160                 }
4161         }
4162
4163         memset(ifp, 0, sizeof(dhd_if_t));
4164         ifp->info = dhdinfo;
4165         ifp->idx = ifidx;
4166         ifp->bssidx = bssidx;
4167         if (mac != NULL)
4168                 memcpy(&ifp->mac_addr, mac, ETHER_ADDR_LEN);
4169
4170         /* Allocate etherdev, including space for private structure */
4171         ifp->net = alloc_etherdev(DHD_DEV_PRIV_SIZE);
4172         if (ifp->net == NULL) {
4173                 DHD_ERROR(("%s: OOM - alloc_etherdev(%zu)\n", __FUNCTION__, sizeof(dhdinfo)));
4174                 goto fail;
4175         }
4176
4177         /* Setup the dhd interface's netdevice private structure. */
4178         dhd_dev_priv_save(ifp->net, dhdinfo, ifp, ifidx);
4179
4180         if (name && name[0]) {
4181                 strncpy(ifp->net->name, name, IFNAMSIZ);
4182                 ifp->net->name[IFNAMSIZ - 1] = '\0';
4183         }
4184 #ifdef WL_CFG80211
4185         if (ifidx == 0)
4186                 ifp->net->destructor = free_netdev;
4187         else
4188                 ifp->net->destructor = dhd_netdev_free;
4189 #else
4190         ifp->net->destructor = free_netdev;
4191 #endif /* WL_CFG80211 */
4192         strncpy(ifp->name, ifp->net->name, IFNAMSIZ);
4193         ifp->name[IFNAMSIZ - 1] = '\0';
4194         dhdinfo->iflist[ifidx] = ifp;
4195
4196 #ifdef PCIE_FULL_DONGLE
4197         /* Initialize STA info list */
4198         INIT_LIST_HEAD(&ifp->sta_list);
4199         DHD_IF_STA_LIST_LOCK_INIT(ifp);
4200 #endif /* PCIE_FULL_DONGLE */
4201
4202         return ifp->net;
4203
4204 fail:
4205         if (ifp != NULL) {
4206                 if (ifp->net != NULL) {
4207                         dhd_dev_priv_clear(ifp->net);
4208                         free_netdev(ifp->net);
4209                         ifp->net = NULL;
4210                 }
4211                 MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp));
4212                 ifp = NULL;
4213         }
4214         dhdinfo->iflist[ifidx] = NULL;
4215         return NULL;
4216 }
4217
4218 /* unregister and free the the net_device interface associated with the indexed
4219  * slot, also free the slot memory and set the slot pointer to NULL
4220  */
4221 int
4222 dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock)
4223 {
4224         dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info;
4225         dhd_if_t *ifp;
4226
4227         ifp = dhdinfo->iflist[ifidx];
4228         if (ifp != NULL) {
4229                 dhdinfo->iflist[ifidx] = NULL;
4230                 if (ifp->net != NULL) {
4231                         DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx));
4232
4233                         /* in unregister_netdev case, the interface gets freed by net->destructor
4234                          * (which is set to free_netdev)
4235                          */
4236                         if (ifp->net->reg_state == NETREG_UNINITIALIZED) {
4237                                 free_netdev(ifp->net);
4238                         } else {
4239                                 netif_stop_queue(ifp->net);
4240
4241
4242
4243                                 if (need_rtnl_lock)
4244                                         unregister_netdev(ifp->net);
4245                                 else
4246                                         unregister_netdevice(ifp->net);
4247                         }
4248                         ifp->net = NULL;
4249                 }
4250 #ifdef DHD_WMF
4251                 dhd_wmf_cleanup(dhdpub, ifidx);
4252 #endif /* DHD_WMF */
4253
4254                 dhd_if_del_sta_list(ifp);
4255
4256                 MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp));
4257
4258         }
4259
4260         return BCME_OK;
4261 }
4262
4263 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
4264 static struct net_device_ops dhd_ops_pri = {
4265         .ndo_open = dhd_open,
4266         .ndo_stop = dhd_stop,
4267         .ndo_get_stats = dhd_get_stats,
4268         .ndo_do_ioctl = dhd_ioctl_entry,
4269         .ndo_start_xmit = dhd_start_xmit,
4270         .ndo_set_mac_address = dhd_set_mac_address,
4271 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
4272         .ndo_set_rx_mode = dhd_set_multicast_list,
4273 #else
4274         .ndo_set_multicast_list = dhd_set_multicast_list,
4275 #endif
4276 };
4277
4278 static struct net_device_ops dhd_ops_virt = {
4279         .ndo_get_stats = dhd_get_stats,
4280         .ndo_do_ioctl = dhd_ioctl_entry,
4281         .ndo_start_xmit = dhd_start_xmit,
4282         .ndo_set_mac_address = dhd_set_mac_address,
4283 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
4284         .ndo_set_rx_mode = dhd_set_multicast_list,
4285 #else
4286         .ndo_set_multicast_list = dhd_set_multicast_list,
4287 #endif
4288 };
4289 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
4290
4291 #ifdef DEBUGGER
4292 extern void debugger_init(void *bus_handle);
4293 #endif
4294
4295
4296 #ifdef SHOW_LOGTRACE
4297 static char *logstrs_path = "/root/logstrs.bin";
4298 module_param(logstrs_path, charp, S_IRUGO);
4299
4300 int
4301 dhd_init_logstrs_array(dhd_event_log_t *temp)
4302 {
4303         struct file *filep = NULL;
4304         struct kstat stat;
4305         mm_segment_t fs;
4306         char *raw_fmts =  NULL;
4307         int logstrs_size = 0;
4308
4309         logstr_header_t *hdr = NULL;
4310         uint32 *lognums = NULL;
4311         char *logstrs = NULL;
4312         int ram_index = 0;
4313         char **fmts;
4314         int num_fmts = 0;
4315         uint32 i = 0;
4316         int error = 0;
4317         set_fs(KERNEL_DS);
4318         fs = get_fs();
4319         filep = filp_open(logstrs_path, O_RDONLY, 0);
4320         if (IS_ERR(filep)) {
4321                 DHD_ERROR(("Failed to open the file logstrs.bin in %s",  __FUNCTION__));
4322                 goto fail;
4323         }
4324         error = vfs_stat(logstrs_path, &stat);
4325         if (error) {
4326                 DHD_ERROR(("Failed in %s to find file stat", __FUNCTION__));
4327                 goto fail;
4328         }
4329         logstrs_size = (int) stat.size;
4330
4331         raw_fmts = kmalloc(logstrs_size, GFP_KERNEL);
4332         if (raw_fmts == NULL) {
4333                 DHD_ERROR(("Failed to allocate raw_fmts memory"));
4334                 goto fail;
4335         }
4336         if (vfs_read(filep, raw_fmts, logstrs_size, &filep->f_pos) !=   logstrs_size) {
4337                 DHD_ERROR(("Error: Log strings file read failed"));
4338                 goto fail;
4339         }
4340
4341         /* Remember header from the logstrs.bin file */
4342         hdr = (logstr_header_t *) (raw_fmts + logstrs_size -
4343                 sizeof(logstr_header_t));
4344
4345         if (hdr->log_magic == LOGSTRS_MAGIC) {
4346                 /*
4347                 * logstrs.bin start with header.
4348                 */
4349                 num_fmts =      hdr->rom_logstrs_offset / sizeof(uint32);
4350                 ram_index = (hdr->ram_lognums_offset -
4351                         hdr->rom_lognums_offset) / sizeof(uint32);
4352                 lognums = (uint32 *) &raw_fmts[hdr->rom_lognums_offset];
4353                 logstrs = (char *)       &raw_fmts[hdr->rom_logstrs_offset];
4354         } else {
4355                 /*
4356                  * Legacy logstrs.bin format without header.
4357                  */
4358                 num_fmts = *((uint32 *) (raw_fmts)) / sizeof(uint32);
4359                 if (num_fmts == 0) {
4360                         /* Legacy ROM/RAM logstrs.bin format:
4361                           *  - ROM 'lognums' section
4362                           *   - RAM 'lognums' section
4363                           *   - ROM 'logstrs' section.
4364                           *   - RAM 'logstrs' section.
4365                           *
4366                           * 'lognums' is an array of indexes for the strings in the
4367                           * 'logstrs' section. The first uint32 is 0 (index of first
4368                           * string in ROM 'logstrs' section).
4369                           *
4370                           * The 4324b5 is the only ROM that uses this legacy format. Use the
4371                           * fixed number of ROM fmtnums to find the start of the RAM
4372                           * 'lognums' section. Use the fixed first ROM string ("Con\n") to
4373                           * find the ROM 'logstrs' section.
4374                           */
4375                         #define NUM_4324B5_ROM_FMTS     186
4376                         #define FIRST_4324B5_ROM_LOGSTR "Con\n"
4377                         ram_index = NUM_4324B5_ROM_FMTS;
4378                         lognums = (uint32 *) raw_fmts;
4379                         num_fmts =      ram_index;
4380                         logstrs = (char *) &raw_fmts[num_fmts << 2];
4381                         while (strncmp(FIRST_4324B5_ROM_LOGSTR, logstrs, 4)) {
4382                                 num_fmts++;
4383                                 logstrs = (char *) &raw_fmts[num_fmts << 2];
4384                         }
4385                 } else {
4386                                 /* Legacy RAM-only logstrs.bin format:
4387                                  *        - RAM 'lognums' section
4388                                  *        - RAM 'logstrs' section.
4389                                  *
4390                                  * 'lognums' is an array of indexes for the strings in the
4391                                  * 'logstrs' section. The first uint32 is an index to the
4392                                  * start of 'logstrs'. Therefore, if this index is divided
4393                                  * by 'sizeof(uint32)' it provides the number of logstr
4394                                  *      entries.
4395                                  */
4396                                 ram_index = 0;
4397                                 lognums = (uint32 *) raw_fmts;
4398                                 logstrs = (char *)      &raw_fmts[num_fmts << 2];
4399                         }
4400         }
4401         fmts = kmalloc(num_fmts  * sizeof(char *), GFP_KERNEL);
4402         if (fmts == NULL) {
4403                 DHD_ERROR(("Failed to allocate fmts memory"));
4404                 goto fail;
4405         }
4406
4407         for (i = 0; i < num_fmts; i++) {
4408                 /* ROM lognums index into logstrs using 'rom_logstrs_offset' as a base
4409                 * (they are 0-indexed relative to 'rom_logstrs_offset').
4410                 *
4411                 * RAM lognums are already indexed to point to the correct RAM logstrs (they
4412                 * are 0-indexed relative to the start of the logstrs.bin file).
4413                 */
4414                 if (i == ram_index) {
4415                         logstrs = raw_fmts;
4416                 }
4417                 fmts[i] = &logstrs[lognums[i]];
4418         }
4419         temp->fmts = fmts;
4420         temp->raw_fmts = raw_fmts;
4421         temp->num_fmts = num_fmts;
4422         filp_close(filep, NULL);
4423         set_fs(fs);
4424         return 0;
4425 fail:
4426         if (raw_fmts) {
4427                 kfree(raw_fmts);
4428                 raw_fmts = NULL;
4429         }
4430         if (!IS_ERR(filep))
4431                 filp_close(filep, NULL);
4432         set_fs(fs);
4433         temp->fmts = NULL;
4434         return -1;
4435 }
4436 #endif /* SHOW_LOGTRACE */
4437
4438
4439 dhd_pub_t *
4440 dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
4441 {
4442         dhd_info_t *dhd = NULL;
4443         struct net_device *net = NULL;
4444         char if_name[IFNAMSIZ] = {'\0'};
4445         uint32 bus_type = -1;
4446         uint32 bus_num = -1;
4447         uint32 slot_num = -1;
4448         wifi_adapter_info_t *adapter = NULL;
4449
4450         dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT;
4451         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4452
4453         /* will implement get_ids for DBUS later */
4454 #if defined(BCMSDIO)
4455         dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num);
4456 #endif 
4457         adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num);
4458
4459         /* Allocate primary dhd_info */
4460         dhd = wifi_platform_prealloc(adapter, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t));
4461         if (dhd == NULL) {
4462                 dhd = MALLOC(osh, sizeof(dhd_info_t));
4463                 if (dhd == NULL) {
4464                         DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__));
4465                         goto fail;
4466                 }
4467         }
4468         memset(dhd, 0, sizeof(dhd_info_t));
4469         dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC;
4470
4471         dhd->unit = dhd_found + instance_base; /* do not increment dhd_found, yet */
4472
4473         dhd->pub.osh = osh;
4474         dhd->adapter = adapter;
4475
4476 #ifdef GET_CUSTOM_MAC_ENABLE
4477         wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet);
4478 #endif /* GET_CUSTOM_MAC_ENABLE */
4479         dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID;
4480         dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID;
4481
4482         /* Initialize thread based operation and lock */
4483         sema_init(&dhd->sdsem, 1);
4484
4485         /* Some DHD modules (e.g. cfg80211) configures operation mode based on firmware name.
4486          * This is indeed a hack but we have to make it work properly before we have a better
4487          * solution
4488          */
4489         dhd_update_fw_nv_path(dhd);
4490
4491         /* Link to info module */
4492         dhd->pub.info = dhd;
4493
4494
4495         /* Link to bus module */
4496         dhd->pub.bus = bus;
4497         dhd->pub.hdrlen = bus_hdrlen;
4498
4499         /* Set network interface name if it was provided as module parameter */
4500         if (iface_name[0]) {
4501                 int len;
4502                 char ch;
4503                 strncpy(if_name, iface_name, IFNAMSIZ);
4504                 if_name[IFNAMSIZ - 1] = 0;
4505                 len = strlen(if_name);
4506                 ch = if_name[len - 1];
4507                 if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2))
4508                         strcat(if_name, "%d");
4509         }
4510         net = dhd_allocate_if(&dhd->pub, 0, if_name, NULL, 0, TRUE);
4511         if (net == NULL)
4512                 goto fail;
4513         dhd_state |= DHD_ATTACH_STATE_ADD_IF;
4514
4515 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
4516         net->open = NULL;
4517 #else
4518         net->netdev_ops = NULL;
4519 #endif
4520
4521         sema_init(&dhd->proto_sem, 1);
4522
4523 #ifdef PROP_TXSTATUS
4524         spin_lock_init(&dhd->wlfc_spinlock);
4525
4526         dhd->pub.skip_fc = dhd_wlfc_skip_fc;
4527         dhd->pub.plat_init = dhd_wlfc_plat_init;
4528         dhd->pub.plat_deinit = dhd_wlfc_plat_deinit;
4529 #endif /* PROP_TXSTATUS */
4530
4531         /* Initialize other structure content */
4532         init_waitqueue_head(&dhd->ioctl_resp_wait);
4533         init_waitqueue_head(&dhd->ctrl_wait);
4534
4535         /* Initialize the spinlocks */
4536         spin_lock_init(&dhd->sdlock);
4537         spin_lock_init(&dhd->txqlock);
4538         spin_lock_init(&dhd->dhd_lock);
4539         spin_lock_init(&dhd->rxf_lock);
4540 #if defined(RXFRAME_THREAD)
4541         dhd->rxthread_enabled = TRUE;
4542 #endif /* defined(RXFRAME_THREAD) */
4543
4544 #ifdef DHDTCPACK_SUPPRESS
4545         spin_lock_init(&dhd->tcpack_lock);
4546 #endif /* DHDTCPACK_SUPPRESS */
4547
4548         /* Initialize Wakelock stuff */
4549         spin_lock_init(&dhd->wakelock_spinlock);
4550         dhd->wakelock_counter = 0;
4551         dhd->wakelock_wd_counter = 0;
4552         dhd->wakelock_rx_timeout_enable = 0;
4553         dhd->wakelock_ctrl_timeout_enable = 0;
4554 #ifdef CONFIG_HAS_WAKELOCK
4555         wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake");
4556         wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake");
4557         wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake");
4558         wake_lock_init(&dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake");
4559 #endif /* CONFIG_HAS_WAKELOCK */
4560 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
4561         mutex_init(&dhd->dhd_net_if_mutex);
4562         mutex_init(&dhd->dhd_suspend_mutex);
4563 #endif
4564         dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
4565
4566         /* Attach and link in the protocol */
4567         if (dhd_prot_attach(&dhd->pub) != 0) {
4568                 DHD_ERROR(("dhd_prot_attach failed\n"));
4569                 goto fail;
4570         }
4571         dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH;
4572
4573 #ifdef WL_CFG80211
4574         /* Attach and link in the cfg80211 */
4575         if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) {
4576                 DHD_ERROR(("wl_cfg80211_attach failed\n"));
4577                 goto fail;
4578         }
4579
4580         dhd_monitor_init(&dhd->pub);
4581         dhd_state |= DHD_ATTACH_STATE_CFG80211;
4582 #endif
4583 #if defined(WL_WIRELESS_EXT)
4584         /* Attach and link in the iw */
4585         if (!(dhd_state &  DHD_ATTACH_STATE_CFG80211)) {
4586                 if (wl_iw_attach(net, (void *)&dhd->pub) != 0) {
4587                 DHD_ERROR(("wl_iw_attach failed\n"));
4588                 goto fail;
4589         }
4590         dhd_state |= DHD_ATTACH_STATE_WL_ATTACH;
4591         }
4592 #endif /* defined(WL_WIRELESS_EXT) */
4593
4594 #ifdef SHOW_LOGTRACE
4595         dhd_init_logstrs_array(&dhd->event_data);
4596 #endif /* SHOW_LOGTRACE */
4597
4598         if (dhd_sta_pool_init(&dhd->pub, DHD_MAX_STA) != BCME_OK) {
4599                 DHD_ERROR(("%s: Initializing %u sta\n", __FUNCTION__, DHD_MAX_STA));
4600                 goto fail;
4601         }
4602
4603
4604         /* Set up the watchdog timer */
4605         init_timer(&dhd->timer);
4606         dhd->timer.data = (ulong)dhd;
4607         dhd->timer.function = dhd_watchdog;
4608         dhd->default_wd_interval = dhd_watchdog_ms;
4609
4610         if (dhd_watchdog_prio >= 0) {
4611                 /* Initialize watchdog thread */
4612                 PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread");
4613
4614         } else {
4615                 dhd->thr_wdt_ctl.thr_pid = -1;
4616         }
4617
4618 #ifdef DEBUGGER
4619         debugger_init((void *) bus);
4620 #endif
4621
4622         /* Set up the bottom half handler */
4623         if (dhd_dpc_prio >= 0) {
4624                 /* Initialize DPC thread */
4625                 PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc");
4626         } else {
4627                 /*  use tasklet for dpc */
4628                 tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd);
4629                 dhd->thr_dpc_ctl.thr_pid = -1;
4630         }
4631
4632         if (dhd->rxthread_enabled) {
4633                 bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND);
4634                 /* Initialize RXF thread */
4635                 PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf");
4636         }
4637
4638         dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
4639
4640 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \
4641         KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM_SLEEP)
4642         if (!dhd_pm_notifier_registered) {
4643                 dhd_pm_notifier_registered = TRUE;
4644                 register_pm_notifier(&dhd_pm_notifier);
4645         }
4646 #endif /* CONFIG_PM_SLEEP */
4647
4648 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
4649         dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20;
4650         dhd->early_suspend.suspend = dhd_early_suspend;
4651         dhd->early_suspend.resume = dhd_late_resume;
4652         register_early_suspend(&dhd->early_suspend);
4653         dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE;
4654 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
4655
4656 #ifdef ARP_OFFLOAD_SUPPORT
4657         dhd->pend_ipaddr = 0;
4658         if (!dhd_inetaddr_notifier_registered) {
4659                 dhd_inetaddr_notifier_registered = TRUE;
4660                 register_inetaddr_notifier(&dhd_inetaddr_notifier);
4661         }
4662 #endif /* ARP_OFFLOAD_SUPPORT */
4663 #ifdef CONFIG_IPV6
4664         if (!dhd_inet6addr_notifier_registered) {
4665                 dhd_inet6addr_notifier_registered = TRUE;
4666                 register_inet6addr_notifier(&dhd_inet6addr_notifier);
4667         }
4668 #endif
4669         dhd->dhd_deferred_wq = dhd_deferred_work_init((void *)dhd);
4670 #ifdef DEBUG_CPU_FREQ
4671         dhd->new_freq = alloc_percpu(int);
4672         dhd->freq_trans.notifier_call = dhd_cpufreq_notifier;
4673         cpufreq_register_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER);
4674 #endif
4675 #ifdef DHDTCPACK_SUPPRESS
4676 #ifdef BCMSDIO
4677         dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_REPLACE);
4678 #elif defined(BCMPCIE)
4679         dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_REPLACE);
4680 #else
4681         dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF);
4682 #endif /* BCMSDIO */
4683 #endif /* DHDTCPACK_SUPPRESS */
4684
4685         dhd_state |= DHD_ATTACH_STATE_DONE;
4686         dhd->dhd_state = dhd_state;
4687
4688         dhd_found++;
4689         return &dhd->pub;
4690
4691 fail:
4692         if (dhd_state >= DHD_ATTACH_STATE_DHD_ALLOC) {
4693                 DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n",
4694                         __FUNCTION__, dhd_state, &dhd->pub));
4695                 dhd->dhd_state = dhd_state;
4696                 dhd_detach(&dhd->pub);
4697                 dhd_free(&dhd->pub);
4698         }
4699
4700         return NULL;
4701 }
4702
4703 int dhd_get_fw_mode(dhd_info_t *dhdinfo)
4704 {
4705         if (strstr(dhdinfo->fw_path, "_apsta") != NULL)
4706                 return DHD_FLAG_HOSTAP_MODE;
4707         if (strstr(dhdinfo->fw_path, "_p2p") != NULL)
4708                 return DHD_FLAG_P2P_MODE;
4709         if (strstr(dhdinfo->fw_path, "_ibss") != NULL)
4710                 return DHD_FLAG_IBSS_MODE;
4711         if (strstr(dhdinfo->fw_path, "_mfg") != NULL)
4712                 return DHD_FLAG_MFG_MODE;
4713
4714         return DHD_FLAG_STA_MODE;
4715 }
4716
4717 bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo)
4718 {
4719         int fw_len;
4720         int nv_len;
4721         const char *fw = NULL;
4722         const char *nv = NULL;
4723         wifi_adapter_info_t *adapter = dhdinfo->adapter;
4724
4725
4726         /* Update firmware and nvram path. The path may be from adapter info or module parameter
4727          * The path from adapter info is used for initialization only (as it won't change).
4728          *
4729          * The firmware_path/nvram_path module parameter may be changed by the system at run
4730          * time. When it changes we need to copy it to dhdinfo->fw_path. Also Android private
4731          * command may change dhdinfo->fw_path. As such we need to clear the path info in
4732          * module parameter after it is copied. We won't update the path until the module parameter
4733          * is changed again (first character is not '\0')
4734          */
4735
4736         /* set default firmware and nvram path for built-in type driver */
4737         if (!dhd_download_fw_on_driverload) {
4738 #ifdef CONFIG_BCMDHD_FW_PATH
4739                 fw = CONFIG_BCMDHD_FW_PATH;
4740 #endif /* CONFIG_BCMDHD_FW_PATH */
4741 #ifdef CONFIG_BCMDHD_NVRAM_PATH
4742                 nv = CONFIG_BCMDHD_NVRAM_PATH;
4743 #endif /* CONFIG_BCMDHD_NVRAM_PATH */
4744         }
4745
4746         /* check if we need to initialize the path */
4747         if (dhdinfo->fw_path[0] == '\0') {
4748                 if (adapter && adapter->fw_path && adapter->fw_path[0] != '\0')
4749                         fw = adapter->fw_path;
4750
4751         }
4752         if (dhdinfo->nv_path[0] == '\0') {
4753                 if (adapter && adapter->nv_path && adapter->nv_path[0] != '\0')
4754                         nv = adapter->nv_path;
4755         }
4756
4757         /* Use module parameter if it is valid, EVEN IF the path has not been initialized
4758          *
4759          * TODO: need a solution for multi-chip, can't use the same firmware for all chips
4760          */
4761         if (firmware_path[0] != '\0')
4762                 fw = firmware_path;
4763         if (nvram_path[0] != '\0')
4764                 nv = nvram_path;
4765
4766         if (fw && fw[0] != '\0') {
4767                 fw_len = strlen(fw);
4768                 if (fw_len >= sizeof(dhdinfo->fw_path)) {
4769                         DHD_ERROR(("fw path len exceeds max len of dhdinfo->fw_path\n"));
4770                         return FALSE;
4771                 }
4772                 strncpy(dhdinfo->fw_path, fw, sizeof(dhdinfo->fw_path));
4773                 if (dhdinfo->fw_path[fw_len-1] == '\n')
4774                        dhdinfo->fw_path[fw_len-1] = '\0';
4775         }
4776         if (nv && nv[0] != '\0') {
4777                 nv_len = strlen(nv);
4778                 if (nv_len >= sizeof(dhdinfo->nv_path)) {
4779                         DHD_ERROR(("nvram path len exceeds max len of dhdinfo->nv_path\n"));
4780                         return FALSE;
4781                 }
4782                 strncpy(dhdinfo->nv_path, nv, sizeof(dhdinfo->nv_path));
4783                 if (dhdinfo->nv_path[nv_len-1] == '\n')
4784                        dhdinfo->nv_path[nv_len-1] = '\0';
4785         }
4786
4787         /* clear the path in module parameter */
4788         firmware_path[0] = '\0';
4789         nvram_path[0] = '\0';
4790
4791 #ifndef BCMEMBEDIMAGE
4792         /* fw_path and nv_path are not mandatory for BCMEMBEDIMAGE */
4793         if (dhdinfo->fw_path[0] == '\0') {
4794                 DHD_ERROR(("firmware path not found\n"));
4795                 return FALSE;
4796         }
4797         if (dhdinfo->nv_path[0] == '\0') {
4798                 DHD_ERROR(("nvram path not found\n"));
4799                 return FALSE;
4800         }
4801 #endif /* BCMEMBEDIMAGE */
4802
4803         return TRUE;
4804 }
4805
4806
4807 int
4808 dhd_bus_start(dhd_pub_t *dhdp)
4809 {
4810         int ret = -1;
4811         dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
4812         unsigned long flags;
4813
4814         ASSERT(dhd);
4815
4816         DHD_TRACE(("Enter %s:\n", __FUNCTION__));
4817
4818         DHD_PERIM_LOCK(dhdp);
4819
4820         /* try to download image and nvram to the dongle */
4821         if  (dhd->pub.busstate == DHD_BUS_DOWN && dhd_update_fw_nv_path(dhd)) {
4822                 DHD_INFO(("%s download fw %s, nv %s\n", __FUNCTION__, dhd->fw_path, dhd->nv_path));
4823                 ret = dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh,
4824                                                 dhd->fw_path, dhd->nv_path);
4825                 if (ret < 0) {
4826                         DHD_ERROR(("%s: failed to download firmware %s\n",
4827                                   __FUNCTION__, dhd->fw_path));
4828                         DHD_PERIM_UNLOCK(dhdp);
4829                         return ret;
4830                 }
4831         }
4832         if (dhd->pub.busstate != DHD_BUS_LOAD) {
4833                 DHD_PERIM_UNLOCK(dhdp);
4834                 return -ENETDOWN;
4835         }
4836
4837         dhd_os_sdlock(dhdp);
4838
4839         /* Start the watchdog timer */
4840         dhd->pub.tickcnt = 0;
4841         dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms);
4842
4843         /* Bring up the bus */
4844         if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) {
4845
4846                 DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
4847                 dhd_os_sdunlock(dhdp);
4848                 DHD_PERIM_UNLOCK(dhdp);
4849                 return ret;
4850         }
4851 #if defined(OOB_INTR_ONLY)
4852         /* Host registration for OOB interrupt */
4853         if (dhd_bus_oob_intr_register(dhdp)) {
4854                 /* deactivate timer and wait for the handler to finish */
4855
4856                 DHD_GENERAL_LOCK(&dhd->pub, flags);
4857                 dhd->wd_timer_valid = FALSE;
4858                 DHD_GENERAL_UNLOCK(&dhd->pub, flags);
4859                 dhd_os_sdunlock(dhdp);
4860                 del_timer_sync(&dhd->timer);
4861
4862                 DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
4863                 DHD_PERIM_UNLOCK(dhdp);
4864                 DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
4865                 return -ENODEV;
4866         }
4867
4868         /* Enable oob at firmware */
4869         dhd_enable_oob_intr(dhd->pub.bus, TRUE);
4870 #endif 
4871 #ifdef PCIE_FULL_DONGLE
4872         {
4873                 uint8 txpush = 0;
4874                 uint32 num_flowrings; /* includes H2D common rings */
4875                 num_flowrings = dhd_bus_max_h2d_queues(dhd->pub.bus, &txpush);
4876                 DHD_ERROR(("%s: Initializing %u flowrings\n", __FUNCTION__,
4877                         num_flowrings));
4878                 if ((ret = dhd_flow_rings_init(&dhd->pub, num_flowrings)) != BCME_OK) {
4879                         dhd_os_sdunlock(dhdp);
4880                         DHD_PERIM_UNLOCK(dhdp);
4881                         return ret;
4882                 }
4883         }
4884 #endif /* PCIE_FULL_DONGLE */
4885
4886         /* Do protocol initialization necessary for IOCTL/IOVAR */
4887         dhd_prot_init(&dhd->pub);
4888
4889         /* If bus is not ready, can't come up */
4890         if (dhd->pub.busstate != DHD_BUS_DATA) {
4891                 DHD_GENERAL_LOCK(&dhd->pub, flags);
4892                 dhd->wd_timer_valid = FALSE;
4893                 DHD_GENERAL_UNLOCK(&dhd->pub, flags);
4894                 dhd_os_sdunlock(dhdp);
4895                 del_timer_sync(&dhd->timer);
4896                 DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
4897                 DHD_PERIM_UNLOCK(dhdp);
4898                 DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
4899                 return -ENODEV;
4900         }
4901
4902         dhd_os_sdunlock(dhdp);
4903
4904         /* Bus is ready, query any dongle information */
4905         if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) {
4906                 DHD_PERIM_UNLOCK(dhdp);
4907                 return ret;
4908         }
4909
4910 #ifdef ARP_OFFLOAD_SUPPORT
4911         if (dhd->pend_ipaddr) {
4912 #ifdef AOE_IP_ALIAS_SUPPORT
4913                 aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0);
4914 #endif /* AOE_IP_ALIAS_SUPPORT */
4915                 dhd->pend_ipaddr = 0;
4916         }
4917 #endif /* ARP_OFFLOAD_SUPPORT */
4918
4919         DHD_PERIM_UNLOCK(dhdp);
4920         return 0;
4921 }
4922 #ifdef WLTDLS
4923 int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac)
4924 {
4925         char iovbuf[WLC_IOCTL_SMLEN];
4926         uint32 tdls = tdls_on;
4927         int ret = 0;
4928         uint32 tdls_auto_op = 0;
4929         uint32 tdls_idle_time = CUSTOM_TDLS_IDLE_MODE_SETTING;
4930         int32 tdls_rssi_high = CUSTOM_TDLS_RSSI_THRESHOLD_HIGH;
4931         int32 tdls_rssi_low = CUSTOM_TDLS_RSSI_THRESHOLD_LOW;
4932         BCM_REFERENCE(mac);
4933         if (!FW_SUPPORTED(dhd, tdls))
4934                 return BCME_ERROR;
4935
4936         if (dhd->tdls_enable == tdls_on)
4937                 goto auto_mode;
4938         bcm_mkiovar("tdls_enable", (char *)&tdls, sizeof(tdls), iovbuf, sizeof(iovbuf));
4939         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
4940                 DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret));
4941                 goto exit;
4942         }
4943         dhd->tdls_enable = tdls_on;
4944 auto_mode:
4945
4946         tdls_auto_op = auto_on;
4947         bcm_mkiovar("tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op),
4948                 iovbuf, sizeof(iovbuf));
4949         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
4950                 sizeof(iovbuf), TRUE, 0)) < 0) {
4951                 DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret));
4952                 goto exit;
4953         }
4954
4955         if (tdls_auto_op) {
4956                 bcm_mkiovar("tdls_idle_time", (char *)&tdls_idle_time,
4957                         sizeof(tdls_idle_time), iovbuf, sizeof(iovbuf));
4958                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
4959                         sizeof(iovbuf), TRUE, 0)) < 0) {
4960                         DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret));
4961                         goto exit;
4962                 }
4963                 bcm_mkiovar("tdls_rssi_high", (char *)&tdls_rssi_high, 4, iovbuf, sizeof(iovbuf));
4964                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
4965                         sizeof(iovbuf), TRUE, 0)) < 0) {
4966                         DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret));
4967                         goto exit;
4968                 }
4969                 bcm_mkiovar("tdls_rssi_low", (char *)&tdls_rssi_low, 4, iovbuf, sizeof(iovbuf));
4970                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
4971                         sizeof(iovbuf), TRUE, 0)) < 0) {
4972                         DHD_ERROR(("%s: tdls_rssi_low failed %d\n", __FUNCTION__, ret));
4973                         goto exit;
4974                 }
4975         }
4976
4977 exit:
4978         return ret;
4979 }
4980 int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac)
4981 {
4982         dhd_info_t *dhd = DHD_DEV_INFO(dev);
4983         int ret = 0;
4984         if (dhd)
4985                 ret = _dhd_tdls_enable(&dhd->pub, tdls_on, auto_on, mac);
4986         else
4987                 ret = BCME_ERROR;
4988         return ret;
4989 }
4990 #ifdef PCIE_FULL_DONGLE
4991 void dhd_tdls_update_peer_info(struct net_device *dev, bool connect, uint8 *da)
4992 {
4993         dhd_info_t *dhd = DHD_DEV_INFO(dev);
4994         dhd_pub_t *dhdp =  (dhd_pub_t *)&dhd->pub;
4995         tdls_peer_node_t *cur = dhdp->peer_tbl.node;
4996         tdls_peer_node_t *new = NULL, *prev = NULL;
4997         dhd_if_t *dhdif;
4998         uint8 sa[ETHER_ADDR_LEN];
4999         int ifidx = dhd_net2idx(dhd, dev);
5000
5001         if (ifidx == DHD_BAD_IF)
5002                 return;
5003
5004         dhdif = dhd->iflist[ifidx];
5005         memcpy(sa, dhdif->mac_addr, ETHER_ADDR_LEN);
5006
5007         if (connect) {
5008                 while (cur != NULL) {
5009                         if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
5010                                 DHD_ERROR(("%s: TDLS Peer exist already %d\n",
5011                                         __FUNCTION__, __LINE__));
5012                                 return;
5013                         }
5014                         cur = cur->next;
5015                 }
5016
5017                 new = MALLOC(dhdp->osh, sizeof(tdls_peer_node_t));
5018                 if (new == NULL) {
5019                         DHD_ERROR(("%s: Failed to allocate memory\n", __FUNCTION__));
5020                         return;
5021                 }
5022                 memcpy(new->addr, da, ETHER_ADDR_LEN);
5023                 new->next = dhdp->peer_tbl.node;
5024                 dhdp->peer_tbl.node = new;
5025                 dhdp->peer_tbl.tdls_peer_count++;
5026
5027         } else {
5028                 while (cur != NULL) {
5029                         if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
5030                                 dhd_flow_rings_delete_for_peer(dhdp, ifidx, da);
5031                                 if (prev)
5032                                         prev->next = cur->next;
5033                                 else
5034                                         dhdp->peer_tbl.node = cur->next;
5035                                 MFREE(dhdp->osh, cur, sizeof(tdls_peer_node_t));
5036                                 dhdp->peer_tbl.tdls_peer_count--;
5037                                 return;
5038                         }
5039                         prev = cur;
5040                         cur = cur->next;
5041                 }
5042                 DHD_ERROR(("%s: TDLS Peer Entry Not found\n", __FUNCTION__));
5043         }
5044 }
5045 #endif /* PCIE_FULL_DONGLE */
5046 #endif 
5047
5048 bool dhd_is_concurrent_mode(dhd_pub_t *dhd)
5049 {
5050         if (!dhd)
5051                 return FALSE;
5052
5053         if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE)
5054                 return TRUE;
5055         else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) ==
5056                 DHD_FLAG_CONCURR_SINGLE_CHAN_MODE)
5057                 return TRUE;
5058         else
5059                 return FALSE;
5060 }
5061 #if !defined(AP) && defined(WLP2P)
5062 /* From Android JerryBean release, the concurrent mode is enabled by default and the firmware
5063  * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA
5064  * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware
5065  * would still be named as fw_bcmdhd_apsta.
5066  */
5067 uint32
5068 dhd_get_concurrent_capabilites(dhd_pub_t *dhd)
5069 {
5070         int32 ret = 0;
5071         char buf[WLC_IOCTL_SMLEN];
5072         bool mchan_supported = FALSE;
5073         /* if dhd->op_mode is already set for HOSTAP and Manufacturing
5074          * test mode, that means we only will use the mode as it is
5075          */
5076         if (dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))
5077                 return 0;
5078         if (FW_SUPPORTED(dhd, vsdb)) {
5079                 mchan_supported = TRUE;
5080         }
5081         if (!FW_SUPPORTED(dhd, p2p)) {
5082                 DHD_TRACE(("Chip does not support p2p\n"));
5083                 return 0;
5084         }
5085         else {
5086                 /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */
5087                 memset(buf, 0, sizeof(buf));
5088                 bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf));
5089                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
5090                         FALSE, 0)) < 0) {
5091                         DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret));
5092                         return 0;
5093                 }
5094                 else {
5095                         if (buf[0] == 1) {
5096                                 /* By default, chip supports single chan concurrency,
5097                                 * now lets check for mchan
5098                                 */
5099                                 ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE;
5100                                 if (mchan_supported)
5101                                         ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE;
5102 #if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
5103                                 /* For customer_hw4, although ICS,
5104                                 * we still support concurrent mode
5105                                 */
5106                                 return ret;
5107 #else
5108                                 return 0;
5109 #endif 
5110                         }
5111                 }
5112         }
5113         return 0;
5114 }
5115 #endif 
5116
5117 int
5118 dhd_preinit_ioctls(dhd_pub_t *dhd)
5119 {
5120         int ret = 0;
5121         char eventmask[WL_EVENTING_MASK_LEN];
5122         char iovbuf[WL_EVENTING_MASK_LEN + 12]; /*  Room for "event_msgs" + '\0' + bitvec  */
5123         uint32 buf_key_b4_m4 = 1;
5124         uint32 rpt_hitxrate = 1;
5125         uint8 msglen;
5126         eventmsgs_ext_t *eventmask_msg;
5127         char iov_buf[WLC_IOCTL_SMLEN];
5128         int ret2 = 0;
5129 #if defined(CUSTOM_AMPDU_BA_WSIZE)
5130         uint32 ampdu_ba_wsize = 0;
5131 #endif 
5132 #if defined(CUSTOM_AMPDU_MPDU)
5133         int32 ampdu_mpdu = 0;
5134 #endif
5135 #if defined(CUSTOM_AMPDU_RELEASE)
5136         int32 ampdu_release = 0;
5137 #endif
5138
5139 #if defined(BCMSDIO)
5140 #ifdef PROP_TXSTATUS
5141         int wlfc_enable = TRUE;
5142 #ifndef DISABLE_11N
5143         uint32 hostreorder = 1;
5144 #endif /* DISABLE_11N */
5145 #endif /* PROP_TXSTATUS */
5146 #endif 
5147 #ifdef PCIE_FULL_DONGLE
5148         uint32 wl_ap_isolate;
5149 #endif /* PCIE_FULL_DONGLE */
5150
5151 #ifdef DHD_ENABLE_LPC
5152         uint32 lpc = 1;
5153 #endif /* DHD_ENABLE_LPC */
5154         uint power_mode = PM_FAST;
5155         uint32 dongle_align = DHD_SDALIGN;
5156 #if defined(BCMSDIO)
5157         uint32 glom = CUSTOM_GLOM_SETTING;
5158 #endif /* defined(BCMSDIO) */
5159 #if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
5160         uint32 credall = 1;
5161 #endif
5162 #if defined(VSDB) || defined(ROAM_ENABLE)
5163         uint bcn_timeout = 8;
5164 #else
5165         uint bcn_timeout = 4;
5166 #endif 
5167         uint retry_max = 3;
5168 #if defined(ARP_OFFLOAD_SUPPORT)
5169         int arpoe = 1;
5170 #endif
5171         int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME;
5172         int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME;
5173         int scan_passive_time = DHD_SCAN_PASSIVE_TIME;
5174         char buf[WLC_IOCTL_SMLEN];
5175         char *ptr;
5176         uint32 listen_interval = CUSTOM_LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
5177 #ifdef ROAM_ENABLE
5178         uint roamvar = 0;
5179         int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL};
5180         int roam_scan_period[2] = {10, WLC_BAND_ALL};
5181         int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL};
5182 #ifdef ROAM_AP_ENV_DETECTION
5183         int roam_env_mode = AP_ENV_INDETERMINATE;
5184 #endif /* ROAM_AP_ENV_DETECTION */
5185 #ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC
5186         int roam_fullscan_period = 60;
5187 #else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */
5188         int roam_fullscan_period = 120;
5189 #endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */
5190 #else
5191 #ifdef DISABLE_BUILTIN_ROAM
5192         uint roamvar = 1;
5193 #endif /* DISABLE_BUILTIN_ROAM */
5194 #endif /* ROAM_ENABLE */
5195
5196 #if defined(SOFTAP)
5197         uint dtim = 1;
5198 #endif
5199 #if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
5200         uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
5201         struct ether_addr p2p_ea;
5202 #endif
5203
5204 #if (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC)
5205         uint32 apsta = 1; /* Enable APSTA mode */
5206 #elif defined(SOFTAP_AND_GC)
5207         uint32 apsta = 0;
5208         int ap_mode = 1;
5209 #endif /* (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC) */
5210 #ifdef GET_CUSTOM_MAC_ENABLE
5211         struct ether_addr ea_addr;
5212 #endif /* GET_CUSTOM_MAC_ENABLE */
5213
5214 #ifdef CUSTOM_AMPDU_BA_WSIZE
5215         struct ampdu_tid_control atc;
5216 #endif
5217 #ifdef DISABLE_11N
5218         uint32 nmode = 0;
5219 #endif /* DISABLE_11N */
5220
5221 #ifdef USE_WL_TXBF
5222         uint32 txbf = 1;
5223 #endif /* USE_WL_TXBF */
5224 #ifdef USE_WL_FRAMEBURST
5225         uint32 frameburst = 1;
5226 #endif /* USE_WL_FRAMEBURST */
5227 #ifdef CUSTOM_PSPRETEND_THR
5228         uint32 pspretend_thr = CUSTOM_PSPRETEND_THR;
5229 #endif
5230 #ifdef PKT_FILTER_SUPPORT
5231         dhd_pkt_filter_enable = TRUE;
5232 #endif /* PKT_FILTER_SUPPORT */
5233 #ifdef WLTDLS
5234         dhd->tdls_enable = FALSE;
5235 #endif /* WLTDLS */
5236 #ifdef RXCB
5237         uint32 rxcb = 1;
5238 #endif
5239         dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM;
5240         DHD_TRACE(("Enter %s\n", __FUNCTION__));
5241         dhd->op_mode = 0;
5242         if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) ||
5243                 (op_mode == DHD_FLAG_MFG_MODE)) {
5244                 /* Check and adjust IOCTL response timeout for Manufactring firmware */
5245                 dhd_os_set_ioctl_resp_timeout(MFG_IOCTL_RESP_TIMEOUT);
5246                 DHD_ERROR(("%s : Set IOCTL response time for Manufactring Firmware\n",
5247                         __FUNCTION__));
5248         }
5249         else {
5250                 dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT);
5251                 DHD_INFO(("%s : Set IOCTL response time.\n", __FUNCTION__));
5252         }
5253 #ifdef GET_CUSTOM_MAC_ENABLE
5254         ret = wifi_platform_get_mac_addr(dhd->info->adapter, ea_addr.octet);
5255         if (!ret) {
5256                 memset(buf, 0, sizeof(buf));
5257                 bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
5258                 ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
5259                 if (ret < 0) {
5260                         DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
5261                         return BCME_NOTUP;
5262                 }
5263                 memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN);
5264         } else {
5265 #endif /* GET_CUSTOM_MAC_ENABLE */
5266                 /* Get the default device MAC address directly from firmware */
5267                 memset(buf, 0, sizeof(buf));
5268                 bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf));
5269                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
5270                         FALSE, 0)) < 0) {
5271                         DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret));
5272                         return BCME_NOTUP;
5273                 }
5274                 /* Update public MAC address after reading from Firmware */
5275                 memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
5276
5277 #ifdef GET_CUSTOM_MAC_ENABLE
5278         }
5279 #endif /* GET_CUSTOM_MAC_ENABLE */
5280
5281         /* get a capabilities from firmware */
5282         memset(dhd->fw_capabilities, 0, sizeof(dhd->fw_capabilities));
5283         bcm_mkiovar("cap", 0, 0, dhd->fw_capabilities, sizeof(dhd->fw_capabilities));
5284         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, dhd->fw_capabilities,
5285                 sizeof(dhd->fw_capabilities), FALSE, 0)) < 0) {
5286                 DHD_ERROR(("%s: Get Capability failed (error=%d)\n",
5287                         __FUNCTION__, ret));
5288                 return 0;
5289         }
5290         if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) ||
5291                 (op_mode == DHD_FLAG_HOSTAP_MODE)) {
5292 #ifdef SET_RANDOM_MAC_SOFTAP
5293                 uint rand_mac;
5294 #endif
5295                 dhd->op_mode = DHD_FLAG_HOSTAP_MODE;
5296 #if defined(ARP_OFFLOAD_SUPPORT)
5297                         arpoe = 0;
5298 #endif
5299 #ifdef PKT_FILTER_SUPPORT
5300                         dhd_pkt_filter_enable = FALSE;
5301 #endif
5302 #ifdef SET_RANDOM_MAC_SOFTAP
5303                 SRANDOM32((uint)jiffies);
5304                 rand_mac = RANDOM32();
5305                 iovbuf[0] = 0x02;                          /* locally administered bit */
5306                 iovbuf[1] = 0x1A;
5307                 iovbuf[2] = 0x11;
5308                 iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0;
5309                 iovbuf[4] = (unsigned char)(rand_mac >> 8);
5310                 iovbuf[5] = (unsigned char)(rand_mac >> 16);
5311
5312                 bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf));
5313                 ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
5314                 if (ret < 0) {
5315                         DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
5316                 } else
5317                         memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
5318 #endif /* SET_RANDOM_MAC_SOFTAP */
5319 #if !defined(AP) && defined(WL_CFG80211)
5320                 /* Turn off MPC in AP mode */
5321                 bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
5322                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5323                         sizeof(iovbuf), TRUE, 0)) < 0) {
5324                         DHD_ERROR(("%s mpc for HostAPD failed  %d\n", __FUNCTION__, ret));
5325                 }
5326 #endif
5327         } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) ||
5328                 (op_mode == DHD_FLAG_MFG_MODE)) {
5329 #if defined(ARP_OFFLOAD_SUPPORT)
5330                 arpoe = 0;
5331 #endif /* ARP_OFFLOAD_SUPPORT */
5332 #ifdef PKT_FILTER_SUPPORT
5333                 dhd_pkt_filter_enable = FALSE;
5334 #endif /* PKT_FILTER_SUPPORT */
5335                 dhd->op_mode = DHD_FLAG_MFG_MODE;
5336         } else {
5337                 uint32 concurrent_mode = 0;
5338                 if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_P2P_MODE) ||
5339                         (op_mode == DHD_FLAG_P2P_MODE)) {
5340 #if defined(ARP_OFFLOAD_SUPPORT)
5341                         arpoe = 0;
5342 #endif
5343 #ifdef PKT_FILTER_SUPPORT
5344                         dhd_pkt_filter_enable = FALSE;
5345 #endif
5346                         dhd->op_mode = DHD_FLAG_P2P_MODE;
5347                 } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_IBSS_MODE) ||
5348                         (op_mode == DHD_FLAG_IBSS_MODE)) {
5349                         dhd->op_mode = DHD_FLAG_IBSS_MODE;
5350                 } else
5351                         dhd->op_mode = DHD_FLAG_STA_MODE;
5352 #if !defined(AP) && defined(WLP2P)
5353                 if (dhd->op_mode != DHD_FLAG_IBSS_MODE &&
5354                         (concurrent_mode = dhd_get_concurrent_capabilites(dhd))) {
5355 #if defined(ARP_OFFLOAD_SUPPORT)
5356                         arpoe = 1;
5357 #endif
5358                         dhd->op_mode |= concurrent_mode;
5359                 }
5360
5361                 /* Check if we are enabling p2p */
5362                 if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
5363                         bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
5364                         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
5365                                 iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
5366                                 DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret));
5367                         }
5368
5369 #if defined(SOFTAP_AND_GC)
5370                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_AP,
5371                         (char *)&ap_mode, sizeof(ap_mode), TRUE, 0)) < 0) {
5372                                 DHD_ERROR(("%s WLC_SET_AP failed %d\n", __FUNCTION__, ret));
5373                 }
5374 #endif
5375                         memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN);
5376                         ETHER_SET_LOCALADDR(&p2p_ea);
5377                         bcm_mkiovar("p2p_da_override", (char *)&p2p_ea,
5378                                 ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf));
5379                         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
5380                                 iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
5381                                 DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret));
5382                         } else {
5383                                 DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n"));
5384                         }
5385                 }
5386 #else
5387         (void)concurrent_mode;
5388 #endif 
5389         }
5390
5391         DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n",
5392                 dhd->op_mode, MAC2STRDBG(dhd->mac.octet)));
5393         /* Set Country code  */
5394         if (dhd->dhd_cspec.ccode[0] != 0) {
5395                 bcm_mkiovar("country", (char *)&dhd->dhd_cspec,
5396                         sizeof(wl_country_t), iovbuf, sizeof(iovbuf));
5397                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
5398                         DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
5399         }
5400
5401
5402         /* Set Listen Interval */
5403         bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf));
5404         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
5405                 DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret));
5406
5407 #if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM)
5408         /* Disable built-in roaming to allowed ext supplicant to take care of roaming */
5409         bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
5410         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
5411 #endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */
5412 #if defined(ROAM_ENABLE)
5413         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger,
5414                 sizeof(roam_trigger), TRUE, 0)) < 0)
5415                 DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret));
5416         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period,
5417                 sizeof(roam_scan_period), TRUE, 0)) < 0)
5418                 DHD_ERROR(("%s: roam scan period set failed %d\n", __FUNCTION__, ret));
5419         if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta,
5420                 sizeof(roam_delta), TRUE, 0)) < 0)
5421                 DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret));
5422         bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf));
5423         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
5424                 DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret));
5425 #ifdef ROAM_AP_ENV_DETECTION
5426         if (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER) {
5427                 bcm_mkiovar("roam_env_detection", (char *)&roam_env_mode,
5428                         4, iovbuf, sizeof(iovbuf));
5429                 if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) == BCME_OK)
5430                         dhd->roam_env_detection = TRUE;
5431                 else {
5432                         dhd->roam_env_detection = FALSE;
5433                 }
5434         }
5435 #endif /* ROAM_AP_ENV_DETECTION */
5436 #endif /* ROAM_ENABLE */
5437
5438 #ifdef WLTDLS
5439         /* by default TDLS on and auto mode off */
5440         _dhd_tdls_enable(dhd, true, false, NULL);
5441 #endif /* WLTDLS */
5442
5443 #ifdef DHD_ENABLE_LPC
5444         /* Set lpc 1 */
5445         bcm_mkiovar("lpc", (char *)&lpc, 4, iovbuf, sizeof(iovbuf));
5446         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5447                 sizeof(iovbuf), TRUE, 0)) < 0) {
5448                 DHD_ERROR(("%s Set lpc failed  %d\n", __FUNCTION__, ret));
5449         }
5450 #endif /* DHD_ENABLE_LPC */
5451
5452         /* Set PowerSave mode */
5453         dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0);
5454
5455         /* Match Host and Dongle rx alignment */
5456         bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
5457         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
5458
5459 #if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
5460         /* enable credall to reduce the chance of no bus credit happened. */
5461         bcm_mkiovar("bus:credall", (char *)&credall, 4, iovbuf, sizeof(iovbuf));
5462         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
5463 #endif
5464
5465 #if defined(BCMSDIO)
5466         if (glom != DEFAULT_GLOM_VALUE) {
5467                 DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom));
5468                 bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
5469                 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
5470         }
5471 #endif /* defined(BCMSDIO) */
5472
5473         /* Setup timeout if Beacons are lost and roam is off to report link down */
5474         bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
5475         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
5476         /* Setup assoc_retry_max count to reconnect target AP in dongle */
5477         bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
5478         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
5479 #if defined(AP) && !defined(WLP2P)
5480         /* Turn off MPC in AP mode */
5481         bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
5482         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
5483         bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
5484         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
5485 #endif /* defined(AP) && !defined(WLP2P) */
5486
5487
5488 #if defined(SOFTAP)
5489         if (ap_fw_loaded == TRUE) {
5490                 dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0);
5491         }
5492 #endif 
5493
5494 #if defined(KEEP_ALIVE)
5495         {
5496         /* Set Keep Alive : be sure to use FW with -keepalive */
5497         int res;
5498
5499 #if defined(SOFTAP)
5500         if (ap_fw_loaded == FALSE)
5501 #endif 
5502                 if (!(dhd->op_mode &
5503                         (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))) {
5504                         if ((res = dhd_keep_alive_onoff(dhd)) < 0)
5505                                 DHD_ERROR(("%s set keeplive failed %d\n",
5506                                 __FUNCTION__, res));
5507                 }
5508         }
5509 #endif /* defined(KEEP_ALIVE) */
5510
5511 #ifdef USE_WL_TXBF
5512         bcm_mkiovar("txbf", (char *)&txbf, 4, iovbuf, sizeof(iovbuf));
5513         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5514                 sizeof(iovbuf), TRUE, 0)) < 0) {
5515                 DHD_ERROR(("%s Set txbf failed  %d\n", __FUNCTION__, ret));
5516         }
5517 #endif /* USE_WL_TXBF */
5518 #ifdef USE_WL_FRAMEBURST
5519         /* Set frameburst to value */
5520         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_FAKEFRAG, (char *)&frameburst,
5521                 sizeof(frameburst), TRUE, 0)) < 0) {
5522                 DHD_ERROR(("%s Set frameburst failed  %d\n", __FUNCTION__, ret));
5523         }
5524 #endif /* USE_WL_FRAMEBURST */
5525 #if defined(CUSTOM_AMPDU_BA_WSIZE)
5526         /* Set ampdu ba wsize to 64 or 16 */
5527 #ifdef CUSTOM_AMPDU_BA_WSIZE
5528         ampdu_ba_wsize = CUSTOM_AMPDU_BA_WSIZE;
5529 #endif
5530         if (ampdu_ba_wsize != 0) {
5531                 bcm_mkiovar("ampdu_ba_wsize", (char *)&ampdu_ba_wsize, 4, iovbuf, sizeof(iovbuf));
5532                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5533                         sizeof(iovbuf), TRUE, 0)) < 0) {
5534                         DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed  %d\n",
5535                                 __FUNCTION__, ampdu_ba_wsize, ret));
5536                 }
5537         }
5538         atc.tid = 7;
5539         atc.enable = 0;
5540         bcm_mkiovar("ampdu_rx_tid", (char *)&atc, sizeof(atc), iovbuf, sizeof(iovbuf));
5541         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
5542 #endif 
5543
5544
5545 #if defined(CUSTOM_AMPDU_MPDU)
5546         ampdu_mpdu = CUSTOM_AMPDU_MPDU;
5547         if (ampdu_mpdu != 0 && (ampdu_mpdu <= ampdu_ba_wsize)) {
5548                 bcm_mkiovar("ampdu_mpdu", (char *)&ampdu_mpdu, 4, iovbuf, sizeof(iovbuf));
5549                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5550                         sizeof(iovbuf), TRUE, 0)) < 0) {
5551                         DHD_ERROR(("%s Set ampdu_mpdu to %d failed  %d\n",
5552                                 __FUNCTION__, CUSTOM_AMPDU_MPDU, ret));
5553                 }
5554         }
5555 #endif /* CUSTOM_AMPDU_MPDU */
5556
5557 #if defined(CUSTOM_AMPDU_RELEASE)
5558         ampdu_release = CUSTOM_AMPDU_RELEASE;
5559         if (ampdu_release != 0 && (ampdu_release <= ampdu_ba_wsize)) {
5560                 bcm_mkiovar("ampdu_release", (char *)&ampdu_release, 4, iovbuf, sizeof(iovbuf));
5561                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5562                         sizeof(iovbuf), TRUE, 0)) < 0) {
5563                         DHD_ERROR(("%s Set ampdu_release to %d failed  %d\n",
5564                                 __FUNCTION__, CUSTOM_AMPDU_RELEASE, ret));
5565                 }
5566         }
5567 #endif /* CUSTOM_AMPDU_RELEASE */
5568
5569 #ifdef CUSTOM_PSPRETEND_THR
5570         /* Turn off MPC in AP mode */
5571         bcm_mkiovar("pspretend_threshold", (char *)&pspretend_thr, 4,
5572                 iovbuf, sizeof(iovbuf));
5573         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5574                 sizeof(iovbuf), TRUE, 0)) < 0) {
5575                 DHD_ERROR(("%s pspretend_threshold for HostAPD failed  %d\n",
5576                         __FUNCTION__, ret));
5577         }
5578 #endif
5579
5580         /* Set the rpt_hitxrate to 1 so that link speed updated by WLC_GET_RATE
5581         *  is the maximum trasnmit rate
5582         *  rpt_hitxrate 0 : Here the rate reported is the most used rate in
5583         *                       the link.
5584         *  rpt_hitxrate 1 : Here the rate reported is the highest used rate
5585         *                       in the link.
5586         */
5587         bcm_mkiovar("rpt_hitxrate", (char *)&rpt_hitxrate, 4, iovbuf,
5588                         sizeof(iovbuf));
5589         ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5590                                 sizeof(iovbuf), TRUE, 0);
5591         if (ret < 0) {
5592                 DHD_ERROR(("%s Set rpt_hitxrate failed  %d\n", __FUNCTION__, ret));
5593         }
5594
5595         bcm_mkiovar("buf_key_b4_m4", (char *)&buf_key_b4_m4, 4, iovbuf, sizeof(iovbuf));
5596         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5597                 sizeof(iovbuf), TRUE, 0)) < 0) {
5598                 DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret));
5599         }
5600
5601         /* Read event_msgs mask */
5602         bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
5603         if ((ret  = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) {
5604                 DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret));
5605                 goto done;
5606         }
5607         bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
5608
5609         /* Setup event_msgs */
5610         setbit(eventmask, WLC_E_SET_SSID);
5611         setbit(eventmask, WLC_E_PRUNE);
5612         setbit(eventmask, WLC_E_AUTH);
5613         setbit(eventmask, WLC_E_AUTH_IND);
5614         setbit(eventmask, WLC_E_ASSOC);
5615         setbit(eventmask, WLC_E_REASSOC);
5616         setbit(eventmask, WLC_E_REASSOC_IND);
5617         setbit(eventmask, WLC_E_DEAUTH);
5618         setbit(eventmask, WLC_E_DEAUTH_IND);
5619         setbit(eventmask, WLC_E_DISASSOC_IND);
5620         setbit(eventmask, WLC_E_DISASSOC);
5621         setbit(eventmask, WLC_E_JOIN);
5622         setbit(eventmask, WLC_E_START);
5623         setbit(eventmask, WLC_E_ASSOC_IND);
5624         setbit(eventmask, WLC_E_PSK_SUP);
5625         setbit(eventmask, WLC_E_LINK);
5626         setbit(eventmask, WLC_E_NDIS_LINK);
5627         setbit(eventmask, WLC_E_MIC_ERROR);
5628         setbit(eventmask, WLC_E_ASSOC_REQ_IE);
5629         setbit(eventmask, WLC_E_ASSOC_RESP_IE);
5630 #ifndef WL_CFG80211
5631         setbit(eventmask, WLC_E_PMKID_CACHE);
5632         setbit(eventmask, WLC_E_TXFAIL);
5633 #endif
5634         setbit(eventmask, WLC_E_JOIN_START);
5635         setbit(eventmask, WLC_E_SCAN_COMPLETE);
5636 #ifdef WLMEDIA_HTSF
5637         setbit(eventmask, WLC_E_HTSFSYNC);
5638 #endif /* WLMEDIA_HTSF */
5639 #ifdef PNO_SUPPORT
5640         setbit(eventmask, WLC_E_PFN_NET_FOUND);
5641         setbit(eventmask, WLC_E_PFN_BEST_BATCHING);
5642         setbit(eventmask, WLC_E_PFN_BSSID_NET_FOUND);
5643         setbit(eventmask, WLC_E_PFN_BSSID_NET_LOST);
5644 #endif /* PNO_SUPPORT */
5645         /* enable dongle roaming event */
5646         /* WLC_E_ROAM event is depricated for bcm4354
5647            WLC_E_BSSID event is used for roaming in bcm4354*/
5648 #ifndef DISABLE_ROAM_EVENT
5649         setbit(eventmask, WLC_E_ROAM);
5650 #endif /* DISABLE_ROAM_EVENT */
5651         setbit(eventmask, WLC_E_BSSID);
5652 #ifdef WLTDLS
5653         setbit(eventmask, WLC_E_TDLS_PEER_EVENT);
5654 #endif /* WLTDLS */
5655 #ifdef WL_CFG80211
5656         setbit(eventmask, WLC_E_ESCAN_RESULT);
5657         if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
5658                 setbit(eventmask, WLC_E_ACTION_FRAME_RX);
5659                 setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE);
5660         }
5661 #endif /* WL_CFG80211 */
5662         setbit(eventmask, WLC_E_TRACE);
5663
5664         /* Write updated Event mask */
5665         bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
5666         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
5667                 DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret));
5668                 goto done;
5669         }
5670
5671         /* make up event mask ext message iovar for event larger than 128 */
5672         msglen = ROUNDUP(WLC_E_LAST, NBBY)/NBBY + EVENTMSGS_EXT_STRUCT_SIZE;
5673         eventmask_msg = (eventmsgs_ext_t*)kmalloc(msglen, GFP_KERNEL);
5674         if (eventmask_msg == NULL) {
5675                 DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", msglen));
5676                 return BCME_NOMEM;
5677         }
5678         bzero(eventmask_msg, msglen);
5679         eventmask_msg->ver = EVENTMSGS_VER;
5680         eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
5681
5682         /* Read event_msgs_ext mask */
5683         bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, sizeof(iov_buf));
5684         ret2  = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iov_buf, sizeof(iov_buf), FALSE, 0);
5685         if (ret2 != BCME_UNSUPPORTED)
5686                 ret = ret2;
5687         if (ret2 == 0) { /* event_msgs_ext must be supported */
5688                 bcopy(iov_buf, eventmask_msg, msglen);
5689
5690 #ifdef BT_WIFI_HANDOVER
5691                 setbit(eventmask_msg->mask, WLC_E_BT_WIFI_HANDOVER_REQ);
5692 #endif /* BT_WIFI_HANDOVER */
5693
5694                 /* Write updated Event mask */
5695                 eventmask_msg->ver = EVENTMSGS_VER;
5696                 eventmask_msg->command = EVENTMSGS_SET_MASK;
5697                 eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
5698                 bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg,
5699                         msglen, iov_buf, sizeof(iov_buf));
5700                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
5701                         iov_buf, sizeof(iov_buf), TRUE, 0)) < 0) {
5702                         DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret));
5703                         kfree(eventmask_msg);
5704                         goto done;
5705                 }
5706         } else if (ret2 < 0 && ret2 != BCME_UNSUPPORTED) {
5707                 DHD_ERROR(("%s read event mask ext failed %d\n", __FUNCTION__, ret2));
5708                 kfree(eventmask_msg);
5709                 goto done;
5710         } /* unsupported is ok */
5711         kfree(eventmask_msg);
5712
5713         dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
5714                 sizeof(scan_assoc_time), TRUE, 0);
5715         dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
5716                 sizeof(scan_unassoc_time), TRUE, 0);
5717         dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time,
5718                 sizeof(scan_passive_time), TRUE, 0);
5719
5720 #ifdef ARP_OFFLOAD_SUPPORT
5721         /* Set and enable ARP offload feature for STA only  */
5722 #if defined(SOFTAP)
5723         if (arpoe && !ap_fw_loaded) {
5724 #else
5725         if (arpoe) {
5726 #endif 
5727                 dhd_arp_offload_enable(dhd, TRUE);
5728                 dhd_arp_offload_set(dhd, dhd_arp_mode);
5729         } else {
5730                 dhd_arp_offload_enable(dhd, FALSE);
5731                 dhd_arp_offload_set(dhd, 0);
5732         }
5733         dhd_arp_enable = arpoe;
5734 #endif /* ARP_OFFLOAD_SUPPORT */
5735
5736 #ifdef PKT_FILTER_SUPPORT
5737         /* Setup default defintions for pktfilter , enable in suspend */
5738         dhd->pktfilter_count = 6;
5739         /* Setup filter to allow only unicast */
5740         dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00";
5741         dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL;
5742         dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL;
5743         dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL;
5744         /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */
5745         dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB";
5746         /* apply APP pktfilter */
5747         dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806";
5748
5749
5750 #if defined(SOFTAP)
5751         if (ap_fw_loaded) {
5752                 dhd_enable_packet_filter(0, dhd);
5753         }
5754 #endif /* defined(SOFTAP) */
5755         dhd_set_packet_filter(dhd);
5756 #endif /* PKT_FILTER_SUPPORT */
5757 #ifdef DISABLE_11N
5758         bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf));
5759         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
5760                 DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret));
5761 #endif /* DISABLE_11N */
5762
5763         /* query for 'ver' to get version info from firmware */
5764         memset(buf, 0, sizeof(buf));
5765         ptr = buf;
5766         bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf));
5767         if ((ret  = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0)
5768                 DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
5769         else {
5770                 bcmstrtok(&ptr, "\n", 0);
5771                 /* Print fw version info */
5772                 DHD_ERROR(("Firmware version = %s\n", buf));
5773 #if defined(BCMSDIO)
5774                 dhd_set_version_info(dhd, buf);
5775 #endif /* defined(BCMSDIO) */
5776         }
5777
5778 #if defined(BCMSDIO)
5779         dhd_txglom_enable(dhd, TRUE);
5780 #endif /* defined(BCMSDIO) */
5781
5782 #if defined(BCMSDIO)
5783 #ifdef PROP_TXSTATUS
5784         if (disable_proptx ||
5785 #ifdef PROP_TXSTATUS_VSDB
5786                 /* enable WLFC only if the firmware is VSDB when it is in STA mode */
5787                 (dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
5788                  dhd->op_mode != DHD_FLAG_IBSS_MODE) ||
5789 #endif /* PROP_TXSTATUS_VSDB */
5790                 FALSE) {
5791                 wlfc_enable = FALSE;
5792         }
5793
5794 #ifndef DISABLE_11N
5795         bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, iovbuf, sizeof(iovbuf));
5796         if ((ret2 = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
5797                 DHD_ERROR(("%s wl ampdu_hostreorder failed %d\n", __FUNCTION__, ret2));
5798                 if (ret2 != BCME_OK)
5799                         hostreorder = 0;
5800         }
5801 #endif /* DISABLE_11N */
5802
5803
5804         if (wlfc_enable)
5805                 dhd_wlfc_init(dhd);
5806 #ifndef DISABLE_11N
5807         else if (hostreorder)
5808                 dhd_wlfc_hostreorder_init(dhd);
5809 #endif /* DISABLE_11N */
5810
5811 #endif /* PROP_TXSTATUS */
5812 #endif /* BCMSDIO || BCMBUS */
5813 #ifdef PCIE_FULL_DONGLE
5814         /* For FD we need all the packets at DHD to handle intra-BSS forwarding */
5815         if (FW_SUPPORTED(dhd, ap)) {
5816                 wl_ap_isolate = AP_ISOLATE_SENDUP_ALL;
5817                 bcm_mkiovar("ap_isolate", (char *)&wl_ap_isolate, 4, iovbuf, sizeof(iovbuf));
5818                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
5819                         DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
5820         }
5821 #endif /* PCIE_FULL_DONGLE */
5822 #ifdef PNO_SUPPORT
5823         if (!dhd->pno_state) {
5824                 dhd_pno_init(dhd);
5825         }
5826 #endif
5827 #ifdef WL11U
5828         dhd_interworking_enable(dhd);
5829 #endif /* WL11U */
5830 #ifdef RXCB
5831         /* Enable bus rx callback */
5832         bcm_mkiovar("bus:rxcb", (char *)&rxcb, 4, iovbuf, sizeof(iovbuf));
5833         if ((ret =dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
5834                 DHD_ERROR(("%s failed to set RXCB %d\n", __FUNCTION__, ret));
5835 #endif
5836
5837 done:
5838         return ret;
5839 }
5840
5841 void dhd_set_ampdu_rx_tid(struct net_device *dev, int ampdu_rx_tid)
5842 {
5843         int i, ret = 0;
5844         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5845         dhd_pub_t *pub = &dhd->pub;
5846         char iovbuf[32];
5847         for (i = 0; i < 8; i++) { /* One bit each for traffic class CS7 - CS0 */
5848                 struct ampdu_tid_control atc;
5849                 atc.tid = i;
5850                 atc.enable = (ampdu_rx_tid >> i) & 1;
5851                 bcm_mkiovar("ampdu_rx_tid", (char *)&atc, sizeof(atc), iovbuf,sizeof(iovbuf));
5852                 ret = dhd_wl_ioctl_cmd(pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf),TRUE, 0);
5853                 if (ret < 0)
5854                         DHD_ERROR(("%s failed %d\n", __func__, ret));
5855         }
5856 }
5857
5858 int
5859 dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set)
5860 {
5861         char buf[strlen(name) + 1 + cmd_len];
5862         int len = sizeof(buf);
5863         wl_ioctl_t ioc;
5864         int ret;
5865
5866         len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len);
5867
5868         memset(&ioc, 0, sizeof(ioc));
5869
5870         ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR;
5871         ioc.buf = buf;
5872         ioc.len = len;
5873         ioc.set = set;
5874
5875         ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len);
5876         if (!set && ret >= 0)
5877                 memcpy(cmd_buf, buf, cmd_len);
5878
5879         return ret;
5880 }
5881
5882 int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
5883 {
5884         struct dhd_info *dhd = dhdp->info;
5885         struct net_device *dev = NULL;
5886
5887         ASSERT(dhd && dhd->iflist[ifidx]);
5888         dev = dhd->iflist[ifidx]->net;
5889         ASSERT(dev);
5890
5891         if (netif_running(dev)) {
5892                 DHD_ERROR(("%s: Must be down to change its MTU", dev->name));
5893                 return BCME_NOTDOWN;
5894         }
5895
5896 #define DHD_MIN_MTU 1500
5897 #define DHD_MAX_MTU 1752
5898
5899         if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) {
5900                 DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu));
5901                 return BCME_BADARG;
5902         }
5903
5904         dev->mtu = new_mtu;
5905         return 0;
5906 }
5907
5908 #ifdef ARP_OFFLOAD_SUPPORT
5909 /* add or remove AOE host ip(s) (up to 8 IPs on the interface)  */
5910 void
5911 aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx)
5912 {
5913         u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */
5914         int i;
5915         int ret;
5916
5917         bzero(ipv4_buf, sizeof(ipv4_buf));
5918
5919         /* display what we've got */
5920         ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx);
5921         DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__));
5922 #ifdef AOE_DBG
5923         dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
5924 #endif
5925         /* now we saved hoste_ip table, clr it in the dongle AOE */
5926         dhd_aoe_hostip_clr(dhd_pub, idx);
5927
5928         if (ret) {
5929                 DHD_ERROR(("%s failed\n", __FUNCTION__));
5930                 return;
5931         }
5932
5933         for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
5934                 if (add && (ipv4_buf[i] == 0)) {
5935                                 ipv4_buf[i] = ipa;
5936                                 add = FALSE; /* added ipa to local table  */
5937                                 DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n",
5938                                 __FUNCTION__, i));
5939                 } else if (ipv4_buf[i] == ipa) {
5940                         ipv4_buf[i]     = 0;
5941                         DHD_ARPOE(("%s: removed IP:%x from temp table %d\n",
5942                                 __FUNCTION__, ipa, i));
5943                 }
5944
5945                 if (ipv4_buf[i] != 0) {
5946                         /* add back host_ip entries from our local cache */
5947                         dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx);
5948                         DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n",
5949                                 __FUNCTION__, ipv4_buf[i], i));
5950                 }
5951         }
5952 #ifdef AOE_DBG
5953         /* see the resulting hostip table */
5954         dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx);
5955         DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__));
5956         dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
5957 #endif
5958 }
5959
5960 /*
5961  * Notification mechanism from kernel to our driver. This function is called by the Linux kernel
5962  * whenever there is an event related to an IP address.
5963  * ptr : kernel provided pointer to IP address that has changed
5964  */
5965 static int dhd_inetaddr_notifier_call(struct notifier_block *this,
5966         unsigned long event,
5967         void *ptr)
5968 {
5969         struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
5970
5971         dhd_info_t *dhd;
5972         dhd_pub_t *dhd_pub;
5973         int idx;
5974
5975         if (!dhd_arp_enable)
5976                 return NOTIFY_DONE;
5977         if (!ifa || !(ifa->ifa_dev->dev))
5978                 return NOTIFY_DONE;
5979
5980 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
5981         /* Filter notifications meant for non Broadcom devices */
5982         if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) &&
5983             (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) {
5984 #if defined(WL_ENABLE_P2P_IF)
5985                 if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops))
5986 #endif /* WL_ENABLE_P2P_IF */
5987                         return NOTIFY_DONE;
5988         }
5989 #endif /* LINUX_VERSION_CODE */
5990
5991         dhd = DHD_DEV_INFO(ifa->ifa_dev->dev);
5992         if (!dhd)
5993                 return NOTIFY_DONE;
5994
5995         dhd_pub = &dhd->pub;
5996
5997         if (dhd_pub->arp_version == 1) {
5998                 idx = 0;
5999         }
6000         else {
6001                 for (idx = 0; idx < DHD_MAX_IFS; idx++) {
6002                         if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev)
6003                         break;
6004                 }
6005                 if (idx < DHD_MAX_IFS)
6006                         DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net,
6007                                 dhd->iflist[idx]->name, dhd->iflist[idx]->idx));
6008                 else {
6009                         DHD_ERROR(("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label));
6010                         idx = 0;
6011                 }
6012         }
6013
6014         switch (event) {
6015                 case NETDEV_UP:
6016                         DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n",
6017                                 __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
6018
6019                         if (dhd->pub.busstate != DHD_BUS_DATA) {
6020                                 DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__));
6021                                 if (dhd->pend_ipaddr) {
6022                                         DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n",
6023                                                 __FUNCTION__, dhd->pend_ipaddr));
6024                                 }
6025                                 dhd->pend_ipaddr = ifa->ifa_address;
6026                                 break;
6027                         }
6028
6029 #ifdef AOE_IP_ALIAS_SUPPORT
6030                         DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n",
6031                                 __FUNCTION__));
6032                         aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx);
6033 #endif /* AOE_IP_ALIAS_SUPPORT */
6034                         break;
6035
6036                 case NETDEV_DOWN:
6037                         DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n",
6038                                 __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
6039                         dhd->pend_ipaddr = 0;
6040 #ifdef AOE_IP_ALIAS_SUPPORT
6041                         DHD_ARPOE(("%s:interface is down, AOE clr all for this if\n",
6042                                 __FUNCTION__));
6043                         aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx);
6044 #else
6045                         dhd_aoe_hostip_clr(&dhd->pub, idx);
6046                         dhd_aoe_arp_clr(&dhd->pub, idx);
6047 #endif /* AOE_IP_ALIAS_SUPPORT */
6048                         break;
6049
6050                 default:
6051                         DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n",
6052                                 __func__, ifa->ifa_label, event));
6053                         break;
6054         }
6055         return NOTIFY_DONE;
6056 }
6057 #endif /* ARP_OFFLOAD_SUPPORT */
6058
6059 #ifdef CONFIG_IPV6
6060 /* Neighbor Discovery Offload: defered handler */
6061 static void
6062 dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event)
6063 {
6064         struct ipv6_work_info_t *ndo_work = (struct ipv6_work_info_t *)event_data;
6065         dhd_pub_t       *pub = &((dhd_info_t *)dhd_info)->pub;
6066         int             ret;
6067
6068         if (event != DHD_WQ_WORK_IPV6_NDO) {
6069                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
6070                 return;
6071         }
6072
6073         if (!ndo_work) {
6074                 DHD_ERROR(("%s: ipv6 work info is not initialized \n", __FUNCTION__));
6075                 return;
6076         }
6077
6078         if (!pub) {
6079                 DHD_ERROR(("%s: dhd pub is not initialized \n", __FUNCTION__));
6080                 return;
6081         }
6082
6083         if (ndo_work->if_idx) {
6084                 DHD_ERROR(("%s: idx %d \n", __FUNCTION__, ndo_work->if_idx));
6085                 return;
6086         }
6087
6088         switch (ndo_work->event) {
6089                 case NETDEV_UP:
6090                         DHD_TRACE(("%s: Enable NDO and add ipv6 into table \n ", __FUNCTION__));
6091                         ret = dhd_ndo_enable(pub, TRUE);
6092                         if (ret < 0) {
6093                                 DHD_ERROR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, ret));
6094                         }
6095
6096                         ret = dhd_ndo_add_ip(pub, &ndo_work->ipv6_addr[0], ndo_work->if_idx);
6097                         if (ret < 0) {
6098                                 DHD_ERROR(("%s: Adding host ip for NDO failed %d\n",
6099                                         __FUNCTION__, ret));
6100                         }
6101                         break;
6102                 case NETDEV_DOWN:
6103                         DHD_TRACE(("%s: clear ipv6 table \n", __FUNCTION__));
6104                         ret = dhd_ndo_remove_ip(pub, ndo_work->if_idx);
6105                         if (ret < 0) {
6106                                 DHD_ERROR(("%s: Removing host ip for NDO failed %d\n",
6107                                         __FUNCTION__, ret));
6108                                 goto done;
6109                         }
6110
6111                         ret = dhd_ndo_enable(pub, FALSE);
6112                         if (ret < 0) {
6113                                 DHD_ERROR(("%s: disabling NDO Failed %d\n", __FUNCTION__, ret));
6114                                 goto done;
6115                         }
6116                         break;
6117                 default:
6118                         DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__));
6119                         break;
6120         }
6121 done:
6122         /* free ndo_work. alloced while scheduling the work */
6123         kfree(ndo_work);
6124
6125         return;
6126 }
6127
6128 /*
6129  * Neighbor Discovery Offload: Called when an interface
6130  * is assigned with ipv6 address.
6131  * Handles only primary interface
6132  */
6133 static int dhd_inet6addr_notifier_call(struct notifier_block *this,
6134         unsigned long event,
6135         void *ptr)
6136 {
6137         dhd_info_t *dhd;
6138         dhd_pub_t *dhd_pub;
6139         struct inet6_ifaddr *inet6_ifa = ptr;
6140         struct in6_addr *ipv6_addr = &inet6_ifa->addr;
6141         struct ipv6_work_info_t *ndo_info;
6142         int idx = 0; /* REVISIT */
6143
6144 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
6145         /* Filter notifications meant for non Broadcom devices */
6146         if (inet6_ifa->idev->dev->netdev_ops != &dhd_ops_pri) {
6147                         return NOTIFY_DONE;
6148         }
6149 #endif /* LINUX_VERSION_CODE */
6150
6151         dhd = DHD_DEV_INFO(inet6_ifa->idev->dev);
6152         if (!dhd)
6153                 return NOTIFY_DONE;
6154
6155         if (dhd->iflist[idx] && dhd->iflist[idx]->net != inet6_ifa->idev->dev)
6156                 return NOTIFY_DONE;
6157         dhd_pub = &dhd->pub;
6158         if (!FW_SUPPORTED(dhd_pub, ndoe))
6159                 return NOTIFY_DONE;
6160
6161         ndo_info = (struct ipv6_work_info_t *)kzalloc(sizeof(struct ipv6_work_info_t), GFP_ATOMIC);
6162         if (!ndo_info) {
6163                 DHD_ERROR(("%s: ipv6 work alloc failed\n", __FUNCTION__));
6164                 return NOTIFY_DONE;
6165         }
6166
6167         ndo_info->event = event;
6168         ndo_info->if_idx = idx;
6169         memcpy(&ndo_info->ipv6_addr[0], ipv6_addr, IPV6_ADDR_LEN);
6170
6171         /* defer the work to thread as it may block kernel */
6172         dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)ndo_info, DHD_WQ_WORK_IPV6_NDO,
6173                 dhd_inet6_work_handler, DHD_WORK_PRIORITY_LOW);
6174         return NOTIFY_DONE;
6175 }
6176 #endif /* #ifdef CONFIG_IPV6 */
6177
6178 int
6179 dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock)
6180 {
6181         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
6182         dhd_if_t *ifp;
6183         struct net_device *net = NULL;
6184         int err = 0;
6185         uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 };
6186
6187         DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
6188
6189         ASSERT(dhd && dhd->iflist[ifidx]);
6190         ifp = dhd->iflist[ifidx];
6191         net = ifp->net;
6192         ASSERT(net && (ifp->idx == ifidx));
6193
6194 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
6195         ASSERT(!net->open);
6196         net->get_stats = dhd_get_stats;
6197         net->do_ioctl = dhd_ioctl_entry;
6198         net->hard_start_xmit = dhd_start_xmit;
6199         net->set_mac_address = dhd_set_mac_address;
6200         net->set_multicast_list = dhd_set_multicast_list;
6201         net->open = net->stop = NULL;
6202 #else
6203         ASSERT(!net->netdev_ops);
6204         net->netdev_ops = &dhd_ops_virt;