Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[linux-2.6-microblaze.git] / drivers / staging / rtl8188eu / os_dep / mon.c
1 /*
2  * RTL8188EU monitor interface
3  *
4  * Copyright (C) 2015 Jakub Sitnicki
5  *
6  * This program is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License version 2 as published by the
8  * Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13  * details.
14  */
15
16 #include <linux/ieee80211.h>
17 #include <linux/netdevice.h>
18 #include <net/cfg80211.h>
19
20 #include <drv_types.h>
21 #include <rtw_recv.h>
22 #include <rtw_xmit.h>
23 #include <mon.h>
24
25 /**
26  * unprotect_frame() - unset Protected flag and strip off IV and ICV/MIC
27  */
28 static void unprotect_frame(struct sk_buff *skb, int iv_len, int icv_len)
29 {
30         struct ieee80211_hdr *hdr;
31         int hdr_len;
32
33         hdr = (struct ieee80211_hdr *)skb->data;
34         hdr_len = ieee80211_hdrlen(hdr->frame_control);
35
36         if (skb->len < hdr_len + iv_len + icv_len)
37                 return;
38         if (!ieee80211_has_protected(hdr->frame_control))
39                 return;
40
41         hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_PROTECTED);
42
43         memmove(skb->data + iv_len, skb->data, hdr_len);
44         skb_pull(skb, iv_len);
45         skb_trim(skb, skb->len - icv_len);
46 }
47
48 static void mon_recv_decrypted(struct net_device *dev, const u8 *data,
49                                int data_len, int iv_len, int icv_len)
50 {
51         struct sk_buff *skb;
52
53         skb = netdev_alloc_skb(dev, data_len);
54         if (!skb)
55                 return;
56         skb_put_data(skb, data, data_len);
57
58         /*
59          * Frame data is not encrypted. Strip off protection so
60          * userspace doesn't think that it is.
61          */
62         unprotect_frame(skb, iv_len, icv_len);
63
64         skb->ip_summed = CHECKSUM_UNNECESSARY;
65         skb->protocol = eth_type_trans(skb, dev);
66         netif_rx(skb);
67 }
68
69 static void mon_recv_decrypted_recv(struct net_device *dev, const u8 *data,
70                                     int data_len)
71 {
72         struct sk_buff *skb;
73         struct ieee80211_hdr *hdr;
74         int hdr_len;
75
76         skb = netdev_alloc_skb(dev, data_len);
77         if (!skb)
78                 return;
79         memcpy(skb_put(skb, data_len), data, data_len);
80
81         /*
82          * Frame data is not encrypted. Strip off protection so
83          * userspace doesn't think that it is.
84          */
85
86         hdr = (struct ieee80211_hdr *)skb->data;
87         hdr_len = ieee80211_hdrlen(hdr->frame_control);
88
89         if (ieee80211_has_protected(hdr->frame_control))
90                 hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_PROTECTED);
91
92         skb->ip_summed = CHECKSUM_UNNECESSARY;
93         skb->protocol = eth_type_trans(skb, dev);
94         netif_rx(skb);
95 }
96
97 static void mon_recv_encrypted(struct net_device *dev, const u8 *data,
98                                int data_len)
99 {
100         if (net_ratelimit())
101                 netdev_info(dev, "Encrypted packets are not supported");
102 }
103
104 /**
105  * rtl88eu_mon_recv_hook() - forward received frame to the monitor interface
106  *
107  * Assumes that the frame contains an IV and an ICV/MIC, and that
108  * encrypt field in frame->attrib have been set accordingly.
109  */
110 void rtl88eu_mon_recv_hook(struct net_device *dev, struct recv_frame *frame)
111 {
112         struct rx_pkt_attrib *attr;
113         int data_len;
114         u8 *data;
115
116         if (!dev || !frame)
117                 return;
118         if (!netif_running(dev))
119                 return;
120
121         attr = &frame->attrib;
122         data = frame->pkt->data;
123         data_len = frame->pkt->len;
124
125         if (attr->bdecrypted)
126                 mon_recv_decrypted_recv(dev, data, data_len);
127         else
128                 mon_recv_encrypted(dev, data, data_len);
129 }
130
131 /**
132  * rtl88eu_mon_xmit_hook() - forward trasmitted frame to the monitor interface
133  *
134  * Assumes that:
135  * - frame header contains an IV and frame->attrib.iv_len is set accordingly,
136  * - data is not encrypted and ICV/MIC has not been appended yet.
137  */
138 void rtl88eu_mon_xmit_hook(struct net_device *dev, struct xmit_frame *frame,
139                            uint frag_len)
140 {
141         struct pkt_attrib *attr;
142         u8 *data;
143         int i, offset;
144
145         if (!dev || !frame)
146                 return;
147         if (!netif_running(dev))
148                 return;
149
150         attr = &frame->attrib;
151
152         offset = TXDESC_SIZE + frame->pkt_offset * PACKET_OFFSET_SZ;
153         data = frame->buf_addr + offset;
154
155         for (i = 0; i < attr->nr_frags - 1; i++) {
156                 mon_recv_decrypted(dev, data, frag_len, attr->iv_len, 0);
157                 data += frag_len;
158                 data = (u8 *)round_up((size_t)data, 4);
159         }
160         /* Last fragment has different length */
161         mon_recv_decrypted(dev, data, attr->last_txcmdsz, attr->iv_len, 0);
162 }
163
164 static netdev_tx_t mon_xmit(struct sk_buff *skb, struct net_device *dev)
165 {
166         dev_kfree_skb(skb);
167         return NETDEV_TX_OK;
168 }
169
170 static const struct net_device_ops mon_netdev_ops = {
171         .ndo_start_xmit         = mon_xmit,
172         .ndo_set_mac_address    = eth_mac_addr,
173         .ndo_validate_addr      = eth_validate_addr,
174 };
175
176 static void mon_setup(struct net_device *dev)
177 {
178         dev->netdev_ops = &mon_netdev_ops;
179         dev->needs_free_netdev = true;
180         ether_setup(dev);
181         dev->priv_flags |= IFF_NO_QUEUE;
182         dev->type = ARPHRD_IEEE80211;
183         /*
184          * Use a locally administered address (IEEE 802)
185          * XXX: Copied from mac80211_hwsim driver. Revisit.
186          */
187         eth_zero_addr(dev->dev_addr);
188         dev->dev_addr[0] = 0x12;
189 }
190
191 struct net_device *rtl88eu_mon_init(void)
192 {
193         struct net_device *dev;
194         int err;
195
196         dev = alloc_netdev(0, "mon%d", NET_NAME_UNKNOWN, mon_setup);
197         if (!dev)
198                 goto fail;
199
200         err = register_netdev(dev);
201         if (err < 0)
202                 goto fail_free_dev;
203
204         return dev;
205
206 fail_free_dev:
207         free_netdev(dev);
208 fail:
209         return NULL;
210 }
211
212 void rtl88eu_mon_deinit(struct net_device *dev)
213 {
214         if (!dev)
215                 return;
216
217         unregister_netdev(dev);
218 }