Root/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 */
41int
42uf_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)
91static void
92netrx_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)
235static void
236netrx_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 */
350void
351ma_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
400

Archive Download this file



interactive