Adding support for MOXA ART SoC. Testing port of linux-2.6.32.60-moxart.
[linux-3.6.7-moxart.git] / drivers / staging / csr / monitor.c
blob628782ad641e4ee62534b542869a13db4d8af399
1 /*
2 * ---------------------------------------------------------------------------
3 * FILE: monitor.c
5 * Copyright (C) 2006-2008 by Cambridge Silicon Radio Ltd.
7 * Refer to LICENSE.txt included with this source code for details on
8 * the license terms.
10 * ---------------------------------------------------------------------------
13 #include "unifi_priv.h"
15 #ifdef UNIFI_SNIFF_ARPHRD
18 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
19 #include <net/ieee80211_radiotap.h>
20 #endif
22 #ifndef ETH_P_80211_RAW
23 #define ETH_P_80211_RAW ETH_P_ALL
24 #endif
29 * ---------------------------------------------------------------------------
30 * uf_start_sniff
32 * Start UniFi capture in SNIFF mode, i.e capture everything it hears.
34 * Arguments:
35 * priv Pointer to device private context struct
37 * Returns:
38 * 0 on success or kernel error code
39 * ---------------------------------------------------------------------------
41 int
42 uf_start_sniff(unifi_priv_t *priv)
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;
50 req->Ifindex = priv->if_index;
51 req->Channel = priv->wext_conf.channel;
52 req->ChannelStartingFactor = 0;
54 signal.SignalPrimitiveHeader.SignalId = CSR_MLME_SNIFFJOIN_REQUEST_ID;
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;
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;
69 return 0;
70 } /* uf_start_sniff() */
75 * ---------------------------------------------------------------------------
76 * netrx_radiotap
78 * Reformat a UniFi SNIFFDATA signal into a radiotap packet.
80 * Arguments:
81 * priv OS private context pointer.
82 * ind Pointer to a MA_UNITDATA_INDICATION or
83 * DS_UNITDATA_INDICATION indication structure.
85 * Notes:
86 * Radiotap header values are all little-endian, UniFi signals will have
87 * been converted to host-endian.
88 * ---------------------------------------------------------------------------
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)
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;
119 /* pad to 4-byte boundary */
120 u8 pad[3];
121 } __attribute__((__packed__));
123 struct unifi_rx_radiotap_header *unifi_rt;
124 int signal, noise, snr;
126 func_enter();
128 if (ind_data_len <= 0) {
129 unifi_error(priv, "Invalid length in CSR_MA_SNIFFDATA_INDICATION.\n");
130 return;
134 * Allocate a SKB for the received data packet, including radiotap
135 * header.
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;
144 base = skb->data;
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));
150 /* Copy in the 802.11 frame */
151 ptr = skb_put(skb, ind_data_len);
152 memcpy(ptr, skb_orig->data, ind_data_len);
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);
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)
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));
176 unifi_rt->rt_flags = 0;
178 unifi_rt->rt_rate = ind->Rate;
180 unifi_rt->rt_chan = cpu_to_le16(ieee80211chan2mhz(priv->wext_conf.channel));
181 unifi_rt->rt_chan_flags = 0;
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;
188 unifi_rt->rt_dbm_antsignal = signal;
189 unifi_rt->rt_dbm_antnoise = noise;
191 unifi_rt->rt_antenna = ind->AntennaId;
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));
204 /* Pass up to Linux network stack */
205 netif_rx_ni(skb);
207 dev->last_rx = jiffies;
209 /* Bump the rx stats */
210 priv->stats.rx_packets++;
211 priv->stats.rx_bytes += ind_data_len;
213 func_exit();
214 } /* netrx_radiotap() */
215 #endif /* RADIOTAP */
219 * ---------------------------------------------------------------------------
220 * netrx_prism
222 * Reformat a UniFi SNIFFDATA signal into a Prism format sniff packet.
224 * Arguments:
225 * priv OS private context pointer.
226 * ind Pointer to a MA_UNITDATA_INDICATION or
227 * DS_UNITDATA_INDICATION indication structure.
229 * Notes:
230 * Radiotap header values are all little-endian, UniFi signals will have
231 * been converted to host-endian.
232 * ---------------------------------------------------------------------------
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)
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;
264 func_enter();
266 if (ind_data_len <= 0) {
267 unifi_error(priv, "Invalid length in CSR_MA_SNIFFDATA_INDICATION.\n");
268 return;
272 * Allocate a SKB for the received data packet, including radiotap
273 * header.
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;
282 base = skb->data;
284 /* Reserve the radiotap header at the front of skb */
285 avs = (struct avs_header_v1 *)skb_put(skb, sizeof(struct avs_header_v1));
287 /* Copy in the 802.11 frame */
288 ptr = skb_put(skb, ind_data_len);
289 memcpy(ptr, skb_orig->data, ind_data_len);
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;
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 */
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));
318 /* Pass up to Linux network stack */
319 netif_rx_ni(skb);
321 dev->last_rx = jiffies;
323 /* Bump the rx stats */
324 priv->stats.rx_packets++;
325 priv->stats.rx_bytes += ind_data_len;
327 func_exit();
328 } /* netrx_prism() */
329 #endif /* PRISM */
333 * ---------------------------------------------------------------------------
334 * ma_sniffdata_ind
336 * Reformat a UniFi SNIFFDATA signal into a network
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.
345 * Notes:
346 * Radiotap header values are all little-endian, UniFi signals will have
347 * been converted to host-endian.
348 * ---------------------------------------------------------------------------
350 void
351 ma_sniffdata_ind(void *ospriv,
352 const CSR_MA_SNIFFDATA_INDICATION *ind,
353 const bulk_data_param_t *bulkdata)
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;
359 func_enter();
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;
367 skb->len = bulkdata->d[0].data_length;
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;
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;
385 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_PRISM)
386 netrx_prism(priv, ind, skb);
387 #endif /* PRISM */
389 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
390 netrx_radiotap(priv, ind, skb);
391 #endif /* RADIOTAP */
393 dev_kfree_skb(skb);
395 } /* ma_sniffdata_ind() */
398 #endif /* UNIFI_SNIFF_ARPHRD */