blob: a943b2304da763ad88e3d9078fe62b51e80be292 [file] [log] [blame]
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001/*!
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 */
Johnny Kimc5c77ba2015-05-11 14:30:56 +09009#include "wilc_wfi_cfgoperations.h"
10#include "linux_wlan_common.h"
11#include "wilc_wlan_if.h"
12#include "wilc_wlan.h"
Tony Cho9690df32015-07-28 17:47:22 +090013
Johnny Kimc5c77ba2015-05-11 14:30:56 +090014
15struct wilc_wfi_radiotap_hdr {
16 struct ieee80211_radiotap_header hdr;
17 u8 rate;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090018} __attribute__((packed));
19
20struct wilc_wfi_radiotap_cb_hdr {
21 struct ieee80211_radiotap_header hdr;
22 u8 rate;
23 u8 dump;
24 u16 tx_flags;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090025} __attribute__((packed));
26
27extern linux_wlan_t *g_linux_wlan;
28
29static struct net_device *wilc_wfi_mon; /* global monitor netdev */
30
Johnny Kimc5c77ba2015-05-11 14:30:56 +090031extern int mac_xmit(struct sk_buff *skb, struct net_device *dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090032
33
Greg Kroah-Hartman63d03e42015-06-02 14:16:04 +090034u8 srcAdd[6];
35u8 bssid[6];
36u8 broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
Johnny Kimc5c77ba2015-05-11 14:30:56 +090037/**
38 * @brief WILC_WFI_monitor_rx
39 * @details
40 * @param[in]
41 * @return int : Return 0 on Success
42 * @author mdaftedar
43 * @date 12 JUL 2012
44 * @version 1.0
45 */
46
47#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
48#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive*/
49#define IS_MANAGMEMENT 0x100
50#define IS_MANAGMEMENT_CALLBACK 0x080
51#define IS_MGMT_STATUS_SUCCES 0x040
52#define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff)
53
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090054void WILC_WFI_monitor_rx(u8 *buff, u32 size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090055{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090056 u32 header, pkt_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090057 struct sk_buff *skb = NULL;
58 struct wilc_wfi_radiotap_hdr *hdr;
59 struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
60
61 PRINT_INFO(HOSTAPD_DBG, "In monitor interface receive function\n");
62
Johnny Kimc5c77ba2015-05-11 14:30:56 +090063 if (wilc_wfi_mon == NULL)
64 return;
65
66 if (!netif_running(wilc_wfi_mon)) {
67 PRINT_INFO(HOSTAPD_DBG, "Monitor interface already RUNNING\n");
68 return;
69 }
70
71 /* Get WILC header */
72 memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET);
73
74 /* The packet offset field conain info about what type of managment frame */
75 /* we are dealing with and ack status */
76 pkt_offset = GET_PKT_OFFSET(header);
77
78 if (pkt_offset & IS_MANAGMEMENT_CALLBACK) {
79
80 /* hostapd callback mgmt frame */
81
82 skb = dev_alloc_skb(size + sizeof(struct wilc_wfi_radiotap_cb_hdr));
83 if (skb == NULL) {
84 PRINT_INFO(HOSTAPD_DBG, "Monitor if : No memory to allocate skb");
85 return;
86 }
87
88 memcpy(skb_put(skb, size), buff, size);
89
90 cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *) skb_push(skb, sizeof(*cb_hdr));
91 memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr));
92
93 cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
94
95 cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr));
96
97 cb_hdr->hdr.it_present = cpu_to_le32(
98 (1 << IEEE80211_RADIOTAP_RATE) |
99 (1 << IEEE80211_RADIOTAP_TX_FLAGS));
100
101 cb_hdr->rate = 5; /* txrate->bitrate / 5; */
102
103 if (pkt_offset & IS_MGMT_STATUS_SUCCES) {
104 /* success */
105 cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_RTS;
106 } else {
107 cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_FAIL;
108 }
109
110 } else {
111
112 skb = dev_alloc_skb(size + sizeof(struct wilc_wfi_radiotap_hdr));
113
114 if (skb == NULL) {
115 PRINT_INFO(HOSTAPD_DBG, "Monitor if : No memory to allocate skb");
116 return;
117 }
118
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900119 memcpy(skb_put(skb, size), buff, size);
120 hdr = (struct wilc_wfi_radiotap_hdr *) skb_push(skb, sizeof(*hdr));
121 memset(hdr, 0, sizeof(struct wilc_wfi_radiotap_hdr));
122 hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900123 hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_hdr));
124 PRINT_INFO(HOSTAPD_DBG, "Radiotap len %d\n", hdr->hdr.it_len);
125 hdr->hdr.it_present = cpu_to_le32
126 (1 << IEEE80211_RADIOTAP_RATE); /* | */
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900127 PRINT_INFO(HOSTAPD_DBG, "Presentflags %d\n", hdr->hdr.it_present);
128 hdr->rate = 5; /* txrate->bitrate / 5; */
129
130 }
131
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900132
133
134 skb->dev = wilc_wfi_mon;
135 skb_set_mac_header(skb, 0);
136 skb->ip_summed = CHECKSUM_UNNECESSARY;
137 skb->pkt_type = PACKET_OTHERHOST;
138 skb->protocol = htons(ETH_P_802_2);
139 memset(skb->cb, 0, sizeof(skb->cb));
140
141 netif_rx(skb);
142
143
144}
145
146struct tx_complete_mon_data {
147 int size;
148 void *buff;
149};
150
151static void mgmt_tx_complete(void *priv, int status)
152{
153
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900154 struct tx_complete_mon_data *pv_data = (struct tx_complete_mon_data *)priv;
Greg Kroah-Hartman63d03e42015-06-02 14:16:04 +0900155 u8 *buf = pv_data->buff;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900156
157
158
159 if (status == 1) {
160 if (INFO || buf[0] == 0x10 || buf[0] == 0xb0)
161 PRINT_INFO(HOSTAPD_DBG, "Packet sent successfully - Size = %d - Address = %p.\n", pv_data->size, pv_data->buff);
162 } else {
163 PRINT_INFO(HOSTAPD_DBG, "Couldn't send packet - Size = %d - Address = %p.\n", pv_data->size, pv_data->buff);
164 }
165
166
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900167
168 /* incase of fully hosting mode, the freeing will be done in response to the cfg packet */
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900169 kfree(pv_data->buff);
170
171 kfree(pv_data);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900172}
173static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len)
174{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900175 struct tx_complete_mon_data *mgmt_tx = NULL;
176
177 if (dev == NULL) {
178 PRINT_D(HOSTAPD_DBG, "ERROR: dev == NULL\n");
Leo Kime6e12662015-09-16 18:36:03 +0900179 return -EFAULT;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900180 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900181
182 netif_stop_queue(dev);
Abdul Hussain25fe2272015-06-17 04:48:23 +0000183 mgmt_tx = kmalloc(sizeof(struct tx_complete_mon_data), GFP_ATOMIC);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900184 if (mgmt_tx == NULL) {
185 PRINT_ER("Failed to allocate memory for mgmt_tx structure\n");
Leo Kime6e12662015-09-16 18:36:03 +0900186 return -EFAULT;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900187 }
188
ChengYi He30ef5c82015-06-16 03:04:59 +0800189 mgmt_tx->buff = kmalloc(len, GFP_ATOMIC);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900190 if (mgmt_tx->buff == NULL) {
191 PRINT_ER("Failed to allocate memory for mgmt_tx buff\n");
Tony Chof638dd32015-09-07 19:09:31 +0900192 kfree(mgmt_tx);
Leo Kime6e12662015-09-16 18:36:03 +0900193 return -EFAULT;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900194
195 }
196
197 mgmt_tx->size = len;
198
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900199 memcpy(mgmt_tx->buff, buf, len);
Glen Leec9d48342015-10-01 16:03:43 +0900200 wilc_wlan_txq_add_mgmt_pkt(mgmt_tx, mgmt_tx->buff, mgmt_tx->size,
201 mgmt_tx_complete);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900202
203 netif_wake_queue(dev);
204 return 0;
205}
206
207/**
208 * @brief WILC_WFI_mon_xmit
209 * @details
210 * @param[in]
211 * @return int : Return 0 on Success
212 * @author mdaftedar
213 * @date 12 JUL 2012
214 * @version 1.0
215 */
216static netdev_tx_t WILC_WFI_mon_xmit(struct sk_buff *skb,
217 struct net_device *dev)
218{
Chaehyun Lim4e4467f2015-06-11 14:35:55 +0900219 u32 rtap_len, i, ret = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900220 struct WILC_WFI_mon_priv *mon_priv;
221
222 struct sk_buff *skb2;
223 struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
224
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900225 if (wilc_wfi_mon == NULL)
Leo Kime6e12662015-09-16 18:36:03 +0900226 return -EFAULT;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900227
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900228 mon_priv = netdev_priv(wilc_wfi_mon);
229
230 if (mon_priv == NULL) {
231 PRINT_ER("Monitor interface private structure is NULL\n");
Leo Kime6e12662015-09-16 18:36:03 +0900232 return -EFAULT;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900233 }
234
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900235
236 rtap_len = ieee80211_get_radiotap_len(skb->data);
237 if (skb->len < rtap_len) {
238 PRINT_ER("Error in radiotap header\n");
239 return -1;
240 }
241 /* skip the radiotap header */
242 PRINT_INFO(HOSTAPD_DBG, "Radiotap len: %d\n", rtap_len);
243
244 if (INFO) {
245 for (i = 0; i < rtap_len; i++)
246 PRINT_INFO(HOSTAPD_DBG, "Radiotap_hdr[%d] %02x\n", i, skb->data[i]);
247 }
248 /* Skip the ratio tap header */
249 skb_pull(skb, rtap_len);
250
251 if (skb->data[0] == 0xc0)
252 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]);
253
254 if (skb->data[0] == 0xc0 && (!(memcmp(broadcast, &skb->data[4], 6)))) {
255 skb2 = dev_alloc_skb(skb->len + sizeof(struct wilc_wfi_radiotap_cb_hdr));
256
257 memcpy(skb_put(skb2, skb->len), skb->data, skb->len);
258
259 cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *) skb_push(skb2, sizeof(*cb_hdr));
260 memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr));
261
262 cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
263
264 cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr));
265
266 cb_hdr->hdr.it_present = cpu_to_le32(
267 (1 << IEEE80211_RADIOTAP_RATE) |
268 (1 << IEEE80211_RADIOTAP_TX_FLAGS));
269
270 cb_hdr->rate = 5; /* txrate->bitrate / 5; */
271 cb_hdr->tx_flags = 0x0004;
272
273 skb2->dev = wilc_wfi_mon;
274 skb_set_mac_header(skb2, 0);
275 skb2->ip_summed = CHECKSUM_UNNECESSARY;
276 skb2->pkt_type = PACKET_OTHERHOST;
277 skb2->protocol = htons(ETH_P_802_2);
278 memset(skb2->cb, 0, sizeof(skb2->cb));
279
280 netif_rx(skb2);
281
282 return 0;
283 }
284 skb->dev = mon_priv->real_ndev;
285
286 PRINT_INFO(HOSTAPD_DBG, "Skipping the radiotap header\n");
287
288
289
290 /* actual deliver of data is device-specific, and not shown here */
291 PRINT_INFO(HOSTAPD_DBG, "SKB netdevice name = %s\n", skb->dev->name);
292 PRINT_INFO(HOSTAPD_DBG, "MONITOR real dev name = %s\n", mon_priv->real_ndev->name);
293
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900294 /* Identify if Ethernet or MAC header (data or mgmt) */
295 memcpy(srcAdd, &skb->data[10], 6);
296 memcpy(bssid, &skb->data[16], 6);
297 /* if source address and bssid fields are equal>>Mac header */
298 /*send it to mgmt frames handler */
299 if (!(memcmp(srcAdd, bssid, 6))) {
300 mon_mgmt_tx(mon_priv->real_ndev, skb->data, skb->len);
301 dev_kfree_skb(skb);
302 } else
303 ret = mac_xmit(skb, mon_priv->real_ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900304
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900305 return ret;
306}
307
308static const struct net_device_ops wilc_wfi_netdev_ops = {
309 .ndo_start_xmit = WILC_WFI_mon_xmit,
310
311};
312
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900313/**
314 * @brief WILC_WFI_mon_setup
315 * @details
316 * @param[in]
317 * @return int : Return 0 on Success
318 * @author mdaftedar
319 * @date 12 JUL 2012
320 * @version 1.0
321 */
322static void WILC_WFI_mon_setup(struct net_device *dev)
323{
324
325 dev->netdev_ops = &wilc_wfi_netdev_ops;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900326 PRINT_INFO(CORECONFIG_DBG, "In Ethernet setup function\n");
327 ether_setup(dev);
Phil Sutter7d9e4372015-08-18 10:30:47 +0200328 dev->priv_flags |= IFF_NO_QUEUE;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900329 dev->type = ARPHRD_IEEE80211_RADIOTAP;
Vaishali Thakkar8ca1b552015-06-21 10:56:21 +0530330 eth_zero_addr(dev->dev_addr);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900331
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900332 {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900333 unsigned char mac_add[] = {0x00, 0x50, 0xc2, 0x5e, 0x10, 0x8f};
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900334 memcpy(dev->dev_addr, mac_add, ETH_ALEN);
335 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900336
337}
338
339/**
340 * @brief WILC_WFI_init_mon_interface
341 * @details
342 * @param[in]
343 * @return int : Return 0 on Success
344 * @author mdaftedar
345 * @date 12 JUL 2012
346 * @version 1.0
347 */
Arnd Bergmann057d1e92015-06-01 21:06:44 +0200348struct net_device *WILC_WFI_init_mon_interface(const char *name, struct net_device *real_dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900349{
350
351
Leo Kime6e12662015-09-16 18:36:03 +0900352 u32 ret = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900353 struct WILC_WFI_mon_priv *priv;
354
355 /*If monitor interface is already initialized, return it*/
356 if (wilc_wfi_mon) {
357 return wilc_wfi_mon;
358 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900359
360 wilc_wfi_mon = alloc_etherdev(sizeof(struct WILC_WFI_mon_priv));
361 if (!wilc_wfi_mon) {
362 PRINT_ER("failed to allocate memory\n");
363 return NULL;
364
365 }
366
367 wilc_wfi_mon->type = ARPHRD_IEEE80211_RADIOTAP;
368 strncpy(wilc_wfi_mon->name, name, IFNAMSIZ);
369 wilc_wfi_mon->name[IFNAMSIZ - 1] = 0;
370 wilc_wfi_mon->netdev_ops = &wilc_wfi_netdev_ops;
371
372 ret = register_netdevice(wilc_wfi_mon);
373 if (ret) {
374 PRINT_ER(" register_netdevice failed (%d)\n", ret);
375 return NULL;
376 }
377 priv = netdev_priv(wilc_wfi_mon);
378 if (priv == NULL) {
379 PRINT_ER("private structure is NULL\n");
380 return NULL;
381 }
382
383 priv->real_ndev = real_dev;
384
385 return wilc_wfi_mon;
386}
387
388/**
389 * @brief WILC_WFI_deinit_mon_interface
390 * @details
391 * @param[in]
392 * @return int : Return 0 on Success
393 * @author mdaftedar
394 * @date 12 JUL 2012
395 * @version 1.0
396 */
Chandra S Gorentlaa96c47e2015-08-05 22:11:55 +0530397int WILC_WFI_deinit_mon_interface(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900398{
399 bool rollback_lock = false;
400
401 if (wilc_wfi_mon != NULL) {
402 PRINT_D(HOSTAPD_DBG, "In Deinit monitor interface\n");
403 PRINT_D(HOSTAPD_DBG, "RTNL is being locked\n");
404 if (rtnl_is_locked()) {
405 rtnl_unlock();
406 rollback_lock = true;
407 }
408 PRINT_D(HOSTAPD_DBG, "Unregister netdev\n");
409 unregister_netdev(wilc_wfi_mon);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900410
411 if (rollback_lock) {
412 rtnl_lock();
413 rollback_lock = false;
414 }
415 wilc_wfi_mon = NULL;
416 }
Leo Kime6e12662015-09-16 18:36:03 +0900417 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900418
419}