1
2
3
4
5
6
7
8
9
10#include "wilc_wfi_cfgoperations.h"
11#include "wilc_wlan_if.h"
12#include "wilc_wlan.h"
13
14struct wilc_wfi_radiotap_hdr {
15 struct ieee80211_radiotap_header hdr;
16 u8 rate;
17} __packed;
18
19struct wilc_wfi_radiotap_cb_hdr {
20 struct ieee80211_radiotap_header hdr;
21 u8 rate;
22 u8 dump;
23 u16 tx_flags;
24} __packed;
25
26static struct net_device *wilc_wfi_mon;
27
28static u8 srcadd[6];
29static u8 bssid[6];
30static u8 broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
31
32
33
34
35
36
37
38
39
40
41#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004
42#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001
43#define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff)
44
45void WILC_WFI_monitor_rx(u8 *buff, u32 size)
46{
47 u32 header, pkt_offset;
48 struct sk_buff *skb = NULL;
49 struct wilc_wfi_radiotap_hdr *hdr;
50 struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
51
52 if (!wilc_wfi_mon)
53 return;
54
55 if (!netif_running(wilc_wfi_mon))
56 return;
57
58
59 memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET);
60
61
62
63
64 pkt_offset = GET_PKT_OFFSET(header);
65
66 if (pkt_offset & IS_MANAGMEMENT_CALLBACK) {
67
68
69 skb = dev_alloc_skb(size + sizeof(struct wilc_wfi_radiotap_cb_hdr));
70 if (!skb)
71 return;
72
73 skb_put_data(skb, buff, size);
74
75 cb_hdr = skb_push(skb, sizeof(*cb_hdr));
76 memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr));
77
78 cb_hdr->hdr.it_version = 0;
79
80 cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr));
81
82 cb_hdr->hdr.it_present = cpu_to_le32(
83 (1 << IEEE80211_RADIOTAP_RATE) |
84 (1 << IEEE80211_RADIOTAP_TX_FLAGS));
85
86 cb_hdr->rate = 5;
87
88 if (pkt_offset & IS_MGMT_STATUS_SUCCES) {
89
90 cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_RTS;
91 } else {
92 cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_FAIL;
93 }
94
95 } else {
96 skb = dev_alloc_skb(size + sizeof(struct wilc_wfi_radiotap_hdr));
97
98 if (!skb)
99 return;
100
101 skb_put_data(skb, buff, size);
102 hdr = skb_push(skb, sizeof(*hdr));
103 memset(hdr, 0, sizeof(struct wilc_wfi_radiotap_hdr));
104 hdr->hdr.it_version = 0;
105 hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_hdr));
106 hdr->hdr.it_present = cpu_to_le32
107 (1 << IEEE80211_RADIOTAP_RATE);
108 hdr->rate = 5;
109 }
110
111 skb->dev = wilc_wfi_mon;
112 skb_reset_mac_header(skb);
113 skb->ip_summed = CHECKSUM_UNNECESSARY;
114 skb->pkt_type = PACKET_OTHERHOST;
115 skb->protocol = htons(ETH_P_802_2);
116 memset(skb->cb, 0, sizeof(skb->cb));
117
118 netif_rx(skb);
119}
120
121struct tx_complete_mon_data {
122 int size;
123 void *buff;
124};
125
126static void mgmt_tx_complete(void *priv, int status)
127{
128 struct tx_complete_mon_data *pv_data = priv;
129
130
131
132
133 kfree(pv_data->buff);
134
135 kfree(pv_data);
136}
137
138static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len)
139{
140 struct tx_complete_mon_data *mgmt_tx = NULL;
141
142 if (!dev)
143 return -EFAULT;
144
145 netif_stop_queue(dev);
146 mgmt_tx = kmalloc(sizeof(*mgmt_tx), GFP_ATOMIC);
147 if (!mgmt_tx)
148 return -ENOMEM;
149
150 mgmt_tx->buff = kmemdup(buf, len, GFP_ATOMIC);
151 if (!mgmt_tx->buff) {
152 kfree(mgmt_tx);
153 return -ENOMEM;
154 }
155
156 mgmt_tx->size = len;
157
158 wilc_wlan_txq_add_mgmt_pkt(dev, mgmt_tx, mgmt_tx->buff, mgmt_tx->size,
159 mgmt_tx_complete);
160
161 netif_wake_queue(dev);
162 return 0;
163}
164
165
166
167
168
169
170
171
172
173
174static netdev_tx_t WILC_WFI_mon_xmit(struct sk_buff *skb,
175 struct net_device *dev)
176{
177 u32 rtap_len, ret = 0;
178 struct WILC_WFI_mon_priv *mon_priv;
179
180 struct sk_buff *skb2;
181 struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
182
183 if (!wilc_wfi_mon)
184 return -EFAULT;
185
186 mon_priv = netdev_priv(wilc_wfi_mon);
187 if (!mon_priv)
188 return -EFAULT;
189 rtap_len = ieee80211_get_radiotap_len(skb->data);
190 if (skb->len < rtap_len)
191 return -1;
192
193 skb_pull(skb, rtap_len);
194
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));
197 if (!skb2)
198 return -ENOMEM;
199
200 skb_put_data(skb2, skb->data, skb->len);
201
202 cb_hdr = skb_push(skb2, sizeof(*cb_hdr));
203 memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr));
204
205 cb_hdr->hdr.it_version = 0;
206
207 cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr));
208
209 cb_hdr->hdr.it_present = cpu_to_le32(
210 (1 << IEEE80211_RADIOTAP_RATE) |
211 (1 << IEEE80211_RADIOTAP_TX_FLAGS));
212
213 cb_hdr->rate = 5;
214 cb_hdr->tx_flags = 0x0004;
215
216 skb2->dev = wilc_wfi_mon;
217 skb_reset_mac_header(skb2);
218 skb2->ip_summed = CHECKSUM_UNNECESSARY;
219 skb2->pkt_type = PACKET_OTHERHOST;
220 skb2->protocol = htons(ETH_P_802_2);
221 memset(skb2->cb, 0, sizeof(skb2->cb));
222
223 netif_rx(skb2);
224
225 return 0;
226 }
227 skb->dev = mon_priv->real_ndev;
228
229
230 memcpy(srcadd, &skb->data[10], 6);
231 memcpy(bssid, &skb->data[16], 6);
232
233
234 if (!(memcmp(srcadd, bssid, 6))) {
235 ret = mon_mgmt_tx(mon_priv->real_ndev, skb->data, skb->len);
236 if (ret)
237 netdev_err(dev, "fail to mgmt tx\n");
238 dev_kfree_skb(skb);
239 } else {
240 ret = wilc_mac_xmit(skb, mon_priv->real_ndev);
241 }
242
243 return ret;
244}
245
246static const struct net_device_ops wilc_wfi_netdev_ops = {
247 .ndo_start_xmit = WILC_WFI_mon_xmit,
248
249};
250
251
252
253
254
255
256
257
258
259
260struct net_device *WILC_WFI_init_mon_interface(const char *name,
261 struct net_device *real_dev)
262{
263 struct WILC_WFI_mon_priv *priv;
264
265
266 if (wilc_wfi_mon)
267 return wilc_wfi_mon;
268
269 wilc_wfi_mon = alloc_etherdev(sizeof(struct WILC_WFI_mon_priv));
270 if (!wilc_wfi_mon)
271 return NULL;
272 wilc_wfi_mon->type = ARPHRD_IEEE80211_RADIOTAP;
273 strncpy(wilc_wfi_mon->name, name, IFNAMSIZ);
274 wilc_wfi_mon->name[IFNAMSIZ - 1] = 0;
275 wilc_wfi_mon->netdev_ops = &wilc_wfi_netdev_ops;
276
277 if (register_netdevice(wilc_wfi_mon)) {
278 netdev_err(real_dev, "register_netdevice failed\n");
279 return NULL;
280 }
281 priv = netdev_priv(wilc_wfi_mon);
282 if (!priv)
283 return NULL;
284
285 priv->real_ndev = real_dev;
286
287 return wilc_wfi_mon;
288}
289
290
291
292
293
294
295
296
297
298
299int WILC_WFI_deinit_mon_interface(void)
300{
301 bool rollback_lock = false;
302
303 if (wilc_wfi_mon) {
304 if (rtnl_is_locked()) {
305 rtnl_unlock();
306 rollback_lock = true;
307 }
308 unregister_netdev(wilc_wfi_mon);
309
310 if (rollback_lock) {
311 rtnl_lock();
312 rollback_lock = false;
313 }
314 wilc_wfi_mon = NULL;
315 }
316 return 0;
317}
318