Merge branch 'testing/driver-warnings' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-block.git] / drivers / staging / csr / monitor.c
1 /*
2  * ---------------------------------------------------------------------------
3  *  FILE:     monitor.c
4  *
5  * Copyright (C) 2006-2008 by Cambridge Silicon Radio Ltd.
6  *
7  * Refer to LICENSE.txt included with this source code for details on
8  * the license terms.
9  *
10  * ---------------------------------------------------------------------------
11  */
12
13 #include <linux/version.h>
14 #include "unifi_priv.h"
15
16 #ifdef UNIFI_SNIFF_ARPHRD
17
18
19 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
20 #include <net/ieee80211_radiotap.h>
21 #endif
22
23 #ifndef ETH_P_80211_RAW
24 #define ETH_P_80211_RAW ETH_P_ALL
25 #endif
26
27 /*
28  * ---------------------------------------------------------------------------
29  *  uf_start_sniff
30  *
31  *      Start UniFi capture in SNIFF mode, i.e capture everything it hears.
32  *
33  *  Arguments:
34  *      priv            Pointer to device private context struct
35  *
36  *  Returns:
37  *      0 on success or kernel error code
38  * ---------------------------------------------------------------------------
39  */
40 int
41 uf_start_sniff(unifi_priv_t *priv)
42 {
43     ul_client_t *pcli = priv->wext_client;
44     CSR_SIGNAL signal;
45     CSR_MLME_SNIFFJOIN_REQUEST *req = &signal.u.MlmeSniffjoinRequest;
46     int timeout = 1000;
47     int r;
48
49     req->Ifindex = priv->if_index;
50     req->Channel = priv->wext_conf.channel;
51     req->ChannelStartingFactor = 0;
52
53     signal.SignalPrimitiveHeader.SignalId = CSR_MLME_SNIFFJOIN_REQUEST_ID;
54
55     r = unifi_mlme_blocking_request(priv, pcli, &signal, NULL, timeout);
56     if (r < 0) {
57         unifi_error(priv, "failed to send SNIFFJOIN request, error %d\n", r);
58         return r;
59     }
60
61     r = pcli->reply_signal->u.MlmeSniffjoinConfirm.Resultcode;
62     if (r) {
63         unifi_notice(priv, "SNIFFJOIN request was rejected with result 0x%X (%s)\n",
64                      r, lookup_result_code(r));
65         return -EIO;
66     }
67
68     return 0;
69 } /* uf_start_sniff() */
70
71
72
73 /*
74  * ---------------------------------------------------------------------------
75  * netrx_radiotap
76  *
77  *      Reformat a UniFi SNIFFDATA signal into a radiotap packet.
78  *
79  * Arguments:
80  *      priv            OS private context pointer.
81  *      ind             Pointer to a MA_UNITDATA_INDICATION or
82  *                      DS_UNITDATA_INDICATION indication structure.
83  *
84  * Notes:
85  *      Radiotap header values are all little-endian, UniFi signals will have
86  *      been converted to host-endian.
87  * ---------------------------------------------------------------------------
88  */
89 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
90 static void
91 netrx_radiotap(unifi_priv_t *priv,
92                const CSR_MA_SNIFFDATA_INDICATION *ind,
93                struct sk_buff *skb_orig)
94 {
95     struct net_device *dev = priv->netdev;
96     struct sk_buff *skb = NULL;
97     unsigned char *ptr;
98     unsigned char *base;
99     int ind_data_len = skb_orig->len - 2 - ETH_HLEN;
100     struct unifi_rx_radiotap_header {
101         struct ieee80211_radiotap_header rt_hdr;
102         /* IEEE80211_RADIOTAP_TSFT */
103         u64 rt_tsft;
104         /* IEEE80211_RADIOTAP_FLAGS */
105         u8  rt_flags;
106         /* IEEE80211_RADIOTAP_RATE */
107         u8  rt_rate;
108         /* IEEE80211_RADIOTAP_CHANNEL */
109         u16 rt_chan;
110         u16 rt_chan_flags;
111         /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
112         u8  rt_dbm_antsignal;
113         /* IEEE80211_RADIOTAP_DBM_ANTNOISE */
114         u8  rt_dbm_antnoise;
115         /* IEEE80211_RADIOTAP_ANTENNA */
116         u8  rt_antenna;
117
118         /* pad to 4-byte boundary */
119         u8 pad[3];
120     } __attribute__((__packed__));
121
122     struct unifi_rx_radiotap_header *unifi_rt;
123     int signal, noise, snr;
124
125     func_enter();
126
127     if (ind_data_len <= 0) {
128         unifi_error(priv, "Invalid length in CSR_MA_SNIFFDATA_INDICATION.\n");
129         return;
130     }
131
132     /*
133      * Allocate a SKB for the received data packet, including radiotap
134      * header.
135      */
136     skb = dev_alloc_skb(ind_data_len + sizeof(struct unifi_rx_radiotap_header) + 4);
137     if (! skb) {
138         unifi_error(priv, "alloc_skb failed.\n");
139         priv->stats.rx_errors++;
140         return;
141     }
142
143     base = skb->data;
144
145     /* Reserve the radiotap header at the front of skb */
146     unifi_rt = (struct unifi_rx_radiotap_header *)
147         skb_put(skb, sizeof(struct unifi_rx_radiotap_header));
148
149     /* Copy in the 802.11 frame */
150     ptr = skb_put(skb, ind_data_len);
151     memcpy(ptr, skb_orig->data, ind_data_len);
152
153     unifi_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
154     unifi_rt->rt_hdr.it_pad = 0;        /* always good to zero */
155     unifi_rt->rt_hdr.it_len = sizeof(struct unifi_rx_radiotap_header);
156
157     /* Big bitfield of all the fields we provide in radiotap */
158     unifi_rt->rt_hdr.it_present = 0
159         | (1 << IEEE80211_RADIOTAP_TSFT)
160         | (1 << IEEE80211_RADIOTAP_FLAGS)
161         | (1 << IEEE80211_RADIOTAP_RATE)
162         | (1 << IEEE80211_RADIOTAP_CHANNEL)
163         | (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL)
164         | (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)
165         | (1 << IEEE80211_RADIOTAP_ANTENNA)
166         ;
167
168
169     /* No flags to set */
170     unifi_rt->rt_tsft = (((u64)ind->Timestamp.x[7]) | (((u64)ind->Timestamp.x[6]) << 8) |
171                          (((u64)ind->Timestamp.x[5]) << 16) | (((u64)ind->Timestamp.x[4]) << 24) |
172                          (((u64)ind->Timestamp.x[3]) << 32) | (((u64)ind->Timestamp.x[2]) << 40) |
173                          (((u64)ind->Timestamp.x[1]) << 48) | (((u64)ind->Timestamp.x[0]) << 56));
174
175     unifi_rt->rt_flags = 0;
176
177     unifi_rt->rt_rate = ind->Rate;
178
179     unifi_rt->rt_chan = cpu_to_le16(ieee80211chan2mhz(priv->wext_conf.channel));
180     unifi_rt->rt_chan_flags = 0;
181
182     /* Convert signal to dBm */
183     signal = (s16)unifi2host_16(ind->Rssi);  /* in dBm */
184     snr    = (s16)unifi2host_16(ind->Snr);   /* in dB */
185     noise  = signal - snr;
186
187     unifi_rt->rt_dbm_antsignal = signal;
188     unifi_rt->rt_dbm_antnoise = noise;
189
190     unifi_rt->rt_antenna = ind->AntennaId;
191
192
193     skb->dev = dev;
194     skb->mac_header = skb->data;
195     skb->pkt_type = PACKET_OTHERHOST;
196     skb->protocol = __constant_htons(ETH_P_80211_RAW);
197     memset(skb->cb, 0, sizeof(skb->cb));
198
199     /* Pass up to Linux network stack */
200     netif_rx_ni(skb);
201
202     dev->last_rx = jiffies;
203
204     /* Bump the rx stats */
205     priv->stats.rx_packets++;
206     priv->stats.rx_bytes += ind_data_len;
207
208     func_exit();
209 } /* netrx_radiotap() */
210 #endif /* RADIOTAP */
211
212
213 /*
214  * ---------------------------------------------------------------------------
215  * netrx_prism
216  *
217  *      Reformat a UniFi SNIFFDATA signal into a Prism format sniff packet.
218  *
219  * Arguments:
220  *      priv            OS private context pointer.
221  *      ind             Pointer to a MA_UNITDATA_INDICATION or
222  *                      DS_UNITDATA_INDICATION indication structure.
223  *
224  * Notes:
225  *      Radiotap header values are all little-endian, UniFi signals will have
226  *      been converted to host-endian.
227  * ---------------------------------------------------------------------------
228  */
229 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_PRISM)
230 static void
231 netrx_prism(unifi_priv_t *priv,
232             const CSR_MA_SNIFFDATA_INDICATION *ind,
233             struct sk_buff *skb_orig)
234 {
235     struct net_device *dev = priv->netdev;
236     struct sk_buff *skb = NULL;
237     unsigned char *ptr;
238     unsigned char *base;
239     int ind_data_len = skb_orig->len - 2 - ETH_HLEN;
240 #define WLANCAP_MAGIC_COOKIE_V1 0x80211001
241     struct avs_header_v1 {
242         uint32  version;
243         uint32  length;
244         uint64  mactime;
245         uint64  hosttime;
246         uint32  phytype;
247         uint32  channel;
248         uint32  datarate;
249         uint32  antenna;
250         uint32  priority;
251         uint32  ssi_type;
252         int32   ssi_signal;
253         int32   ssi_noise;
254         uint32  preamble;
255         uint32  encoding;
256     } *avs;
257     int signal, noise, snr;
258
259     func_enter();
260
261     if (ind_data_len <= 0) {
262         unifi_error(priv, "Invalid length in CSR_MA_SNIFFDATA_INDICATION.\n");
263         return;
264     }
265
266     /*
267      * Allocate a SKB for the received data packet, including radiotap
268      * header.
269      */
270     skb = dev_alloc_skb(ind_data_len + sizeof(struct avs_header_v1) + 4);
271     if (! skb) {
272         unifi_error(priv, "alloc_skb failed.\n");
273         priv->stats.rx_errors++;
274         return;
275     }
276
277     base = skb->data;
278
279     /* Reserve the radiotap header at the front of skb */
280     avs = (struct avs_header_v1 *)skb_put(skb, sizeof(struct avs_header_v1));
281
282     /* Copy in the 802.11 frame */
283     ptr = skb_put(skb, ind_data_len);
284     memcpy(ptr, skb_orig->data, ind_data_len);
285
286     /* Convert signal to dBm */
287     signal = 0x10000 - ((s16)unifi2host_16(ind->Rssi));  /* in dBm */
288     snr    = (s16)unifi2host_16(ind->Snr);   /* in dB */
289     noise  = signal - snr;
290
291     avs->version        = htonl(WLANCAP_MAGIC_COOKIE_V1);
292     avs->length         = htonl(sizeof(struct avs_header_v1));
293     avs->mactime        = __cpu_to_be64(ind->Timestamp);
294     avs->hosttime       = __cpu_to_be64(jiffies);
295     avs->phytype        = htonl(9);             /* dss_ofdm_dot11_g */
296     avs->channel        = htonl(priv->wext_conf.channel);
297     avs->datarate       = htonl(ind->Rate * 5);
298     avs->antenna        = htonl(ind->Antenna);
299     avs->priority       = htonl(0);             /* unknown */
300     avs->ssi_type       = htonl(2);             /* dBm */
301     avs->ssi_signal     = htonl(signal);
302     avs->ssi_noise      = htonl(noise);
303     avs->preamble       = htonl(0); /* unknown */
304     avs->encoding       = htonl(0); /* unknown */
305
306
307     skb->dev = dev;
308     skb->mac.raw = skb->data;
309     skb->pkt_type = PACKET_OTHERHOST;
310     skb->protocol = __constant_htons(ETH_P_80211_RAW);
311     memset(skb->cb, 0, sizeof(skb->cb));
312
313     /* Pass up to Linux network stack */
314     netif_rx_ni(skb);
315
316     dev->last_rx = jiffies;
317
318     /* Bump the rx stats */
319     priv->stats.rx_packets++;
320     priv->stats.rx_bytes += ind_data_len;
321
322     func_exit();
323 } /* netrx_prism() */
324 #endif /* PRISM */
325
326
327 /*
328  * ---------------------------------------------------------------------------
329  * ma_sniffdata_ind
330  *
331  *      Reformat a UniFi SNIFFDATA signal into a network
332  *
333  * Arguments:
334  *      ospriv          OS private context pointer.
335  *      ind             Pointer to a MA_UNITDATA_INDICATION or
336  *                      DS_UNITDATA_INDICATION indication structure.
337  *      bulkdata        Pointer to a bulk data structure, describing
338  *                      the data received.
339  *
340  * Notes:
341  *      Radiotap header values are all little-endian, UniFi signals will have
342  *      been converted to host-endian.
343  * ---------------------------------------------------------------------------
344  */
345 void
346 ma_sniffdata_ind(void *ospriv,
347                  const CSR_MA_SNIFFDATA_INDICATION *ind,
348                  const bulk_data_param_t *bulkdata)
349 {
350     unifi_priv_t *priv = ospriv;
351     struct net_device *dev = priv->netdev;
352     struct sk_buff *skb = (struct sk_buff*)bulkdata->d[0].os_net_buf_ptr;
353
354     func_enter();
355
356     if (bulkdata->d[0].data_length == 0) {
357         unifi_warning(priv, "rx: MA-SNIFFDATA indication with zero bulk data\n");
358         func_exit();
359         return;
360     }
361
362     skb->len = bulkdata->d[0].data_length;
363
364     /* We only process data packets if the interface is open */
365     if (unlikely(!netif_running(dev))) {
366         priv->stats.rx_dropped++;
367         priv->wext_conf.wireless_stats.discard.misc++;
368         dev_kfree_skb(skb);
369         return;
370     }
371
372     if (ind->ReceptionStatus) {
373         priv->stats.rx_dropped++;
374         priv->wext_conf.wireless_stats.discard.misc++;
375         printk(KERN_INFO "unifi: Dropping corrupt sniff packet\n");
376         dev_kfree_skb(skb);
377         return;
378     }
379
380 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_PRISM)
381     netrx_prism(priv, ind, skb);
382 #endif /* PRISM */
383
384 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
385     netrx_radiotap(priv, ind, skb);
386 #endif /* RADIOTAP */
387
388     dev_kfree_skb(skb);
389
390 } /* ma_sniffdata_ind() */
391
392
393 #endif /* UNIFI_SNIFF_ARPHRD */
394