1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
9 struct wilc_wfi_radiotap_hdr
{
10 struct ieee80211_radiotap_header_fixed hdr
;
14 struct wilc_wfi_radiotap_cb_hdr
{
15 struct ieee80211_radiotap_header_fixed hdr
;
21 #define TX_RADIOTAP_PRESENT ((1 << IEEE80211_RADIOTAP_RATE) | \
22 (1 << IEEE80211_RADIOTAP_TX_FLAGS))
24 void wilc_wfi_monitor_rx(struct net_device
*mon_dev
, u8
*buff
, u32 size
)
26 u32 header
, pkt_offset
;
27 struct sk_buff
*skb
= NULL
;
28 struct wilc_wfi_radiotap_hdr
*hdr
;
29 struct wilc_wfi_radiotap_cb_hdr
*cb_hdr
;
34 if (!netif_running(mon_dev
))
38 header
= get_unaligned_le32(buff
- HOST_HDR_OFFSET
);
40 * The packet offset field contain info about what type of management
41 * the frame we are dealing with and ack status
43 pkt_offset
= FIELD_GET(WILC_PKT_HDR_OFFSET_FIELD
, header
);
45 if (pkt_offset
& IS_MANAGMEMENT_CALLBACK
) {
46 /* hostapd callback mgmt frame */
48 skb
= dev_alloc_skb(size
+ sizeof(*cb_hdr
));
52 skb_put_data(skb
, buff
, size
);
54 cb_hdr
= skb_push(skb
, sizeof(*cb_hdr
));
55 memset(cb_hdr
, 0, sizeof(*cb_hdr
));
57 cb_hdr
->hdr
.it_version
= 0; /* PKTHDR_RADIOTAP_VERSION; */
59 cb_hdr
->hdr
.it_len
= cpu_to_le16(sizeof(*cb_hdr
));
61 cb_hdr
->hdr
.it_present
= cpu_to_le32(TX_RADIOTAP_PRESENT
);
65 if (pkt_offset
& IS_MGMT_STATUS_SUCCES
) {
67 cb_hdr
->tx_flags
= IEEE80211_RADIOTAP_F_TX_RTS
;
69 cb_hdr
->tx_flags
= IEEE80211_RADIOTAP_F_TX_FAIL
;
73 skb
= dev_alloc_skb(size
+ sizeof(*hdr
));
78 skb_put_data(skb
, buff
, size
);
79 hdr
= skb_push(skb
, sizeof(*hdr
));
80 memset(hdr
, 0, sizeof(struct wilc_wfi_radiotap_hdr
));
81 hdr
->hdr
.it_version
= 0; /* PKTHDR_RADIOTAP_VERSION; */
82 hdr
->hdr
.it_len
= cpu_to_le16(sizeof(*hdr
));
83 hdr
->hdr
.it_present
= cpu_to_le32
84 (1 << IEEE80211_RADIOTAP_RATE
);
89 skb_reset_mac_header(skb
);
90 skb
->ip_summed
= CHECKSUM_UNNECESSARY
;
91 skb
->pkt_type
= PACKET_OTHERHOST
;
92 skb
->protocol
= htons(ETH_P_802_2
);
93 memset(skb
->cb
, 0, sizeof(skb
->cb
));
98 struct tx_complete_mon_data
{
103 static void mgmt_tx_complete(void *priv
, int status
)
105 struct tx_complete_mon_data
*pv_data
= priv
;
107 * in case of fully hosting mode, the freeing will be done
108 * in response to the cfg packet
110 kfree(pv_data
->buff
);
115 static int mon_mgmt_tx(struct net_device
*dev
, const u8
*buf
, size_t len
)
117 struct tx_complete_mon_data
*mgmt_tx
= NULL
;
122 netif_stop_queue(dev
);
123 mgmt_tx
= kmalloc(sizeof(*mgmt_tx
), GFP_ATOMIC
);
127 mgmt_tx
->buff
= kmemdup(buf
, len
, GFP_ATOMIC
);
128 if (!mgmt_tx
->buff
) {
135 wilc_wlan_txq_add_mgmt_pkt(dev
, mgmt_tx
, mgmt_tx
->buff
, mgmt_tx
->size
,
138 netif_wake_queue(dev
);
142 static netdev_tx_t
wilc_wfi_mon_xmit(struct sk_buff
*skb
,
143 struct net_device
*dev
)
145 u32 rtap_len
, ret
= 0;
146 struct wilc_wfi_mon_priv
*mon_priv
;
147 struct sk_buff
*skb2
;
148 struct wilc_wfi_radiotap_cb_hdr
*cb_hdr
;
152 mon_priv
= netdev_priv(dev
);
156 rtap_len
= ieee80211_get_radiotap_len(skb
->data
);
157 if (skb
->len
< rtap_len
)
160 skb_pull(skb
, rtap_len
);
162 if (skb
->data
[0] == 0xc0 && is_broadcast_ether_addr(&skb
->data
[4])) {
163 skb2
= dev_alloc_skb(skb
->len
+ sizeof(*cb_hdr
));
167 skb_put_data(skb2
, skb
->data
, skb
->len
);
169 cb_hdr
= skb_push(skb2
, sizeof(*cb_hdr
));
170 memset(cb_hdr
, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr
));
172 cb_hdr
->hdr
.it_version
= 0; /* PKTHDR_RADIOTAP_VERSION; */
174 cb_hdr
->hdr
.it_len
= cpu_to_le16(sizeof(*cb_hdr
));
176 cb_hdr
->hdr
.it_present
= cpu_to_le32(TX_RADIOTAP_PRESENT
);
179 cb_hdr
->tx_flags
= 0x0004;
182 skb_reset_mac_header(skb2
);
183 skb2
->ip_summed
= CHECKSUM_UNNECESSARY
;
184 skb2
->pkt_type
= PACKET_OTHERHOST
;
185 skb2
->protocol
= htons(ETH_P_802_2
);
186 memset(skb2
->cb
, 0, sizeof(skb2
->cb
));
192 skb
->dev
= mon_priv
->real_ndev
;
194 ether_addr_copy(srcadd
, &skb
->data
[10]);
195 ether_addr_copy(bssid
, &skb
->data
[16]);
197 * Identify if data or mgmt packet, if source address and bssid
198 * fields are equal send it to mgmt frames handler
200 if (!(memcmp(srcadd
, bssid
, 6))) {
201 ret
= mon_mgmt_tx(mon_priv
->real_ndev
, skb
->data
, skb
->len
);
203 netdev_err(dev
, "fail to mgmt tx\n");
206 ret
= wilc_mac_xmit(skb
, mon_priv
->real_ndev
);
212 static const struct net_device_ops wilc_wfi_netdev_ops
= {
213 .ndo_start_xmit
= wilc_wfi_mon_xmit
,
217 struct net_device
*wilc_wfi_init_mon_interface(struct wilc
*wl
,
219 struct net_device
*real_dev
)
221 struct wilc_wfi_mon_priv
*priv
;
223 /* If monitor interface is already initialized, return it */
225 return wl
->monitor_dev
;
227 wl
->monitor_dev
= alloc_etherdev(sizeof(struct wilc_wfi_mon_priv
));
228 if (!wl
->monitor_dev
)
231 wl
->monitor_dev
->type
= ARPHRD_IEEE80211_RADIOTAP
;
232 strscpy(wl
->monitor_dev
->name
, name
, IFNAMSIZ
);
233 wl
->monitor_dev
->netdev_ops
= &wilc_wfi_netdev_ops
;
234 wl
->monitor_dev
->needs_free_netdev
= true;
236 if (register_netdevice(wl
->monitor_dev
)) {
237 netdev_err(real_dev
, "register_netdevice failed\n");
238 free_netdev(wl
->monitor_dev
);
241 priv
= netdev_priv(wl
->monitor_dev
);
243 priv
->real_ndev
= real_dev
;
245 return wl
->monitor_dev
;
248 void wilc_wfi_deinit_mon_interface(struct wilc
*wl
, bool rtnl_locked
)
250 if (!wl
->monitor_dev
)
254 unregister_netdevice(wl
->monitor_dev
);
256 unregister_netdev(wl
->monitor_dev
);
257 wl
->monitor_dev
= NULL
;