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