3 * @brief File Operations OS wrapper functionality
5 * @sa wilc_wfi_netdevice.h
9 #include "wilc_wfi_cfgoperations.h"
10 #include "linux_wlan_common.h"
11 #include "wilc_wlan_if.h"
12 #include "wilc_wlan.h"
14 #ifdef WILC_FULLY_HOSTING_AP
15 #include "wilc_host_ap.h"
17 #ifdef WILC_AP_EXTERNAL_MLME
19 struct wilc_wfi_radiotap_hdr
{
20 struct ieee80211_radiotap_header hdr
;
23 } __attribute__((packed
));
25 struct wilc_wfi_radiotap_cb_hdr
{
26 struct ieee80211_radiotap_header hdr
;
31 } __attribute__((packed
));
33 extern linux_wlan_t
*g_linux_wlan
;
35 static struct net_device
*wilc_wfi_mon
; /* global monitor netdev */
38 extern int mac_xmit(struct sk_buff
*skb
, struct net_device
*dev
);
44 u8 broadcast
[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
46 * @brief WILC_WFI_monitor_rx
49 * @return int : Return 0 on Success
55 #define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
56 #define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive*/
57 #define IS_MANAGMEMENT 0x100
58 #define IS_MANAGMEMENT_CALLBACK 0x080
59 #define IS_MGMT_STATUS_SUCCES 0x040
60 #define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff)
62 void WILC_WFI_monitor_rx(uint8_t *buff
, uint32_t size
)
64 uint32_t header
, pkt_offset
;
65 struct sk_buff
*skb
= NULL
;
66 struct wilc_wfi_radiotap_hdr
*hdr
;
67 struct wilc_wfi_radiotap_cb_hdr
*cb_hdr
;
69 PRINT_INFO(HOSTAPD_DBG
, "In monitor interface receive function\n");
71 /* struct WILC_WFI_priv *priv = netdev_priv(dev); */
73 /* priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); */
76 if (wilc_wfi_mon
== NULL
)
79 if (!netif_running(wilc_wfi_mon
)) {
80 PRINT_INFO(HOSTAPD_DBG
, "Monitor interface already RUNNING\n");
85 memcpy(&header
, (buff
- HOST_HDR_OFFSET
), HOST_HDR_OFFSET
);
87 /* The packet offset field conain info about what type of managment frame */
88 /* we are dealing with and ack status */
89 pkt_offset
= GET_PKT_OFFSET(header
);
91 if (pkt_offset
& IS_MANAGMEMENT_CALLBACK
) {
93 /* hostapd callback mgmt frame */
95 skb
= dev_alloc_skb(size
+ sizeof(struct wilc_wfi_radiotap_cb_hdr
));
97 PRINT_INFO(HOSTAPD_DBG
, "Monitor if : No memory to allocate skb");
101 memcpy(skb_put(skb
, size
), buff
, size
);
103 cb_hdr
= (struct wilc_wfi_radiotap_cb_hdr
*) skb_push(skb
, sizeof(*cb_hdr
));
104 memset(cb_hdr
, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr
));
106 cb_hdr
->hdr
.it_version
= 0; /* PKTHDR_RADIOTAP_VERSION; */
108 cb_hdr
->hdr
.it_len
= cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr
));
110 cb_hdr
->hdr
.it_present
= cpu_to_le32(
111 (1 << IEEE80211_RADIOTAP_RATE
) |
112 (1 << IEEE80211_RADIOTAP_TX_FLAGS
));
114 cb_hdr
->rate
= 5; /* txrate->bitrate / 5; */
116 if (pkt_offset
& IS_MGMT_STATUS_SUCCES
) {
118 cb_hdr
->tx_flags
= IEEE80211_RADIOTAP_F_TX_RTS
;
120 cb_hdr
->tx_flags
= IEEE80211_RADIOTAP_F_TX_FAIL
;
125 skb
= dev_alloc_skb(size
+ sizeof(struct wilc_wfi_radiotap_hdr
));
128 PRINT_INFO(HOSTAPD_DBG
, "Monitor if : No memory to allocate skb");
132 /* skb = skb_copy_expand(tx_skb, sizeof(*hdr), 0, GFP_ATOMIC); */
133 /* if (skb == NULL) */
136 memcpy(skb_put(skb
, size
), buff
, size
);
137 hdr
= (struct wilc_wfi_radiotap_hdr
*) skb_push(skb
, sizeof(*hdr
));
138 memset(hdr
, 0, sizeof(struct wilc_wfi_radiotap_hdr
));
139 hdr
->hdr
.it_version
= 0; /* PKTHDR_RADIOTAP_VERSION; */
140 /* hdr->hdr.it_pad = 0; */
141 hdr
->hdr
.it_len
= cpu_to_le16(sizeof(struct wilc_wfi_radiotap_hdr
));
142 PRINT_INFO(HOSTAPD_DBG
, "Radiotap len %d\n", hdr
->hdr
.it_len
);
143 hdr
->hdr
.it_present
= cpu_to_le32
144 (1 << IEEE80211_RADIOTAP_RATE
); /* | */
145 /* (1 << IEEE80211_RADIOTAP_CHANNEL)); */
146 PRINT_INFO(HOSTAPD_DBG
, "Presentflags %d\n", hdr
->hdr
.it_present
);
147 hdr
->rate
= 5; /* txrate->bitrate / 5; */
151 /* if(INFO || if(skb->data[9] == 0x00 || skb->data[9] == 0xb0))
153 * for(i=0;i<skb->len;i++)
154 * PRINT_INFO(HOSTAPD_DBG,"Mon RxData[%d] = %02x\n",i,skb->data[i]);
158 skb
->dev
= wilc_wfi_mon
;
159 skb_set_mac_header(skb
, 0);
160 skb
->ip_summed
= CHECKSUM_UNNECESSARY
;
161 skb
->pkt_type
= PACKET_OTHERHOST
;
162 skb
->protocol
= htons(ETH_P_802_2
);
163 memset(skb
->cb
, 0, sizeof(skb
->cb
));
170 struct tx_complete_mon_data
{
175 static void mgmt_tx_complete(void *priv
, int status
)
178 /* struct sk_buff *skb2; */
179 /* struct wilc_wfi_radiotap_cb_hdr *cb_hdr; */
181 struct tx_complete_mon_data
*pv_data
= (struct tx_complete_mon_data
*)priv
;
182 u8
*buf
= pv_data
->buff
;
187 if (INFO
|| buf
[0] == 0x10 || buf
[0] == 0xb0)
188 PRINT_INFO(HOSTAPD_DBG
, "Packet sent successfully - Size = %d - Address = %p.\n", pv_data
->size
, pv_data
->buff
);
190 PRINT_INFO(HOSTAPD_DBG
, "Couldn't send packet - Size = %d - Address = %p.\n", pv_data
->size
, pv_data
->buff
);
194 /* //(skb->data[9] == 0x00 || skb->data[9] == 0xb0 || skb->data[9] == 0x40 || skb->data[9] == 0xd0 )
196 * skb2 = dev_alloc_skb(pv_data->size+sizeof(struct wilc_wfi_radiotap_cb_hdr));
198 * memcpy(skb_put(skb2,pv_data->size),pv_data->buff, pv_data->size);
200 * cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *) skb_push(skb2, sizeof(*cb_hdr));
201 * memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr));
203 * cb_hdr->hdr.it_version = 0;//PKTHDR_RADIOTAP_VERSION;
205 * cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr));
207 * cb_hdr->hdr.it_present = cpu_to_le32(
208 * (1 << IEEE80211_RADIOTAP_RATE) |
209 * (1 << IEEE80211_RADIOTAP_TX_FLAGS));
211 * cb_hdr->rate = 5;//txrate->bitrate / 5;
212 * cb_hdr->tx_flags = 0x0004;
214 * skb2->dev = wilc_wfi_mon;
215 * skb_set_mac_header(skb2, 0);
216 * skb2->ip_summed = CHECKSUM_UNNECESSARY;
217 * skb2->pkt_type = PACKET_OTHERHOST;
218 * skb2->protocol = htons(ETH_P_802_2);
219 * memset(skb2->cb, 0, sizeof(skb2->cb));
224 /* incase of fully hosting mode, the freeing will be done in response to the cfg packet */
225 #ifndef WILC_FULLY_HOSTING_AP
226 kfree(pv_data
->buff
);
231 static int mon_mgmt_tx(struct net_device
*dev
, const u8
*buf
, size_t len
)
233 struct tx_complete_mon_data
*mgmt_tx
= NULL
;
236 PRINT_D(HOSTAPD_DBG
, "ERROR: dev == NULL\n");
240 netif_stop_queue(dev
);
241 mgmt_tx
= kmalloc(sizeof(struct tx_complete_mon_data
), GFP_ATOMIC
);
242 if (mgmt_tx
== NULL
) {
243 PRINT_ER("Failed to allocate memory for mgmt_tx structure\n");
247 #ifdef WILC_FULLY_HOSTING_AP
248 /* add space for the pointer to tx_complete_mon_data */
249 len
+= sizeof(struct tx_complete_mon_data
*);
252 mgmt_tx
->buff
= kmalloc(len
, GFP_ATOMIC
);
253 if (mgmt_tx
->buff
== NULL
) {
254 PRINT_ER("Failed to allocate memory for mgmt_tx buff\n");
261 #ifndef WILC_FULLY_HOSTING_AP
262 memcpy(mgmt_tx
->buff
, buf
, len
);
264 memcpy(mgmt_tx
->buff
, buf
, len
- sizeof(struct tx_complete_mon_data
*));
265 memcpy((mgmt_tx
->buff
) + (len
- sizeof(struct tx_complete_mon_data
*)), &mgmt_tx
, sizeof(struct tx_complete_mon_data
*));
267 /* filter data frames to handle it's PS */
268 if (filter_monitor_data_frames((mgmt_tx
->buff
), len
) == true) {
272 #endif /* WILC_FULLY_HOSTING_AP */
274 g_linux_wlan
->oup
.wlan_add_mgmt_to_tx_que(mgmt_tx
, mgmt_tx
->buff
, mgmt_tx
->size
, mgmt_tx_complete
);
276 netif_wake_queue(dev
);
281 * @brief WILC_WFI_mon_xmit
284 * @return int : Return 0 on Success
289 static netdev_tx_t
WILC_WFI_mon_xmit(struct sk_buff
*skb
,
290 struct net_device
*dev
)
292 u32 rtap_len
, i
, ret
= 0;
293 struct WILC_WFI_mon_priv
*mon_priv
;
295 struct sk_buff
*skb2
;
296 struct wilc_wfi_radiotap_cb_hdr
*cb_hdr
;
299 if (wilc_wfi_mon
== NULL
)
302 /* if(skb->data[3] == 0x10 || skb->data[3] == 0xb0) */
304 mon_priv
= netdev_priv(wilc_wfi_mon
);
306 if (mon_priv
== NULL
) {
307 PRINT_ER("Monitor interface private structure is NULL\n");
312 rtap_len
= ieee80211_get_radiotap_len(skb
->data
);
313 if (skb
->len
< rtap_len
) {
314 PRINT_ER("Error in radiotap header\n");
317 /* skip the radiotap header */
318 PRINT_INFO(HOSTAPD_DBG
, "Radiotap len: %d\n", rtap_len
);
321 for (i
= 0; i
< rtap_len
; i
++)
322 PRINT_INFO(HOSTAPD_DBG
, "Radiotap_hdr[%d] %02x\n", i
, skb
->data
[i
]);
324 /* Skip the ratio tap header */
325 skb_pull(skb
, rtap_len
);
327 if (skb
->data
[0] == 0xc0)
328 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]);
330 if (skb
->data
[0] == 0xc0 && (!(memcmp(broadcast
, &skb
->data
[4], 6)))) {
331 skb2
= dev_alloc_skb(skb
->len
+ sizeof(struct wilc_wfi_radiotap_cb_hdr
));
333 memcpy(skb_put(skb2
, skb
->len
), skb
->data
, skb
->len
);
335 cb_hdr
= (struct wilc_wfi_radiotap_cb_hdr
*) skb_push(skb2
, sizeof(*cb_hdr
));
336 memset(cb_hdr
, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr
));
338 cb_hdr
->hdr
.it_version
= 0; /* PKTHDR_RADIOTAP_VERSION; */
340 cb_hdr
->hdr
.it_len
= cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr
));
342 cb_hdr
->hdr
.it_present
= cpu_to_le32(
343 (1 << IEEE80211_RADIOTAP_RATE
) |
344 (1 << IEEE80211_RADIOTAP_TX_FLAGS
));
346 cb_hdr
->rate
= 5; /* txrate->bitrate / 5; */
347 cb_hdr
->tx_flags
= 0x0004;
349 skb2
->dev
= wilc_wfi_mon
;
350 skb_set_mac_header(skb2
, 0);
351 skb2
->ip_summed
= CHECKSUM_UNNECESSARY
;
352 skb2
->pkt_type
= PACKET_OTHERHOST
;
353 skb2
->protocol
= htons(ETH_P_802_2
);
354 memset(skb2
->cb
, 0, sizeof(skb2
->cb
));
360 skb
->dev
= mon_priv
->real_ndev
;
362 PRINT_INFO(HOSTAPD_DBG
, "Skipping the radiotap header\n");
366 /* actual deliver of data is device-specific, and not shown here */
367 PRINT_INFO(HOSTAPD_DBG
, "SKB netdevice name = %s\n", skb
->dev
->name
);
368 PRINT_INFO(HOSTAPD_DBG
, "MONITOR real dev name = %s\n", mon_priv
->real_ndev
->name
);
371 /* Identify if Ethernet or MAC header (data or mgmt) */
372 memcpy(srcAdd
, &skb
->data
[10], 6);
373 memcpy(bssid
, &skb
->data
[16], 6);
374 /* if source address and bssid fields are equal>>Mac header */
375 /*send it to mgmt frames handler */
376 if (!(memcmp(srcAdd
, bssid
, 6))) {
377 mon_mgmt_tx(mon_priv
->real_ndev
, skb
->data
, skb
->len
);
380 ret
= mac_xmit(skb
, mon_priv
->real_ndev
);
383 /* return NETDEV_TX_OK; */
387 static const struct net_device_ops wilc_wfi_netdev_ops
= {
388 .ndo_start_xmit
= WILC_WFI_mon_xmit
,
392 #ifdef WILC_FULLY_HOSTING_AP
394 * @brief WILC_mgm_HOSTAPD_ACK
395 * @details report the status of transmitted mgmt frames to HOSTAPD
396 * @param[in] priv : pointer to tx_complete_mon_data struct
397 * bStatus : status of transmission
398 * @author Abd Al-Rahman Diab
402 void WILC_mgm_HOSTAPD_ACK(void *priv
, bool bStatus
)
405 struct wilc_wfi_radiotap_cb_hdr
*cb_hdr
;
407 struct tx_complete_mon_data
*pv_data
= (struct tx_complete_mon_data
*)priv
;
408 u8
*buf
= pv_data
->buff
;
410 /* len of the original frame without the added pointer at the tail */
411 u16 u16len
= (pv_data
->size
) - sizeof(struct tx_complete_mon_data
*);
415 * if(INFO || buf[0] == 0x10 || buf[0] == 0xb0)
416 * PRINT_D(HOSTAPD_DBG,"Packet sent successfully - Size = %d - Address = %p.\n",u16len,pv_data->buff);
418 * PRINT_D(HOSTAPD_DBG,"Couldn't send packet - Size = %d - Address = %p.\n",u16len,pv_data->buff);
422 /* (skb->data[9] == 0x00 || skb->data[9] == 0xb0 || skb->data[9] == 0x40 || skb->data[9] == 0xd0 ) */
424 skb
= dev_alloc_skb(u16len
+ sizeof(struct wilc_wfi_radiotap_cb_hdr
));
426 memcpy(skb_put(skb
, u16len
), pv_data
->buff
, u16len
);
428 cb_hdr
= (struct wilc_wfi_radiotap_cb_hdr
*) skb_push(skb
, sizeof(*cb_hdr
));
429 memset(cb_hdr
, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr
));
431 cb_hdr
->hdr
.it_version
= 0; /* PKTHDR_RADIOTAP_VERSION; */
433 cb_hdr
->hdr
.it_len
= cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr
));
435 cb_hdr
->hdr
.it_present
= cpu_to_le32(
436 (1 << IEEE80211_RADIOTAP_RATE
) |
437 (1 << IEEE80211_RADIOTAP_TX_FLAGS
));
439 cb_hdr
->rate
= 5; /* txrate->bitrate / 5; */
444 cb_hdr
->tx_flags
= IEEE80211_RADIOTAP_F_TX_RTS
;
446 cb_hdr
->tx_flags
= IEEE80211_RADIOTAP_F_TX_FAIL
;
449 skb
->dev
= wilc_wfi_mon
;
450 skb_set_mac_header(skb
, 0);
451 skb
->ip_summed
= CHECKSUM_UNNECESSARY
;
452 skb
->pkt_type
= PACKET_OTHERHOST
;
453 skb
->protocol
= htons(ETH_P_802_2
);
454 memset(skb
->cb
, 0, sizeof(skb
->cb
));
459 /* incase of fully hosting mode, the freeing will be done in response to the cfg packet */
460 kfree(pv_data
->buff
);
465 #endif /* WILC_FULLY_HOSTING_AP */
468 * @brief WILC_WFI_mon_setup
471 * @return int : Return 0 on Success
476 static void WILC_WFI_mon_setup(struct net_device
*dev
)
479 dev
->netdev_ops
= &wilc_wfi_netdev_ops
;
480 /* dev->destructor = free_netdev; */
481 PRINT_INFO(CORECONFIG_DBG
, "In Ethernet setup function\n");
483 dev
->tx_queue_len
= 0;
484 dev
->type
= ARPHRD_IEEE80211_RADIOTAP
;
485 eth_zero_addr(dev
->dev_addr
);
490 unsigned char mac_add
[] = {0x00, 0x50, 0xc2, 0x5e, 0x10, 0x8f};
491 /* priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); */
492 /* mac_add = (u8*)WILC_MALLOC(ETH_ALEN); */
493 /* status = host_int_get_MacAddress(priv->hWILCWFIDrv,mac_add); */
494 /* mac_add[ETH_ALEN-1]+=1; */
495 memcpy(dev
->dev_addr
, mac_add
, ETH_ALEN
);
498 dev
->dev_addr
[0] = 0x12;
504 * @brief WILC_WFI_init_mon_interface
507 * @return int : Return 0 on Success
512 struct net_device
*WILC_WFI_init_mon_interface(const char *name
, struct net_device
*real_dev
)
516 u32 ret
= WILC_SUCCESS
;
517 struct WILC_WFI_mon_priv
*priv
;
519 /*If monitor interface is already initialized, return it*/
524 wilc_wfi_mon
= alloc_etherdev(sizeof(struct WILC_WFI_mon_priv
));
526 PRINT_ER("failed to allocate memory\n");
531 wilc_wfi_mon
->type
= ARPHRD_IEEE80211_RADIOTAP
;
532 strncpy(wilc_wfi_mon
->name
, name
, IFNAMSIZ
);
533 wilc_wfi_mon
->name
[IFNAMSIZ
- 1] = 0;
534 wilc_wfi_mon
->netdev_ops
= &wilc_wfi_netdev_ops
;
536 ret
= register_netdevice(wilc_wfi_mon
);
538 PRINT_ER(" register_netdevice failed (%d)\n", ret
);
541 priv
= netdev_priv(wilc_wfi_mon
);
543 PRINT_ER("private structure is NULL\n");
547 priv
->real_ndev
= real_dev
;
553 * @brief WILC_WFI_deinit_mon_interface
556 * @return int : Return 0 on Success
561 int WILC_WFI_deinit_mon_interface()
563 bool rollback_lock
= false;
565 if (wilc_wfi_mon
!= NULL
) {
566 PRINT_D(HOSTAPD_DBG
, "In Deinit monitor interface\n");
567 PRINT_D(HOSTAPD_DBG
, "RTNL is being locked\n");
568 if (rtnl_is_locked()) {
570 rollback_lock
= true;
572 PRINT_D(HOSTAPD_DBG
, "Unregister netdev\n");
573 unregister_netdev(wilc_wfi_mon
);
574 /* free_netdev(wilc_wfi_mon); */
578 rollback_lock
= false;
585 #endif /* WILC_AP_EXTERNAL_MLME */