3 * @brief File Operations OS wrapper functionality
5 * @sa wilc_wfi_netdevice.h
11 #include "wilc_wfi_cfgoperations.h"
12 #include "linux_wlan_common.h"
13 #include "wilc_wlan_if.h"
14 #include "wilc_wlan.h"
16 #ifdef WILC_FULLY_HOSTING_AP
17 #include "wilc_host_ap.h"
19 #ifdef WILC_AP_EXTERNAL_MLME
21 #include "wilc_wfi_cfgoperations.h"
24 struct wilc_wfi_radiotap_hdr {
25 struct ieee80211_radiotap_header hdr;
28 } __attribute__((packed));
30 struct wilc_wfi_radiotap_cb_hdr {
31 struct ieee80211_radiotap_header hdr;
36 } __attribute__((packed));
38 extern linux_wlan_t *g_linux_wlan;
40 static struct net_device *wilc_wfi_mon; /* global monitor netdev */
43 extern int WILC_WFI_Tx(struct sk_buff *skb, struct net_device *dev);
45 extern int mac_xmit(struct sk_buff *skb, struct net_device *dev);
51 u8 broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
53 * @brief WILC_WFI_monitor_rx
56 * @return int : Return 0 on Success
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)
69 void WILC_WFI_monitor_rx(uint8_t *buff, uint32_t size)
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;
76 PRINT_INFO(HOSTAPD_DBG, "In monitor interface receive function\n");
78 /* struct WILC_WFI_priv *priv = netdev_priv(dev); */
80 /* priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); */
83 if (wilc_wfi_mon == NULL)
86 if (!netif_running(wilc_wfi_mon)) {
87 PRINT_INFO(HOSTAPD_DBG, "Monitor interface already RUNNING\n");
92 memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET);
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);
98 if (pkt_offset & IS_MANAGMEMENT_CALLBACK) {
100 /* hostapd callback mgmt frame */
102 skb = dev_alloc_skb(size + sizeof(struct wilc_wfi_radiotap_cb_hdr));
104 PRINT_INFO(HOSTAPD_DBG, "Monitor if : No memory to allocate skb");
108 memcpy(skb_put(skb, size), buff, size);
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));
113 cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
115 cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr));
117 cb_hdr->hdr.it_present = cpu_to_le32(
118 (1 << IEEE80211_RADIOTAP_RATE) |
119 (1 << IEEE80211_RADIOTAP_TX_FLAGS));
121 cb_hdr->rate = 5; /* txrate->bitrate / 5; */
123 if (pkt_offset & IS_MGMT_STATUS_SUCCES) {
125 cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_RTS;
127 cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_FAIL;
132 skb = dev_alloc_skb(size + sizeof(struct wilc_wfi_radiotap_hdr));
135 PRINT_INFO(HOSTAPD_DBG, "Monitor if : No memory to allocate skb");
139 /* skb = skb_copy_expand(tx_skb, sizeof(*hdr), 0, GFP_ATOMIC); */
140 /* if (skb == NULL) */
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; */
158 /* if(INFO || if(skb->data[9] == 0x00 || skb->data[9] == 0xb0))
160 * for(i=0;i<skb->len;i++)
161 * PRINT_INFO(HOSTAPD_DBG,"Mon RxData[%d] = %02x\n",i,skb->data[i]);
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));
177 struct tx_complete_mon_data {
182 static void mgmt_tx_complete(void *priv, int status)
185 /* struct sk_buff *skb2; */
186 /* struct wilc_wfi_radiotap_cb_hdr *cb_hdr; */
188 struct tx_complete_mon_data *pv_data = (struct tx_complete_mon_data *)priv;
189 u8 *buf = pv_data->buff;
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);
197 PRINT_INFO(HOSTAPD_DBG, "Couldn't send packet - Size = %d - Address = %p.\n", pv_data->size, pv_data->buff);
201 /* //(skb->data[9] == 0x00 || skb->data[9] == 0xb0 || skb->data[9] == 0x40 || skb->data[9] == 0xd0 )
203 * skb2 = dev_alloc_skb(pv_data->size+sizeof(struct wilc_wfi_radiotap_cb_hdr));
205 * memcpy(skb_put(skb2,pv_data->size),pv_data->buff, pv_data->size);
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));
210 * cb_hdr->hdr.it_version = 0;//PKTHDR_RADIOTAP_VERSION;
212 * cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr));
214 * cb_hdr->hdr.it_present = cpu_to_le32(
215 * (1 << IEEE80211_RADIOTAP_RATE) |
216 * (1 << IEEE80211_RADIOTAP_TX_FLAGS));
218 * cb_hdr->rate = 5;//txrate->bitrate / 5;
219 * cb_hdr->tx_flags = 0x0004;
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));
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);
238 static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len)
241 struct tx_complete_mon_data *mgmt_tx = NULL;
244 PRINT_D(HOSTAPD_DBG, "ERROR: dev == NULL\n");
247 nic = netdev_priv(dev);
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");
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 *);
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");
270 #ifndef WILC_FULLY_HOSTING_AP
271 memcpy(mgmt_tx->buff, buf, len);
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 *));
276 /* filter data frames to handle it's PS */
277 if (filter_monitor_data_frames((mgmt_tx->buff), len) == true) {
281 #endif /* WILC_FULLY_HOSTING_AP */
283 g_linux_wlan->oup.wlan_add_mgmt_to_tx_que(mgmt_tx, mgmt_tx->buff, mgmt_tx->size, mgmt_tx_complete);
285 netif_wake_queue(dev);
290 * @brief WILC_WFI_mon_xmit
293 * @return int : Return 0 on Success
298 static netdev_tx_t WILC_WFI_mon_xmit(struct sk_buff *skb,
299 struct net_device *dev)
301 struct ieee80211_radiotap_header *rtap_hdr;
302 u32 rtap_len, i, ret = 0;
303 struct WILC_WFI_mon_priv *mon_priv;
305 struct sk_buff *skb2;
306 struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
309 if (wilc_wfi_mon == NULL)
312 /* if(skb->data[3] == 0x10 || skb->data[3] == 0xb0) */
314 mon_priv = netdev_priv(wilc_wfi_mon);
316 if (mon_priv == NULL) {
317 PRINT_ER("Monitor interface private structure is NULL\n");
321 rtap_hdr = (struct ieee80211_radiotap_header *)skb->data;
323 rtap_len = ieee80211_get_radiotap_len(skb->data);
324 if (skb->len < rtap_len) {
325 PRINT_ER("Error in radiotap header\n");
328 /* skip the radiotap header */
329 PRINT_INFO(HOSTAPD_DBG, "Radiotap len: %d\n", rtap_len);
332 for (i = 0; i < rtap_len; i++)
333 PRINT_INFO(HOSTAPD_DBG, "Radiotap_hdr[%d] %02x\n", i, skb->data[i]);
335 /* Skip the ratio tap header */
336 skb_pull(skb, rtap_len);
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]);
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));
344 memcpy(skb_put(skb2, skb->len), skb->data, skb->len);
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));
349 cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
351 cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr));
353 cb_hdr->hdr.it_present = cpu_to_le32(
354 (1 << IEEE80211_RADIOTAP_RATE) |
355 (1 << IEEE80211_RADIOTAP_TX_FLAGS));
357 cb_hdr->rate = 5; /* txrate->bitrate / 5; */
358 cb_hdr->tx_flags = 0x0004;
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));
371 skb->dev = mon_priv->real_ndev;
373 PRINT_INFO(HOSTAPD_DBG, "Skipping the radiotap header\n");
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);
382 ret = WILC_WFI_Tx(skb, mon_priv->real_ndev);
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);
393 ret = mac_xmit(skb, mon_priv->real_ndev);
396 /* return NETDEV_TX_OK; */
400 static const struct net_device_ops wilc_wfi_netdev_ops = {
401 .ndo_start_xmit = WILC_WFI_mon_xmit,
405 #ifdef WILC_FULLY_HOSTING_AP
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
415 void WILC_mgm_HOSTAPD_ACK(void *priv, bool bStatus)
418 struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
420 struct tx_complete_mon_data *pv_data = (struct tx_complete_mon_data *)priv;
421 u8 *buf = pv_data->buff;
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 *);
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);
431 * PRINT_D(HOSTAPD_DBG,"Couldn't send packet - Size = %d - Address = %p.\n",u16len,pv_data->buff);
435 /* (skb->data[9] == 0x00 || skb->data[9] == 0xb0 || skb->data[9] == 0x40 || skb->data[9] == 0xd0 ) */
437 skb = dev_alloc_skb(u16len + sizeof(struct wilc_wfi_radiotap_cb_hdr));
439 memcpy(skb_put(skb, u16len), pv_data->buff, u16len);
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));
444 cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
446 cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr));
448 cb_hdr->hdr.it_present = cpu_to_le32(
449 (1 << IEEE80211_RADIOTAP_RATE) |
450 (1 << IEEE80211_RADIOTAP_TX_FLAGS));
452 cb_hdr->rate = 5; /* txrate->bitrate / 5; */
457 cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_RTS;
459 cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_FAIL;
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));
472 /* incase of fully hosting mode, the freeing will be done in response to the cfg packet */
473 kfree(pv_data->buff);
478 #endif /* WILC_FULLY_HOSTING_AP */
481 * @brief WILC_WFI_mon_setup
484 * @return int : Return 0 on Success
489 static void WILC_WFI_mon_setup(struct net_device *dev)
492 dev->netdev_ops = &wilc_wfi_netdev_ops;
493 /* dev->destructor = free_netdev; */
494 PRINT_INFO(CORECONFIG_DBG, "In Ethernet setup function\n");
496 dev->priv_flags |= IFF_NO_QUEUE;
497 dev->type = ARPHRD_IEEE80211_RADIOTAP;
498 memset(dev->dev_addr, 0, ETH_ALEN);
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);
511 dev->dev_addr[0] = 0x12;
517 * @brief WILC_WFI_init_mon_interface
520 * @return int : Return 0 on Success
525 struct net_device *WILC_WFI_init_mon_interface(const char *name, struct net_device *real_dev)
529 u32 ret = WILC_SUCCESS;
530 struct WILC_WFI_mon_priv *priv;
532 /*If monitor interface is already initialized, return it*/
537 wilc_wfi_mon = alloc_etherdev(sizeof(struct WILC_WFI_mon_priv));
539 PRINT_ER("failed to allocate memory\n");
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;
549 ret = register_netdevice(wilc_wfi_mon);
551 PRINT_ER(" register_netdevice failed (%d)\n", ret);
554 priv = netdev_priv(wilc_wfi_mon);
556 PRINT_ER("private structure is NULL\n");
560 priv->real_ndev = real_dev;
566 * @brief WILC_WFI_deinit_mon_interface
569 * @return int : Return 0 on Success
574 int WILC_WFI_deinit_mon_interface()
576 bool rollback_lock = false;
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()) {
583 rollback_lock = true;
585 PRINT_D(HOSTAPD_DBG, "Unregister netdev\n");
586 unregister_netdev(wilc_wfi_mon);
587 /* free_netdev(wilc_wfi_mon); */
591 rollback_lock = false;
598 #endif /* WILC_AP_EXTERNAL_MLME */