Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
monitor.c
Go to the documentation of this file.
1 /*
2  * ---------------------------------------------------------------------------
3  * FILE: monitor.c
4  *
5  * Copyright (C) 2006-2008 by Cambridge Silicon Radio Ltd.
6  *
7  * Refer to LICENSE.txt included with this source code for details on
8  * the license terms.
9  *
10  * ---------------------------------------------------------------------------
11  */
12 
13 #include <linux/version.h>
14 #include "unifi_priv.h"
15 
16 #ifdef UNIFI_SNIFF_ARPHRD
17 
18 
19 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
20 #include <net/ieee80211_radiotap.h>
21 #endif
22 
23 #ifndef ETH_P_80211_RAW
24 #define ETH_P_80211_RAW ETH_P_ALL
25 #endif
26 
27 /*
28  * ---------------------------------------------------------------------------
29  * uf_start_sniff
30  *
31  * Start UniFi capture in SNIFF mode, i.e capture everything it hears.
32  *
33  * Arguments:
34  * priv Pointer to device private context struct
35  *
36  * Returns:
37  * 0 on success or kernel error code
38  * ---------------------------------------------------------------------------
39  */
40 int
41 uf_start_sniff(unifi_priv_t *priv)
42 {
43  ul_client_t *pcli = priv->wext_client;
44  CSR_SIGNAL signal;
45  CSR_MLME_SNIFFJOIN_REQUEST *req = &signal.u.MlmeSniffjoinRequest;
46  int timeout = 1000;
47  int r;
48 
49  req->Ifindex = priv->if_index;
50  req->Channel = priv->wext_conf.channel;
51  req->ChannelStartingFactor = 0;
52 
53  signal.SignalPrimitiveHeader.SignalId = CSR_MLME_SNIFFJOIN_REQUEST_ID;
54 
55  r = unifi_mlme_blocking_request(priv, pcli, &signal, NULL, timeout);
56  if (r < 0) {
57  unifi_error(priv, "failed to send SNIFFJOIN request, error %d\n", r);
58  return r;
59  }
60 
61  r = pcli->reply_signal->u.MlmeSniffjoinConfirm.Resultcode;
62  if (r) {
63  unifi_notice(priv, "SNIFFJOIN request was rejected with result 0x%X (%s)\n",
64  r, lookup_result_code(r));
65  return -EIO;
66  }
67 
68  return 0;
69 } /* uf_start_sniff() */
70 
71 
72 
73 /*
74  * ---------------------------------------------------------------------------
75  * netrx_radiotap
76  *
77  * Reformat a UniFi SNIFFDATA signal into a radiotap packet.
78  *
79  * Arguments:
80  * priv OS private context pointer.
81  * ind Pointer to a MA_UNITDATA_INDICATION or
82  * DS_UNITDATA_INDICATION indication structure.
83  *
84  * Notes:
85  * Radiotap header values are all little-endian, UniFi signals will have
86  * been converted to host-endian.
87  * ---------------------------------------------------------------------------
88  */
89 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
90 static void
91 netrx_radiotap(unifi_priv_t *priv,
92  const CSR_MA_SNIFFDATA_INDICATION *ind,
93  struct sk_buff *skb_orig)
94 {
95  struct net_device *dev = priv->netdev;
96  struct sk_buff *skb = NULL;
97  unsigned char *ptr;
98  unsigned char *base;
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 */
103  u64 rt_tsft;
104  /* IEEE80211_RADIOTAP_FLAGS */
105  u8 rt_flags;
106  /* IEEE80211_RADIOTAP_RATE */
107  u8 rt_rate;
108  /* IEEE80211_RADIOTAP_CHANNEL */
109  u16 rt_chan;
110  u16 rt_chan_flags;
111  /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
112  u8 rt_dbm_antsignal;
113  /* IEEE80211_RADIOTAP_DBM_ANTNOISE */
114  u8 rt_dbm_antnoise;
115  /* IEEE80211_RADIOTAP_ANTENNA */
116  u8 rt_antenna;
117 
118  /* pad to 4-byte boundary */
119  u8 pad[3];
120  } __attribute__((__packed__));
121 
122  struct unifi_rx_radiotap_header *unifi_rt;
123  int signal, noise, snr;
124 
125  func_enter();
126 
127  if (ind_data_len <= 0) {
128  unifi_error(priv, "Invalid length in CSR_MA_SNIFFDATA_INDICATION.\n");
129  return;
130  }
131 
132  /*
133  * Allocate a SKB for the received data packet, including radiotap
134  * header.
135  */
136  skb = dev_alloc_skb(ind_data_len + sizeof(struct unifi_rx_radiotap_header) + 4);
137  if (! skb) {
138  unifi_error(priv, "alloc_skb failed.\n");
139  priv->stats.rx_errors++;
140  return;
141  }
142 
143  base = skb->data;
144 
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));
148 
149  /* Copy in the 802.11 frame */
150  ptr = skb_put(skb, ind_data_len);
151  memcpy(ptr, skb_orig->data, ind_data_len);
152 
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);
156 
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)
166  ;
167 
168 
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));
174 
175  unifi_rt->rt_flags = 0;
176 
177  unifi_rt->rt_rate = ind->Rate;
178 
179  unifi_rt->rt_chan = cpu_to_le16(ieee80211chan2mhz(priv->wext_conf.channel));
180  unifi_rt->rt_chan_flags = 0;
181 
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;
186 
187  unifi_rt->rt_dbm_antsignal = signal;
188  unifi_rt->rt_dbm_antnoise = noise;
189 
190  unifi_rt->rt_antenna = ind->AntennaId;
191 
192 
193  skb->dev = dev;
194  skb->mac_header = skb->data;
195  skb->pkt_type = PACKET_OTHERHOST;
197  memset(skb->cb, 0, sizeof(skb->cb));
198 
199  /* Pass up to Linux network stack */
200  netif_rx_ni(skb);
201 
202  dev->last_rx = jiffies;
203 
204  /* Bump the rx stats */
205  priv->stats.rx_packets++;
206  priv->stats.rx_bytes += ind_data_len;
207 
208  func_exit();
209 } /* netrx_radiotap() */
210 #endif /* RADIOTAP */
211 
212 
213 /*
214  * ---------------------------------------------------------------------------
215  * netrx_prism
216  *
217  * Reformat a UniFi SNIFFDATA signal into a Prism format sniff packet.
218  *
219  * Arguments:
220  * priv OS private context pointer.
221  * ind Pointer to a MA_UNITDATA_INDICATION or
222  * DS_UNITDATA_INDICATION indication structure.
223  *
224  * Notes:
225  * Radiotap header values are all little-endian, UniFi signals will have
226  * been converted to host-endian.
227  * ---------------------------------------------------------------------------
228  */
229 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_PRISM)
230 static void
231 netrx_prism(unifi_priv_t *priv,
232  const CSR_MA_SNIFFDATA_INDICATION *ind,
233  struct sk_buff *skb_orig)
234 {
235  struct net_device *dev = priv->netdev;
236  struct sk_buff *skb = NULL;
237  unsigned char *ptr;
238  unsigned char *base;
239  int ind_data_len = skb_orig->len - 2 - ETH_HLEN;
240 #define WLANCAP_MAGIC_COOKIE_V1 0x80211001
241  struct avs_header_v1 {
242  uint32 version;
243  uint32 length;
244  uint64 mactime;
245  uint64 hosttime;
246  uint32 phytype;
247  uint32 channel;
248  uint32 datarate;
249  uint32 antenna;
251  uint32 ssi_type;
252  int32 ssi_signal;
253  int32 ssi_noise;
254  uint32 preamble;
255  uint32 encoding;
256  } *avs;
257  int signal, noise, snr;
258 
259  func_enter();
260 
261  if (ind_data_len <= 0) {
262  unifi_error(priv, "Invalid length in CSR_MA_SNIFFDATA_INDICATION.\n");
263  return;
264  }
265 
266  /*
267  * Allocate a SKB for the received data packet, including radiotap
268  * header.
269  */
270  skb = dev_alloc_skb(ind_data_len + sizeof(struct avs_header_v1) + 4);
271  if (! skb) {
272  unifi_error(priv, "alloc_skb failed.\n");
273  priv->stats.rx_errors++;
274  return;
275  }
276 
277  base = skb->data;
278 
279  /* Reserve the radiotap header at the front of skb */
280  avs = (struct avs_header_v1 *)skb_put(skb, sizeof(struct avs_header_v1));
281 
282  /* Copy in the 802.11 frame */
283  ptr = skb_put(skb, ind_data_len);
284  memcpy(ptr, skb_orig->data, ind_data_len);
285 
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;
290 
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 */
305 
306 
307  skb->dev = dev;
308  skb->mac.raw = skb->data;
309  skb->pkt_type = PACKET_OTHERHOST;
311  memset(skb->cb, 0, sizeof(skb->cb));
312 
313  /* Pass up to Linux network stack */
314  netif_rx_ni(skb);
315 
316  dev->last_rx = jiffies;
317 
318  /* Bump the rx stats */
319  priv->stats.rx_packets++;
320  priv->stats.rx_bytes += ind_data_len;
321 
322  func_exit();
323 } /* netrx_prism() */
324 #endif /* PRISM */
325 
326 
327 /*
328  * ---------------------------------------------------------------------------
329  * ma_sniffdata_ind
330  *
331  * Reformat a UniFi SNIFFDATA signal into a network
332  *
333  * Arguments:
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
338  * the data received.
339  *
340  * Notes:
341  * Radiotap header values are all little-endian, UniFi signals will have
342  * been converted to host-endian.
343  * ---------------------------------------------------------------------------
344  */
345 void
346 ma_sniffdata_ind(void *ospriv,
347  const CSR_MA_SNIFFDATA_INDICATION *ind,
348  const bulk_data_param_t *bulkdata)
349 {
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;
353 
354  func_enter();
355 
356  if (bulkdata->d[0].data_length == 0) {
357  unifi_warning(priv, "rx: MA-SNIFFDATA indication with zero bulk data\n");
358  func_exit();
359  return;
360  }
361 
362  skb->len = bulkdata->d[0].data_length;
363 
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++;
368  dev_kfree_skb(skb);
369  return;
370  }
371 
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");
376  dev_kfree_skb(skb);
377  return;
378  }
379 
380 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_PRISM)
381  netrx_prism(priv, ind, skb);
382 #endif /* PRISM */
383 
384 #if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
385  netrx_radiotap(priv, ind, skb);
386 #endif /* RADIOTAP */
387 
388  dev_kfree_skb(skb);
389 
390 } /* ma_sniffdata_ind() */
391 
392 
393 #endif /* UNIFI_SNIFF_ARPHRD */
394