Merge remote-tracking branches 'asoc/fix/sgtl5000', 'asoc/fix/topology' and 'asoc...
[cascardo/linux.git] / drivers / staging / wilc1000 / linux_mon.c
1 /*!
2  *  @file       linux_mon.c
3  *  @brief      File Operations OS wrapper functionality
4  *  @author     mdaftedar
5  *  @sa         wilc_wfi_netdevice.h
6  *  @date       01 MAR 2012
7  *  @version    1.0
8  */
9
10 #ifndef SIMULATION
11 #include "wilc_wfi_cfgoperations.h"
12 #include "linux_wlan_common.h"
13 #include "wilc_wlan_if.h"
14 #include "wilc_wlan.h"
15 #endif
16 #ifdef WILC_FULLY_HOSTING_AP
17 #include "wilc_host_ap.h"
18 #endif
19 #ifdef WILC_AP_EXTERNAL_MLME
20 #ifdef SIMULATION
21 #include "wilc_wfi_cfgoperations.h"
22 #endif
23
24 struct wilc_wfi_radiotap_hdr {
25         struct ieee80211_radiotap_header hdr;
26         u8 rate;
27         /* u32 channel; */
28 } __attribute__((packed));
29
30 struct wilc_wfi_radiotap_cb_hdr {
31         struct ieee80211_radiotap_header hdr;
32         u8 rate;
33         u8 dump;
34         u16 tx_flags;
35         /* u32 channel; */
36 } __attribute__((packed));
37
38 extern linux_wlan_t *g_linux_wlan;
39
40 static struct net_device *wilc_wfi_mon; /* global monitor netdev */
41
42 #ifdef SIMULATION
43 extern int WILC_WFI_Tx(struct sk_buff *skb, struct net_device *dev);
44 #elif USE_WIRELESS
45 extern int  mac_xmit(struct sk_buff *skb, struct net_device *dev);
46 #endif
47
48
49 u8 srcAdd[6];
50 u8 bssid[6];
51 u8 broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
52 /**
53  *  @brief      WILC_WFI_monitor_rx
54  *  @details
55  *  @param[in]
56  *  @return     int : Return 0 on Success
57  *  @author     mdaftedar
58  *  @date       12 JUL 2012
59  *  @version    1.0
60  */
61
62 #define IEEE80211_RADIOTAP_F_TX_RTS     0x0004  /* used rts/cts handshake */
63 #define IEEE80211_RADIOTAP_F_TX_FAIL    0x0001  /* failed due to excessive*/
64 #define IS_MANAGMEMENT                          0x100
65 #define IS_MANAGMEMENT_CALLBACK                 0x080
66 #define IS_MGMT_STATUS_SUCCES                   0x040
67 #define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff)
68
69 void WILC_WFI_monitor_rx(uint8_t *buff, uint32_t size)
70 {
71         uint32_t header, pkt_offset;
72         struct sk_buff *skb = NULL;
73         struct wilc_wfi_radiotap_hdr *hdr;
74         struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
75
76         PRINT_INFO(HOSTAPD_DBG, "In monitor interface receive function\n");
77
78         /*   struct WILC_WFI_priv *priv = netdev_priv(dev); */
79
80         /*   priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); */
81
82         /* Bug 4601 */
83         if (wilc_wfi_mon == NULL)
84                 return;
85
86         if (!netif_running(wilc_wfi_mon)) {
87                 PRINT_INFO(HOSTAPD_DBG, "Monitor interface already RUNNING\n");
88                 return;
89         }
90
91         /* Get WILC header */
92         memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET);
93
94         /* The packet offset field conain info about what type of managment frame */
95         /* we are dealing with and ack status */
96         pkt_offset = GET_PKT_OFFSET(header);
97
98         if (pkt_offset & IS_MANAGMEMENT_CALLBACK) {
99
100                 /* hostapd callback mgmt frame */
101
102                 skb = dev_alloc_skb(size + sizeof(struct wilc_wfi_radiotap_cb_hdr));
103                 if (skb == NULL) {
104                         PRINT_INFO(HOSTAPD_DBG, "Monitor if : No memory to allocate skb");
105                         return;
106                 }
107
108                 memcpy(skb_put(skb, size), buff, size);
109
110                 cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *) skb_push(skb, sizeof(*cb_hdr));
111                 memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr));
112
113                 cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
114
115                 cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr));
116
117                 cb_hdr->hdr.it_present = cpu_to_le32(
118                                 (1 << IEEE80211_RADIOTAP_RATE) |
119                                 (1 << IEEE80211_RADIOTAP_TX_FLAGS));
120
121                 cb_hdr->rate = 5; /* txrate->bitrate / 5; */
122
123                 if (pkt_offset & IS_MGMT_STATUS_SUCCES) {
124                         /* success */
125                         cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_RTS;
126                 } else {
127                         cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_FAIL;
128                 }
129
130         } else {
131
132                 skb = dev_alloc_skb(size + sizeof(struct wilc_wfi_radiotap_hdr));
133
134                 if (skb == NULL) {
135                         PRINT_INFO(HOSTAPD_DBG, "Monitor if : No memory to allocate skb");
136                         return;
137                 }
138
139                 /* skb = skb_copy_expand(tx_skb, sizeof(*hdr), 0, GFP_ATOMIC); */
140                 /* if (skb == NULL) */
141                 /*      return; */
142
143                 memcpy(skb_put(skb, size), buff, size);
144                 hdr = (struct wilc_wfi_radiotap_hdr *) skb_push(skb, sizeof(*hdr));
145                 memset(hdr, 0, sizeof(struct wilc_wfi_radiotap_hdr));
146                 hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
147                 /* hdr->hdr.it_pad = 0; */
148                 hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_hdr));
149                 PRINT_INFO(HOSTAPD_DBG, "Radiotap len %d\n", hdr->hdr.it_len);
150                 hdr->hdr.it_present = cpu_to_le32
151                                 (1 << IEEE80211_RADIOTAP_RATE);                   /* | */
152                 /* (1 << IEEE80211_RADIOTAP_CHANNEL)); */
153                 PRINT_INFO(HOSTAPD_DBG, "Presentflags %d\n", hdr->hdr.it_present);
154                 hdr->rate = 5; /* txrate->bitrate / 5; */
155
156         }
157
158 /*      if(INFO || if(skb->data[9] == 0x00 || skb->data[9] == 0xb0))
159  *      {
160  *              for(i=0;i<skb->len;i++)
161  *                      PRINT_INFO(HOSTAPD_DBG,"Mon RxData[%d] = %02x\n",i,skb->data[i]);
162  *      }*/
163
164
165         skb->dev = wilc_wfi_mon;
166         skb_set_mac_header(skb, 0);
167         skb->ip_summed = CHECKSUM_UNNECESSARY;
168         skb->pkt_type = PACKET_OTHERHOST;
169         skb->protocol = htons(ETH_P_802_2);
170         memset(skb->cb, 0, sizeof(skb->cb));
171
172         netif_rx(skb);
173
174
175 }
176
177 struct tx_complete_mon_data {
178         int size;
179         void *buff;
180 };
181
182 static void mgmt_tx_complete(void *priv, int status)
183 {
184
185         /* struct sk_buff *skb2; */
186         /* struct wilc_wfi_radiotap_cb_hdr *cb_hdr; */
187
188         struct tx_complete_mon_data *pv_data = (struct tx_complete_mon_data *)priv;
189         u8 *buf =  pv_data->buff;
190
191
192
193         if (status == 1) {
194                 if (INFO || buf[0] == 0x10 || buf[0] == 0xb0)
195                         PRINT_INFO(HOSTAPD_DBG, "Packet sent successfully - Size = %d - Address = %p.\n", pv_data->size, pv_data->buff);
196         } else {
197                 PRINT_INFO(HOSTAPD_DBG, "Couldn't send packet - Size = %d - Address = %p.\n", pv_data->size, pv_data->buff);
198         }
199
200
201 /*                      //(skb->data[9] == 0x00 || skb->data[9] == 0xb0 || skb->data[9] == 0x40 ||  skb->data[9] == 0xd0 )
202  *      {
203  *              skb2 = dev_alloc_skb(pv_data->size+sizeof(struct wilc_wfi_radiotap_cb_hdr));
204  *
205  *              memcpy(skb_put(skb2,pv_data->size),pv_data->buff, pv_data->size);
206  *
207  *              cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *) skb_push(skb2, sizeof(*cb_hdr));
208  *              memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr));
209  *
210  *               cb_hdr->hdr.it_version = 0;//PKTHDR_RADIOTAP_VERSION;
211  *
212  *              cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr));
213  *
214  *       cb_hdr->hdr.it_present = cpu_to_le32(
215  *                                        (1 << IEEE80211_RADIOTAP_RATE) |
216  *                                       (1 << IEEE80211_RADIOTAP_TX_FLAGS));
217  *
218  *              cb_hdr->rate = 5;//txrate->bitrate / 5;
219  *              cb_hdr->tx_flags = 0x0004;
220  *
221  *              skb2->dev = wilc_wfi_mon;
222  *              skb_set_mac_header(skb2, 0);
223  *              skb2->ip_summed = CHECKSUM_UNNECESSARY;
224  *              skb2->pkt_type = PACKET_OTHERHOST;
225  *              skb2->protocol = htons(ETH_P_802_2);
226  *              memset(skb2->cb, 0, sizeof(skb2->cb));
227  *
228  *              netif_rx(skb2);
229  *      }*/
230
231         /* incase of fully hosting mode, the freeing will be done in response to the cfg packet */
232         #ifndef WILC_FULLY_HOSTING_AP
233         kfree(pv_data->buff);
234
235         kfree(pv_data);
236         #endif
237 }
238 static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len)
239 {
240         linux_wlan_t *nic;
241         struct tx_complete_mon_data *mgmt_tx = NULL;
242
243         if (dev == NULL) {
244                 PRINT_D(HOSTAPD_DBG, "ERROR: dev == NULL\n");
245                 return WILC_FAIL;
246         }
247         nic = netdev_priv(dev);
248
249         netif_stop_queue(dev);
250         mgmt_tx = kmalloc(sizeof(struct tx_complete_mon_data), GFP_ATOMIC);
251         if (mgmt_tx == NULL) {
252                 PRINT_ER("Failed to allocate memory for mgmt_tx structure\n");
253                 return WILC_FAIL;
254         }
255
256         #ifdef WILC_FULLY_HOSTING_AP
257         /* add space for the pointer to tx_complete_mon_data */
258         len += sizeof(struct tx_complete_mon_data *);
259         #endif
260
261         mgmt_tx->buff = kmalloc(len, GFP_ATOMIC);
262         if (mgmt_tx->buff == NULL) {
263                 PRINT_ER("Failed to allocate memory for mgmt_tx buff\n");
264                 return WILC_FAIL;
265
266         }
267
268         mgmt_tx->size = len;
269
270         #ifndef WILC_FULLY_HOSTING_AP
271         memcpy(mgmt_tx->buff, buf, len);
272         #else
273         memcpy(mgmt_tx->buff, buf, len - sizeof(struct tx_complete_mon_data *));
274         memcpy((mgmt_tx->buff) + (len - sizeof(struct tx_complete_mon_data *)), &mgmt_tx, sizeof(struct tx_complete_mon_data *));
275
276         /* filter data frames to handle it's PS */
277         if (filter_monitor_data_frames((mgmt_tx->buff), len) == true) {
278                 return;
279         }
280
281         #endif /* WILC_FULLY_HOSTING_AP */
282
283         g_linux_wlan->oup.wlan_add_mgmt_to_tx_que(mgmt_tx, mgmt_tx->buff, mgmt_tx->size, mgmt_tx_complete);
284
285         netif_wake_queue(dev);
286         return 0;
287 }
288
289 /**
290  *  @brief      WILC_WFI_mon_xmit
291  *  @details
292  *  @param[in]
293  *  @return     int : Return 0 on Success
294  *  @author     mdaftedar
295  *  @date       12 JUL 2012
296  *  @version    1.0
297  */
298 static netdev_tx_t WILC_WFI_mon_xmit(struct sk_buff *skb,
299                                      struct net_device *dev)
300 {
301         struct ieee80211_radiotap_header *rtap_hdr;
302         u32 rtap_len, i, ret = 0;
303         struct WILC_WFI_mon_priv  *mon_priv;
304
305         struct sk_buff *skb2;
306         struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
307
308         /* Bug 4601 */
309         if (wilc_wfi_mon == NULL)
310                 return WILC_FAIL;
311
312         /* if(skb->data[3] == 0x10 || skb->data[3] == 0xb0) */
313
314         mon_priv = netdev_priv(wilc_wfi_mon);
315
316         if (mon_priv == NULL) {
317                 PRINT_ER("Monitor interface private structure is NULL\n");
318                 return WILC_FAIL;
319         }
320
321         rtap_hdr = (struct ieee80211_radiotap_header *)skb->data;
322
323         rtap_len = ieee80211_get_radiotap_len(skb->data);
324         if (skb->len < rtap_len) {
325                 PRINT_ER("Error in radiotap header\n");
326                 return -1;
327         }
328         /* skip the radiotap header */
329         PRINT_INFO(HOSTAPD_DBG, "Radiotap len: %d\n", rtap_len);
330
331         if (INFO) {
332                 for (i = 0; i < rtap_len; i++)
333                         PRINT_INFO(HOSTAPD_DBG, "Radiotap_hdr[%d] %02x\n", i, skb->data[i]);
334         }
335         /* Skip the ratio tap header */
336         skb_pull(skb, rtap_len);
337
338         if (skb->data[0] == 0xc0)
339                 PRINT_INFO(HOSTAPD_DBG, "%x:%x:%x:%x:%x%x\n", skb->data[4], skb->data[5], skb->data[6], skb->data[7], skb->data[8], skb->data[9]);
340
341         if (skb->data[0] == 0xc0 && (!(memcmp(broadcast, &skb->data[4], 6)))) {
342                 skb2 = dev_alloc_skb(skb->len + sizeof(struct wilc_wfi_radiotap_cb_hdr));
343
344                 memcpy(skb_put(skb2, skb->len), skb->data, skb->len);
345
346                 cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *) skb_push(skb2, sizeof(*cb_hdr));
347                 memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr));
348
349                 cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
350
351                 cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr));
352
353                 cb_hdr->hdr.it_present = cpu_to_le32(
354                                 (1 << IEEE80211_RADIOTAP_RATE) |
355                                 (1 << IEEE80211_RADIOTAP_TX_FLAGS));
356
357                 cb_hdr->rate = 5; /* txrate->bitrate / 5; */
358                 cb_hdr->tx_flags = 0x0004;
359
360                 skb2->dev = wilc_wfi_mon;
361                 skb_set_mac_header(skb2, 0);
362                 skb2->ip_summed = CHECKSUM_UNNECESSARY;
363                 skb2->pkt_type = PACKET_OTHERHOST;
364                 skb2->protocol = htons(ETH_P_802_2);
365                 memset(skb2->cb, 0, sizeof(skb2->cb));
366
367                 netif_rx(skb2);
368
369                 return 0;
370         }
371         skb->dev = mon_priv->real_ndev;
372
373         PRINT_INFO(HOSTAPD_DBG, "Skipping the radiotap header\n");
374
375
376
377         /* actual deliver of data is device-specific, and not shown here */
378         PRINT_INFO(HOSTAPD_DBG, "SKB netdevice name = %s\n", skb->dev->name);
379         PRINT_INFO(HOSTAPD_DBG, "MONITOR real dev name = %s\n", mon_priv->real_ndev->name);
380
381         #ifdef SIMULATION
382         ret = WILC_WFI_Tx(skb, mon_priv->real_ndev);
383         #elif USE_WIRELESS
384         /* Identify if Ethernet or MAC header (data or mgmt) */
385         memcpy(srcAdd, &skb->data[10], 6);
386         memcpy(bssid, &skb->data[16], 6);
387         /* if source address and bssid fields are equal>>Mac header */
388         /*send it to mgmt frames handler */
389         if (!(memcmp(srcAdd, bssid, 6))) {
390                 mon_mgmt_tx(mon_priv->real_ndev, skb->data, skb->len);
391                 dev_kfree_skb(skb);
392         } else
393                 ret = mac_xmit(skb, mon_priv->real_ndev);
394         #endif
395
396         /* return NETDEV_TX_OK; */
397         return ret;
398 }
399
400 static const struct net_device_ops wilc_wfi_netdev_ops = {
401         .ndo_start_xmit         = WILC_WFI_mon_xmit,
402
403 };
404
405 #ifdef WILC_FULLY_HOSTING_AP
406 /*
407  *  @brief                      WILC_mgm_HOSTAPD_ACK
408  *  @details            report the status of transmitted mgmt frames to HOSTAPD
409  *  @param[in]          priv : pointer to tx_complete_mon_data struct
410  *                              bStatus : status of transmission
411  *  @author             Abd Al-Rahman Diab
412  *  @date                       9 May 2013
413  *  @version            1.0
414  */
415 void WILC_mgm_HOSTAPD_ACK(void *priv, bool bStatus)
416 {
417         struct sk_buff *skb;
418         struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
419
420         struct tx_complete_mon_data *pv_data = (struct tx_complete_mon_data *)priv;
421         u8 *buf =  pv_data->buff;
422
423         /* len of the original frame without the added pointer at the tail */
424         u16 u16len = (pv_data->size) - sizeof(struct tx_complete_mon_data *);
425
426
427         /*if(bStatus == 1){
428          *      if(INFO || buf[0] == 0x10 || buf[0] == 0xb0)
429          *      PRINT_D(HOSTAPD_DBG,"Packet sent successfully - Size = %d - Address = %p.\n",u16len,pv_data->buff);
430          * }else{
431          *              PRINT_D(HOSTAPD_DBG,"Couldn't send packet - Size = %d - Address = %p.\n",u16len,pv_data->buff);
432          *      }
433          */
434
435         /* (skb->data[9] == 0x00 || skb->data[9] == 0xb0 || skb->data[9] == 0x40 ||  skb->data[9] == 0xd0 ) */
436         {
437                 skb = dev_alloc_skb(u16len + sizeof(struct wilc_wfi_radiotap_cb_hdr));
438
439                 memcpy(skb_put(skb, u16len), pv_data->buff, u16len);
440
441                 cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *) skb_push(skb, sizeof(*cb_hdr));
442                 memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr));
443
444                 cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
445
446                 cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr));
447
448                 cb_hdr->hdr.it_present = cpu_to_le32(
449                                 (1 << IEEE80211_RADIOTAP_RATE) |
450                                 (1 << IEEE80211_RADIOTAP_TX_FLAGS));
451
452                 cb_hdr->rate = 5; /* txrate->bitrate / 5; */
453
454
455                 if (bStatus) {
456                         /* success */
457                         cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_RTS;
458                 } else {
459                         cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_FAIL;
460                 }
461
462                 skb->dev = wilc_wfi_mon;
463                 skb_set_mac_header(skb, 0);
464                 skb->ip_summed = CHECKSUM_UNNECESSARY;
465                 skb->pkt_type = PACKET_OTHERHOST;
466                 skb->protocol = htons(ETH_P_802_2);
467                 memset(skb->cb, 0, sizeof(skb->cb));
468
469                 netif_rx(skb);
470         }
471
472         /* incase of fully hosting mode, the freeing will be done in response to the cfg packet */
473         kfree(pv_data->buff);
474
475         kfree(pv_data);
476
477 }
478 #endif /* WILC_FULLY_HOSTING_AP */
479
480 /**
481  *  @brief      WILC_WFI_mon_setup
482  *  @details
483  *  @param[in]
484  *  @return     int : Return 0 on Success
485  *  @author     mdaftedar
486  *  @date       12 JUL 2012
487  *  @version    1.0
488  */
489 static void WILC_WFI_mon_setup(struct net_device *dev)
490 {
491
492         dev->netdev_ops = &wilc_wfi_netdev_ops;
493         /* dev->destructor = free_netdev; */
494         PRINT_INFO(CORECONFIG_DBG, "In Ethernet setup function\n");
495         ether_setup(dev);
496         dev->tx_queue_len = 0;
497         dev->type = ARPHRD_IEEE80211_RADIOTAP;
498         memset(dev->dev_addr, 0, ETH_ALEN);
499
500         #ifdef USE_WIRELESS
501         {
502                 /* u8 * mac_add; */
503                 unsigned char mac_add[] = {0x00, 0x50, 0xc2, 0x5e, 0x10, 0x8f};
504                 /* priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); */
505                 /* mac_add = (u8*)WILC_MALLOC(ETH_ALEN); */
506                 /* status = host_int_get_MacAddress(priv->hWILCWFIDrv,mac_add); */
507                 /* mac_add[ETH_ALEN-1]+=1; */
508                 memcpy(dev->dev_addr, mac_add, ETH_ALEN);
509         }
510         #else
511         dev->dev_addr[0] = 0x12;
512         #endif
513
514 }
515
516 /**
517  *  @brief      WILC_WFI_init_mon_interface
518  *  @details
519  *  @param[in]
520  *  @return     int : Return 0 on Success
521  *  @author     mdaftedar
522  *  @date       12 JUL 2012
523  *  @version    1.0
524  */
525 struct net_device *WILC_WFI_init_mon_interface(const char *name, struct net_device *real_dev)
526 {
527
528
529         u32 ret = WILC_SUCCESS;
530         struct WILC_WFI_mon_priv *priv;
531
532         /*If monitor interface is already initialized, return it*/
533         if (wilc_wfi_mon) {
534                 return wilc_wfi_mon;
535         }
536
537         wilc_wfi_mon = alloc_etherdev(sizeof(struct WILC_WFI_mon_priv));
538         if (!wilc_wfi_mon) {
539                 PRINT_ER("failed to allocate memory\n");
540                 return NULL;
541
542         }
543
544         wilc_wfi_mon->type = ARPHRD_IEEE80211_RADIOTAP;
545         strncpy(wilc_wfi_mon->name, name, IFNAMSIZ);
546         wilc_wfi_mon->name[IFNAMSIZ - 1] = 0;
547         wilc_wfi_mon->netdev_ops = &wilc_wfi_netdev_ops;
548
549         ret = register_netdevice(wilc_wfi_mon);
550         if (ret) {
551                 PRINT_ER(" register_netdevice failed (%d)\n", ret);
552                 return NULL;
553         }
554         priv = netdev_priv(wilc_wfi_mon);
555         if (priv == NULL) {
556                 PRINT_ER("private structure is NULL\n");
557                 return NULL;
558         }
559
560         priv->real_ndev = real_dev;
561
562         return wilc_wfi_mon;
563 }
564
565 /**
566  *  @brief      WILC_WFI_deinit_mon_interface
567  *  @details
568  *  @param[in]
569  *  @return     int : Return 0 on Success
570  *  @author     mdaftedar
571  *  @date       12 JUL 2012
572  *  @version    1.0
573  */
574 int WILC_WFI_deinit_mon_interface()
575 {
576         bool rollback_lock = false;
577
578         if (wilc_wfi_mon != NULL) {
579                 PRINT_D(HOSTAPD_DBG, "In Deinit monitor interface\n");
580                 PRINT_D(HOSTAPD_DBG, "RTNL is being locked\n");
581                 if (rtnl_is_locked()) {
582                         rtnl_unlock();
583                         rollback_lock = true;
584                 }
585                 PRINT_D(HOSTAPD_DBG, "Unregister netdev\n");
586                 unregister_netdev(wilc_wfi_mon);
587                 /* free_netdev(wilc_wfi_mon); */
588
589                 if (rollback_lock) {
590                         rtnl_lock();
591                         rollback_lock = false;
592                 }
593                 wilc_wfi_mon = NULL;
594         }
595         return WILC_SUCCESS;
596
597 }
598 #endif /* WILC_AP_EXTERNAL_MLME */