3 * @brief File Operations OS wrapper functionality
5 * @sa wilc_wfi_netdevice.h
9 #include "wilc_wfi_cfgoperations.h"
10 #include "wilc_wlan_if.h"
11 #include "wilc_wlan.h"
13 struct wilc_wfi_radiotap_hdr {
14 struct ieee80211_radiotap_header hdr;
18 struct wilc_wfi_radiotap_cb_hdr {
19 struct ieee80211_radiotap_header hdr;
25 static struct net_device *wilc_wfi_mon; /* global monitor netdev */
29 static u8 broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
31 * @brief WILC_WFI_monitor_rx
34 * @return int : Return 0 on Success
40 #define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
41 #define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive*/
42 #define IS_MANAGMEMENT 0x100
43 #define IS_MANAGMEMENT_CALLBACK 0x080
44 #define IS_MGMT_STATUS_SUCCES 0x040
45 #define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff)
47 void WILC_WFI_monitor_rx(u8 *buff, u32 size)
49 u32 header, pkt_offset;
50 struct sk_buff *skb = NULL;
51 struct wilc_wfi_radiotap_hdr *hdr;
52 struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
57 if (!netif_running(wilc_wfi_mon))
61 memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET);
63 /* The packet offset field conain info about what type of managment frame */
64 /* we are dealing with and ack status */
65 pkt_offset = GET_PKT_OFFSET(header);
67 if (pkt_offset & IS_MANAGMEMENT_CALLBACK) {
68 /* hostapd callback mgmt frame */
70 skb = dev_alloc_skb(size + sizeof(struct wilc_wfi_radiotap_cb_hdr));
74 memcpy(skb_put(skb, size), buff, size);
76 cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *)skb_push(skb, sizeof(*cb_hdr));
77 memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr));
79 cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
81 cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr));
83 cb_hdr->hdr.it_present = cpu_to_le32(
84 (1 << IEEE80211_RADIOTAP_RATE) |
85 (1 << IEEE80211_RADIOTAP_TX_FLAGS));
87 cb_hdr->rate = 5; /* txrate->bitrate / 5; */
89 if (pkt_offset & IS_MGMT_STATUS_SUCCES) {
91 cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_RTS;
93 cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_FAIL;
97 skb = dev_alloc_skb(size + sizeof(struct wilc_wfi_radiotap_hdr));
102 memcpy(skb_put(skb, size), buff, size);
103 hdr = (struct wilc_wfi_radiotap_hdr *)skb_push(skb, sizeof(*hdr));
104 memset(hdr, 0, sizeof(struct wilc_wfi_radiotap_hdr));
105 hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
106 hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_hdr));
107 hdr->hdr.it_present = cpu_to_le32
108 (1 << IEEE80211_RADIOTAP_RATE); /* | */
109 hdr->rate = 5; /* txrate->bitrate / 5; */
112 skb->dev = wilc_wfi_mon;
113 skb_set_mac_header(skb, 0);
114 skb->ip_summed = CHECKSUM_UNNECESSARY;
115 skb->pkt_type = PACKET_OTHERHOST;
116 skb->protocol = htons(ETH_P_802_2);
117 memset(skb->cb, 0, sizeof(skb->cb));
122 struct tx_complete_mon_data {
127 static void mgmt_tx_complete(void *priv, int status)
129 struct tx_complete_mon_data *pv_data = priv;
131 /* incase of fully hosting mode, the freeing will be done in response to the cfg packet */
132 kfree(pv_data->buff);
137 static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len)
139 struct tx_complete_mon_data *mgmt_tx = NULL;
144 netif_stop_queue(dev);
145 mgmt_tx = kmalloc(sizeof(*mgmt_tx), GFP_ATOMIC);
149 mgmt_tx->buff = kmalloc(len, GFP_ATOMIC);
150 if (!mgmt_tx->buff) {
157 memcpy(mgmt_tx->buff, buf, len);
158 wilc_wlan_txq_add_mgmt_pkt(dev, mgmt_tx, mgmt_tx->buff, mgmt_tx->size,
161 netif_wake_queue(dev);
166 * @brief WILC_WFI_mon_xmit
169 * @return int : Return 0 on Success
174 static netdev_tx_t WILC_WFI_mon_xmit(struct sk_buff *skb,
175 struct net_device *dev)
177 u32 rtap_len, ret = 0;
178 struct WILC_WFI_mon_priv *mon_priv;
180 struct sk_buff *skb2;
181 struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
186 mon_priv = netdev_priv(wilc_wfi_mon);
189 rtap_len = ieee80211_get_radiotap_len(skb->data);
190 if (skb->len < rtap_len)
193 skb_pull(skb, rtap_len);
195 if (skb->data[0] == 0xc0 && (!(memcmp(broadcast, &skb->data[4], 6)))) {
196 skb2 = dev_alloc_skb(skb->len + sizeof(struct wilc_wfi_radiotap_cb_hdr));
198 memcpy(skb_put(skb2, skb->len), skb->data, skb->len);
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));
225 skb->dev = mon_priv->real_ndev;
227 /* Identify if Ethernet or MAC header (data or mgmt) */
228 memcpy(srcAdd, &skb->data[10], 6);
229 memcpy(bssid, &skb->data[16], 6);
230 /* if source address and bssid fields are equal>>Mac header */
231 /*send it to mgmt frames handler */
232 if (!(memcmp(srcAdd, bssid, 6))) {
233 ret = mon_mgmt_tx(mon_priv->real_ndev, skb->data, skb->len);
235 netdev_err(dev, "fail to mgmt tx\n");
238 ret = wilc_mac_xmit(skb, mon_priv->real_ndev);
244 static const struct net_device_ops wilc_wfi_netdev_ops = {
245 .ndo_start_xmit = WILC_WFI_mon_xmit,
250 * @brief WILC_WFI_init_mon_interface
253 * @return int : Return 0 on Success
258 struct net_device *WILC_WFI_init_mon_interface(const char *name, struct net_device *real_dev)
261 struct WILC_WFI_mon_priv *priv;
263 /*If monitor interface is already initialized, return it*/
267 wilc_wfi_mon = alloc_etherdev(sizeof(struct WILC_WFI_mon_priv));
270 wilc_wfi_mon->type = ARPHRD_IEEE80211_RADIOTAP;
271 strncpy(wilc_wfi_mon->name, name, IFNAMSIZ);
272 wilc_wfi_mon->name[IFNAMSIZ - 1] = 0;
273 wilc_wfi_mon->netdev_ops = &wilc_wfi_netdev_ops;
275 ret = register_netdevice(wilc_wfi_mon);
277 netdev_err(real_dev, "register_netdevice failed\n");
280 priv = netdev_priv(wilc_wfi_mon);
284 priv->real_ndev = real_dev;
290 * @brief WILC_WFI_deinit_mon_interface
293 * @return int : Return 0 on Success
298 int WILC_WFI_deinit_mon_interface(void)
300 bool rollback_lock = false;
303 if (rtnl_is_locked()) {
305 rollback_lock = true;
307 unregister_netdev(wilc_wfi_mon);
311 rollback_lock = false;