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