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 */