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 "unifi_priv.h"
15 #ifdef UNIFI_SNIFF_ARPHRD
18 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
19 #include <net/ieee80211_radiotap.h>
22 #ifndef ETH_P_80211_RAW
23 #define ETH_P_80211_RAW ETH_P_ALL
29 * ---------------------------------------------------------------------------
32 * Start UniFi capture in SNIFF mode, i.e capture everything it hears.
35 * priv Pointer to device private context struct
38 * 0 on success or kernel error code
39 * ---------------------------------------------------------------------------
42 uf_start_sniff(unifi_priv_t *priv)
44 ul_client_t *pcli = priv->wext_client;
46 CSR_MLME_SNIFFJOIN_REQUEST *req = &signal.u.MlmeSniffjoinRequest;
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);
58 unifi_error(priv, "failed to send SNIFFJOIN request, error %d\n", r);
62 r = pcli->reply_signal->u.MlmeSniffjoinConfirm.Resultcode;
64 unifi_notice(priv, "SNIFFJOIN request was rejected with result 0x%X (%s)\n",
65 r, lookup_result_code(r));
70 } /* uf_start_sniff() */
75 * ---------------------------------------------------------------------------
78 * Reformat a UniFi SNIFFDATA signal into a radiotap packet.
81 * priv OS private context pointer.
82 * ind Pointer to a MA_UNITDATA_INDICATION or
83 * DS_UNITDATA_INDICATION indication structure.
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)
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;
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 */
105 /* IEEE80211_RADIOTAP_FLAGS */
107 /* IEEE80211_RADIOTAP_RATE */
109 /* IEEE80211_RADIOTAP_CHANNEL */
112 /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
114 /* IEEE80211_RADIOTAP_DBM_ANTNOISE */
116 /* IEEE80211_RADIOTAP_ANTENNA */
119 /* pad to 4-byte boundary */
121 } __attribute__((__packed__));
123 struct unifi_rx_radiotap_header *unifi_rt;
124 int signal, noise, snr;
128 if (ind_data_len <= 0) {
129 unifi_error(priv, "Invalid length in CSR_MA_SNIFFDATA_INDICATION.\n");
134 * Allocate a SKB for the received data packet, including radiotap
137 skb = dev_alloc_skb(ind_data_len + sizeof(struct unifi_rx_radiotap_header) + 4);
139 unifi_error(priv, "alloc_skb failed.\n");
140 priv->stats.rx_errors++;
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;
195 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
196 skb->mac_header = skb->data;
198 skb->mac.raw = skb->data;
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 */
207 dev->last_rx = jiffies;
209 /* Bump the rx stats */
210 priv->stats.rx_packets++;
211 priv->stats.rx_bytes += ind_data_len;
214 } /* netrx_radiotap() */
215 #endif /* RADIOTAP */
219 * ---------------------------------------------------------------------------
222 * Reformat a UniFi SNIFFDATA signal into a Prism format sniff packet.
225 * priv OS private context pointer.
226 * ind Pointer to a MA_UNITDATA_INDICATION or
227 * DS_UNITDATA_INDICATION indication structure.
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)
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;
244 int ind_data_len = skb_orig->len - 2 - ETH_HLEN;
245 #define WLANCAP_MAGIC_COOKIE_V1 0x80211001
246 struct avs_header_v1 {
262 int signal, noise, snr;
266 if (ind_data_len <= 0) {
267 unifi_error(priv, "Invalid length in CSR_MA_SNIFFDATA_INDICATION.\n");
272 * Allocate a SKB for the received data packet, including radiotap
275 skb = dev_alloc_skb(ind_data_len + sizeof(struct avs_header_v1) + 4);
277 unifi_error(priv, "alloc_skb failed.\n");
278 priv->stats.rx_errors++;
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 */
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 */
321 dev->last_rx = jiffies;
323 /* Bump the rx stats */
324 priv->stats.rx_packets++;
325 priv->stats.rx_bytes += ind_data_len;
328 } /* netrx_prism() */
333 * ---------------------------------------------------------------------------
336 * Reformat a UniFi SNIFFDATA signal into a network
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
346 * Radiotap header values are all little-endian, UniFi signals will have
347 * been converted to host-endian.
348 * ---------------------------------------------------------------------------
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;
361 if (bulkdata->d[0].data_length == 0) {
362 unifi_warning(priv, "rx: MA-SNIFFDATA indication with zero bulk data\n");
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++;
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");
385 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_PRISM)
386 netrx_prism(priv, ind, skb);
389 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
390 netrx_radiotap(priv, ind, skb);
391 #endif /* RADIOTAP */
395 } /* ma_sniffdata_ind() */
398 #endif /* UNIFI_SNIFF_ARPHRD */