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
27 * ---------------------------------------------------------------------------
30 * Start UniFi capture in SNIFF mode, i.e capture everything it hears.
33 * priv Pointer to device private context struct
36 * 0 on success or kernel error code
37 * ---------------------------------------------------------------------------
40 uf_start_sniff(unifi_priv_t *priv)
42 ul_client_t *pcli = priv->wext_client;
44 CSR_MLME_SNIFFJOIN_REQUEST *req = &signal.u.MlmeSniffjoinRequest;
48 req->Ifindex = priv->if_index;
49 req->Channel = priv->wext_conf.channel;
50 req->ChannelStartingFactor = 0;
52 signal.SignalPrimitiveHeader.SignalId = CSR_MLME_SNIFFJOIN_REQUEST_ID;
54 r = unifi_mlme_blocking_request(priv, pcli, &signal, NULL, timeout);
56 unifi_error(priv, "failed to send SNIFFJOIN request, error %d\n", r);
60 r = pcli->reply_signal->u.MlmeSniffjoinConfirm.Resultcode;
62 unifi_notice(priv, "SNIFFJOIN request was rejected with result 0x%X (%s)\n",
63 r, lookup_result_code(r));
68 } /* uf_start_sniff() */
73 * ---------------------------------------------------------------------------
76 * Reformat a UniFi SNIFFDATA signal into a radiotap packet.
79 * priv OS private context pointer.
80 * ind Pointer to a MA_UNITDATA_INDICATION or
81 * DS_UNITDATA_INDICATION indication structure.
84 * Radiotap header values are all little-endian, UniFi signals will have
85 * been converted to host-endian.
86 * ---------------------------------------------------------------------------
88 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
90 netrx_radiotap(unifi_priv_t *priv,
91 const CSR_MA_SNIFFDATA_INDICATION *ind,
92 struct sk_buff *skb_orig)
94 struct net_device *dev = priv->netdev;
95 struct sk_buff *skb = NULL;
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 */
103 /* IEEE80211_RADIOTAP_FLAGS */
105 /* IEEE80211_RADIOTAP_RATE */
107 /* IEEE80211_RADIOTAP_CHANNEL */
110 /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
112 /* IEEE80211_RADIOTAP_DBM_ANTNOISE */
114 /* IEEE80211_RADIOTAP_ANTENNA */
117 /* pad to 4-byte boundary */
119 } __attribute__((__packed__));
121 struct unifi_rx_radiotap_header *unifi_rt;
122 int signal, noise, snr;
124 if (ind_data_len <= 0) {
125 unifi_error(priv, "Invalid length in CSR_MA_SNIFFDATA_INDICATION.\n");
130 * Allocate a SKB for the received data packet, including radiotap
133 skb = dev_alloc_skb(ind_data_len + sizeof(struct unifi_rx_radiotap_header) + 4);
135 unifi_error(priv, "alloc_skb failed.\n");
136 priv->stats.rx_errors++;
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));
146 /* Copy in the 802.11 frame */
147 ptr = skb_put(skb, ind_data_len);
148 memcpy(ptr, skb_orig->data, ind_data_len);
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);
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)
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));
172 unifi_rt->rt_flags = 0;
174 unifi_rt->rt_rate = ind->Rate;
176 unifi_rt->rt_chan = cpu_to_le16(ieee80211chan2mhz(priv->wext_conf.channel));
177 unifi_rt->rt_chan_flags = 0;
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;
184 unifi_rt->rt_dbm_antsignal = signal;
185 unifi_rt->rt_dbm_antnoise = noise;
187 unifi_rt->rt_antenna = ind->AntennaId;
191 skb->mac_header = skb->data;
192 skb->pkt_type = PACKET_OTHERHOST;
193 skb->protocol = __constant_htons(ETH_P_80211_RAW);
194 memset(skb->cb, 0, sizeof(skb->cb));
196 /* Pass up to Linux network stack */
199 dev->last_rx = jiffies;
201 /* Bump the rx stats */
202 priv->stats.rx_packets++;
203 priv->stats.rx_bytes += ind_data_len;
205 } /* netrx_radiotap() */
206 #endif /* RADIOTAP */
210 * ---------------------------------------------------------------------------
213 * Reformat a UniFi SNIFFDATA signal into a Prism format sniff packet.
216 * priv OS private context pointer.
217 * ind Pointer to a MA_UNITDATA_INDICATION or
218 * DS_UNITDATA_INDICATION indication structure.
221 * Radiotap header values are all little-endian, UniFi signals will have
222 * been converted to host-endian.
223 * ---------------------------------------------------------------------------
225 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_PRISM)
227 netrx_prism(unifi_priv_t *priv,
228 const CSR_MA_SNIFFDATA_INDICATION *ind,
229 struct sk_buff *skb_orig)
231 struct net_device *dev = priv->netdev;
232 struct sk_buff *skb = NULL;
235 int ind_data_len = skb_orig->len - 2 - ETH_HLEN;
236 #define WLANCAP_MAGIC_COOKIE_V1 0x80211001
237 struct avs_header_v1 {
253 int signal, noise, snr;
255 if (ind_data_len <= 0) {
256 unifi_error(priv, "Invalid length in CSR_MA_SNIFFDATA_INDICATION.\n");
261 * Allocate a SKB for the received data packet, including radiotap
264 skb = dev_alloc_skb(ind_data_len + sizeof(struct avs_header_v1) + 4);
266 unifi_error(priv, "alloc_skb failed.\n");
267 priv->stats.rx_errors++;
273 /* Reserve the radiotap header at the front of skb */
274 avs = (struct avs_header_v1 *)skb_put(skb, sizeof(struct avs_header_v1));
276 /* Copy in the 802.11 frame */
277 ptr = skb_put(skb, ind_data_len);
278 memcpy(ptr, skb_orig->data, ind_data_len);
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;
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 */
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));
307 /* Pass up to Linux network stack */
310 dev->last_rx = jiffies;
312 /* Bump the rx stats */
313 priv->stats.rx_packets++;
314 priv->stats.rx_bytes += ind_data_len;
316 } /* netrx_prism() */
321 * ---------------------------------------------------------------------------
324 * Reformat a UniFi SNIFFDATA signal into a network
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
334 * Radiotap header values are all little-endian, UniFi signals will have
335 * been converted to host-endian.
336 * ---------------------------------------------------------------------------
339 ma_sniffdata_ind(void *ospriv,
340 const CSR_MA_SNIFFDATA_INDICATION *ind,
341 const bulk_data_param_t *bulkdata)
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;
347 if (bulkdata->d[0].data_length == 0) {
348 unifi_warning(priv, "rx: MA-SNIFFDATA indication with zero bulk data\n");
352 skb->len = bulkdata->d[0].data_length;
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++;
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");
370 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_PRISM)
371 netrx_prism(priv, ind, skb);
374 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
375 netrx_radiotap(priv, ind, skb);
376 #endif /* RADIOTAP */
380 } /* ma_sniffdata_ind() */
383 #endif /* UNIFI_SNIFF_ARPHRD */