2 * ---------------------------------------------------------------------------
5 * Copyright (C) 2006-2008 by Cambridge Silicon Radio Ltd.
7 * Refer to LICENSE.txt included with this source code for details on
10 * ---------------------------------------------------------------------------
13 #include <linux/version.h>
14 #include "unifi_priv.h"
16 #ifdef UNIFI_SNIFF_ARPHRD
19 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
20 #include <net/ieee80211_radiotap.h>
23 #ifndef ETH_P_80211_RAW
24 #define ETH_P_80211_RAW ETH_P_ALL
28 * ---------------------------------------------------------------------------
31 * Start UniFi capture in SNIFF mode, i.e capture everything it hears.
34 * priv Pointer to device private context struct
37 * 0 on success or kernel error code
38 * ---------------------------------------------------------------------------
41 uf_start_sniff(unifi_priv_t *priv)
43 ul_client_t *pcli = priv->wext_client;
45 CSR_MLME_SNIFFJOIN_REQUEST *req = &signal.u.MlmeSniffjoinRequest;
49 req->Ifindex = priv->if_index;
50 req->Channel = priv->wext_conf.channel;
51 req->ChannelStartingFactor = 0;
53 signal.SignalPrimitiveHeader.SignalId = CSR_MLME_SNIFFJOIN_REQUEST_ID;
55 r = unifi_mlme_blocking_request(priv, pcli, &signal, NULL, timeout);
57 unifi_error(priv, "failed to send SNIFFJOIN request, error %d\n", r);
61 r = pcli->reply_signal->u.MlmeSniffjoinConfirm.Resultcode;
63 unifi_notice(priv, "SNIFFJOIN request was rejected with result 0x%X (%s)\n",
64 r, lookup_result_code(r));
69 } /* uf_start_sniff() */
74 * ---------------------------------------------------------------------------
77 * Reformat a UniFi SNIFFDATA signal into a radiotap packet.
80 * priv OS private context pointer.
81 * ind Pointer to a MA_UNITDATA_INDICATION or
82 * DS_UNITDATA_INDICATION indication structure.
85 * Radiotap header values are all little-endian, UniFi signals will have
86 * been converted to host-endian.
87 * ---------------------------------------------------------------------------
89 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
91 netrx_radiotap(unifi_priv_t *priv,
92 const CSR_MA_SNIFFDATA_INDICATION *ind,
93 struct sk_buff *skb_orig)
95 struct net_device *dev = priv->netdev;
96 struct sk_buff *skb = NULL;
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 */
104 /* IEEE80211_RADIOTAP_FLAGS */
106 /* IEEE80211_RADIOTAP_RATE */
108 /* IEEE80211_RADIOTAP_CHANNEL */
111 /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
113 /* IEEE80211_RADIOTAP_DBM_ANTNOISE */
115 /* IEEE80211_RADIOTAP_ANTENNA */
118 /* pad to 4-byte boundary */
120 } __attribute__((__packed__));
122 struct unifi_rx_radiotap_header *unifi_rt;
123 int signal, noise, snr;
127 if (ind_data_len <= 0) {
128 unifi_error(priv, "Invalid length in CSR_MA_SNIFFDATA_INDICATION.\n");
133 * Allocate a SKB for the received data packet, including radiotap
136 skb = dev_alloc_skb(ind_data_len + sizeof(struct unifi_rx_radiotap_header) + 4);
138 unifi_error(priv, "alloc_skb failed.\n");
139 priv->stats.rx_errors++;
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));
149 /* Copy in the 802.11 frame */
150 ptr = skb_put(skb, ind_data_len);
151 memcpy(ptr, skb_orig->data, ind_data_len);
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);
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)
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));
175 unifi_rt->rt_flags = 0;
177 unifi_rt->rt_rate = ind->Rate;
179 unifi_rt->rt_chan = cpu_to_le16(ieee80211chan2mhz(priv->wext_conf.channel));
180 unifi_rt->rt_chan_flags = 0;
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;
187 unifi_rt->rt_dbm_antsignal = signal;
188 unifi_rt->rt_dbm_antnoise = noise;
190 unifi_rt->rt_antenna = ind->AntennaId;
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));
199 /* Pass up to Linux network stack */
202 dev->last_rx = jiffies;
204 /* Bump the rx stats */
205 priv->stats.rx_packets++;
206 priv->stats.rx_bytes += ind_data_len;
209 } /* netrx_radiotap() */
210 #endif /* RADIOTAP */
214 * ---------------------------------------------------------------------------
217 * Reformat a UniFi SNIFFDATA signal into a Prism format sniff packet.
220 * priv OS private context pointer.
221 * ind Pointer to a MA_UNITDATA_INDICATION or
222 * DS_UNITDATA_INDICATION indication structure.
225 * Radiotap header values are all little-endian, UniFi signals will have
226 * been converted to host-endian.
227 * ---------------------------------------------------------------------------
229 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_PRISM)
231 netrx_prism(unifi_priv_t *priv,
232 const CSR_MA_SNIFFDATA_INDICATION *ind,
233 struct sk_buff *skb_orig)
235 struct net_device *dev = priv->netdev;
236 struct sk_buff *skb = NULL;
239 int ind_data_len = skb_orig->len - 2 - ETH_HLEN;
240 #define WLANCAP_MAGIC_COOKIE_V1 0x80211001
241 struct avs_header_v1 {
257 int signal, noise, snr;
261 if (ind_data_len <= 0) {
262 unifi_error(priv, "Invalid length in CSR_MA_SNIFFDATA_INDICATION.\n");
267 * Allocate a SKB for the received data packet, including radiotap
270 skb = dev_alloc_skb(ind_data_len + sizeof(struct avs_header_v1) + 4);
272 unifi_error(priv, "alloc_skb failed.\n");
273 priv->stats.rx_errors++;
279 /* Reserve the radiotap header at the front of skb */
280 avs = (struct avs_header_v1 *)skb_put(skb, sizeof(struct avs_header_v1));
282 /* Copy in the 802.11 frame */
283 ptr = skb_put(skb, ind_data_len);
284 memcpy(ptr, skb_orig->data, ind_data_len);
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;
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 */
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));
313 /* Pass up to Linux network stack */
316 dev->last_rx = jiffies;
318 /* Bump the rx stats */
319 priv->stats.rx_packets++;
320 priv->stats.rx_bytes += ind_data_len;
323 } /* netrx_prism() */
328 * ---------------------------------------------------------------------------
331 * Reformat a UniFi SNIFFDATA signal into a network
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
341 * Radiotap header values are all little-endian, UniFi signals will have
342 * been converted to host-endian.
343 * ---------------------------------------------------------------------------
346 ma_sniffdata_ind(void *ospriv,
347 const CSR_MA_SNIFFDATA_INDICATION *ind,
348 const bulk_data_param_t *bulkdata)
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;
356 if (bulkdata->d[0].data_length == 0) {
357 unifi_warning(priv, "rx: MA-SNIFFDATA indication with zero bulk data\n");
362 skb->len = bulkdata->d[0].data_length;
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++;
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");
380 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_PRISM)
381 netrx_prism(priv, ind, skb);
384 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
385 netrx_radiotap(priv, ind, skb);
386 #endif /* RADIOTAP */
390 } /* ma_sniffdata_ind() */
393 #endif /* UNIFI_SNIFF_ARPHRD */