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