aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas/rx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/libertas/rx.c')
-rw-r--r--drivers/net/wireless/libertas/rx.c459
1 files changed, 459 insertions, 0 deletions
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
new file mode 100644
index 000000000000..7e3f78f092dc
--- /dev/null
+++ b/drivers/net/wireless/libertas/rx.c
@@ -0,0 +1,459 @@
1/**
2 * This file contains the handling of RX in wlan driver.
3 */
4#include <linux/etherdevice.h>
5#include <linux/types.h>
6
7#include "hostcmd.h"
8#include "radiotap.h"
9#include "decl.h"
10#include "dev.h"
11#include "wext.h"
12
13struct eth803hdr {
14 u8 dest_addr[6];
15 u8 src_addr[6];
16 u16 h803_len;
17} __attribute__ ((packed));
18
19struct rfc1042hdr {
20 u8 llc_dsap;
21 u8 llc_ssap;
22 u8 llc_ctrl;
23 u8 snap_oui[3];
24 u16 snap_type;
25} __attribute__ ((packed));
26
27struct rxpackethdr {
28 struct rxpd rx_pd;
29 struct eth803hdr eth803_hdr;
30 struct rfc1042hdr rfc1042_hdr;
31} __attribute__ ((packed));
32
33struct rx80211packethdr {
34 struct rxpd rx_pd;
35 void *eth80211_hdr;
36} __attribute__ ((packed));
37
38static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb);
39
40/**
41 * @brief This function computes the avgSNR .
42 *
43 * @param priv A pointer to wlan_private structure
44 * @return avgSNR
45 */
46static u8 wlan_getavgsnr(wlan_private * priv)
47{
48 u8 i;
49 u16 temp = 0;
50 wlan_adapter *adapter = priv->adapter;
51 if (adapter->numSNRNF == 0)
52 return 0;
53 for (i = 0; i < adapter->numSNRNF; i++)
54 temp += adapter->rawSNR[i];
55 return (u8) (temp / adapter->numSNRNF);
56
57}
58
59/**
60 * @brief This function computes the AvgNF
61 *
62 * @param priv A pointer to wlan_private structure
63 * @return AvgNF
64 */
65static u8 wlan_getavgnf(wlan_private * priv)
66{
67 u8 i;
68 u16 temp = 0;
69 wlan_adapter *adapter = priv->adapter;
70 if (adapter->numSNRNF == 0)
71 return 0;
72 for (i = 0; i < adapter->numSNRNF; i++)
73 temp += adapter->rawNF[i];
74 return (u8) (temp / adapter->numSNRNF);
75
76}
77
78/**
79 * @brief This function save the raw SNR/NF to our internel buffer
80 *
81 * @param priv A pointer to wlan_private structure
82 * @param prxpd A pointer to rxpd structure of received packet
83 * @return n/a
84 */
85static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd)
86{
87 wlan_adapter *adapter = priv->adapter;
88 if (adapter->numSNRNF < adapter->data_avg_factor)
89 adapter->numSNRNF++;
90 adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr;
91 adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf;
92 adapter->nextSNRNF++;
93 if (adapter->nextSNRNF >= adapter->data_avg_factor)
94 adapter->nextSNRNF = 0;
95 return;
96}
97
98/**
99 * @brief This function computes the RSSI in received packet.
100 *
101 * @param priv A pointer to wlan_private structure
102 * @param prxpd A pointer to rxpd structure of received packet
103 * @return n/a
104 */
105static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd)
106{
107 wlan_adapter *adapter = priv->adapter;
108
109 ENTER();
110
111 lbs_pr_debug(1, "rxpd: SNR = %d, NF = %d\n", p_rx_pd->snr, p_rx_pd->nf);
112 lbs_pr_debug(1, "Before computing SNR: SNR- avg = %d, NF-avg = %d\n",
113 adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
114 adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
115
116 adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
117 adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
118 wlan_save_rawSNRNF(priv, p_rx_pd);
119
120 adapter->rxpd_rate = p_rx_pd->rx_rate;
121
122 adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE;
123 adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE;
124 lbs_pr_debug(1, "After computing SNR: SNR-avg = %d, NF-avg = %d\n",
125 adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
126 adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
127
128 adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] =
129 CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
130 adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
131
132 adapter->RSSI[TYPE_RXPD][TYPE_AVG] =
133 CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
134 adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
135
136 LEAVE();
137}
138
139int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb)
140{
141 lbs_pr_debug(1, "skb->data=%p\n", skb->data);
142
143 if(IS_MESH_FRAME(skb))
144 skb->dev = priv->mesh_dev;
145 else
146 skb->dev = priv->wlan_dev.netdev;
147 skb->protocol = eth_type_trans(skb, priv->wlan_dev.netdev);
148 skb->ip_summed = CHECKSUM_UNNECESSARY;
149
150 netif_rx(skb);
151
152 return 0;
153}
154
155/**
156 * @brief This function processes received packet and forwards it
157 * to kernel/upper layer
158 *
159 * @param priv A pointer to wlan_private
160 * @param skb A pointer to skb which includes the received packet
161 * @return 0 or -1
162 */
163int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
164{
165 wlan_adapter *adapter = priv->adapter;
166 int ret = 0;
167
168 struct rxpackethdr *p_rx_pkt;
169 struct rxpd *p_rx_pd;
170
171 int hdrchop;
172 struct ethhdr *p_ethhdr;
173
174 const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
175
176 ENTER();
177
178 if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH)
179 lbs_dbg_hex("RX packet: ", skb->data,
180 min_t(unsigned int, skb->len, 100));
181
182 if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
183 return process_rxed_802_11_packet(priv, skb);
184
185 p_rx_pkt = (struct rxpackethdr *) skb->data;
186 p_rx_pd = &p_rx_pkt->rx_pd;
187 if (p_rx_pd->rx_control & RxPD_MESH_FRAME)
188 SET_MESH_FRAME(skb);
189 else
190 UNSET_MESH_FRAME(skb);
191
192 lbs_dbg_hex("RX Data: Before chop rxpd", skb->data,
193 min_t(unsigned int, skb->len, 100));
194
195 if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
196 lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n");
197 priv->stats.rx_length_errors++;
198 ret = 0;
199 goto done;
200 }
201
202 /*
203 * Check rxpd status and update 802.3 stat,
204 */
205 if (!(p_rx_pd->status & MRVDRV_RXPD_STATUS_OK)) {
206 lbs_pr_debug(1, "RX error: frame received with bad status\n");
207 lbs_pr_alert("rxpd Not OK\n");
208 priv->stats.rx_errors++;
209 ret = 0;
210 goto done;
211 }
212
213 lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n",
214 skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
215
216 lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
217 sizeof(p_rx_pkt->eth803_hdr.dest_addr));
218 lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
219 sizeof(p_rx_pkt->eth803_hdr.src_addr));
220
221 if (memcmp(&p_rx_pkt->rfc1042_hdr,
222 rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
223 /*
224 * Replace the 803 header and rfc1042 header (llc/snap) with an
225 * EthernetII header, keep the src/dst and snap_type (ethertype)
226 *
227 * The firmware only passes up SNAP frames converting
228 * all RX Data from 802.11 to 802.2/LLC/SNAP frames.
229 *
230 * To create the Ethernet II, just move the src, dst address right
231 * before the snap_type.
232 */
233 p_ethhdr = (struct ethhdr *)
234 ((u8 *) & p_rx_pkt->eth803_hdr
235 + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr)
236 - sizeof(p_rx_pkt->eth803_hdr.dest_addr)
237 - sizeof(p_rx_pkt->eth803_hdr.src_addr)
238 - sizeof(p_rx_pkt->rfc1042_hdr.snap_type));
239
240 memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr,
241 sizeof(p_ethhdr->h_source));
242 memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr,
243 sizeof(p_ethhdr->h_dest));
244
245 /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header
246 * that was removed
247 */
248 hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt;
249 } else {
250 lbs_dbg_hex("RX Data: LLC/SNAP",
251 (u8 *) & p_rx_pkt->rfc1042_hdr,
252 sizeof(p_rx_pkt->rfc1042_hdr));
253
254 /* Chop off the rxpd */
255 hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt;
256 }
257
258 /* Chop off the leading header bytes so the skb points to the start of
259 * either the reconstructed EthII frame or the 802.2/llc/snap frame
260 */
261 skb_pull(skb, hdrchop);
262
263 /* Take the data rate from the rxpd structure
264 * only if the rate is auto
265 */
266 if (adapter->is_datarate_auto)
267 adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate);
268
269 wlan_compute_rssi(priv, p_rx_pd);
270
271 lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len);
272 if (libertas_upload_rx_packet(priv, skb)) {
273 lbs_pr_debug(1, "RX error: libertas_upload_rx_packet"
274 " returns failure\n");
275 ret = -1;
276 goto done;
277 }
278 priv->stats.rx_bytes += skb->len;
279 priv->stats.rx_packets++;
280
281 ret = 0;
282done:
283 LEAVE();
284
285 return ret;
286}
287
288/**
289 * @brief This function converts Tx/Rx rates from the Marvell WLAN format
290 * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
291 *
292 * @param rate Input rate
293 * @return Output Rate (0 if invalid)
294 */
295static u8 convert_mv_rate_to_radiotap(u8 rate)
296{
297 switch (rate) {
298 case 0: /* 1 Mbps */
299 return 2;
300 case 1: /* 2 Mbps */
301 return 4;
302 case 2: /* 5.5 Mbps */
303 return 11;
304 case 3: /* 11 Mbps */
305 return 22;
306 case 4: /* 6 Mbps */
307 return 12;
308 case 5: /* 9 Mbps */
309 return 18;
310 case 6: /* 12 Mbps */
311 return 24;
312 case 7: /* 18 Mbps */
313 return 36;
314 case 8: /* 24 Mbps */
315 return 48;
316 case 9: /* 36 Mbps */
317 return 72;
318 case 10: /* 48 Mbps */
319 return 96;
320 case 11: /* 54 Mbps */
321 return 108;
322 }
323 lbs_pr_alert( "Invalid Marvell WLAN rate (%i)\n", rate);
324 return 0;
325}
326
327/**
328 * @brief This function processes a received 802.11 packet and forwards it
329 * to kernel/upper layer
330 *
331 * @param priv A pointer to wlan_private
332 * @param skb A pointer to skb which includes the received packet
333 * @return 0 or -1
334 */
335static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
336{
337 wlan_adapter *adapter = priv->adapter;
338 int ret = 0;
339
340 struct rx80211packethdr *p_rx_pkt;
341 struct rxpd *prxpd;
342 struct rx_radiotap_hdr radiotap_hdr;
343 struct rx_radiotap_hdr *pradiotap_hdr;
344
345 ENTER();
346
347 p_rx_pkt = (struct rx80211packethdr *) skb->data;
348 prxpd = &p_rx_pkt->rx_pd;
349
350 // lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
351
352 if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
353 lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n");
354 priv->stats.rx_length_errors++;
355 ret = 0;
356 goto done;
357 }
358
359 /*
360 * Check rxpd status and update 802.3 stat,
361 */
362 if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK)) {
363 //lbs_pr_debug(1, "RX error: frame received with bad status\n");
364 priv->stats.rx_errors++;
365 }
366
367 lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n",
368 skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
369
370 /* create the exported radio header */
371 switch (priv->adapter->radiomode) {
372 case WLAN_RADIOMODE_NONE:
373 /* no radio header */
374 /* chop the rxpd */
375 skb_pull(skb, sizeof(struct rxpd));
376 break;
377
378 case WLAN_RADIOMODE_RADIOTAP:
379 /* radiotap header */
380 radiotap_hdr.hdr.it_version = 0;
381 /* XXX must check this value for pad */
382 radiotap_hdr.hdr.it_pad = 0;
383 radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr);
384 radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT;
385 /* unknown values */
386 radiotap_hdr.flags = 0;
387 radiotap_hdr.chan_freq = 0;
388 radiotap_hdr.chan_flags = 0;
389 radiotap_hdr.antenna = 0;
390 /* known values */
391 radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
392 /* XXX must check no carryout */
393 radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
394 radiotap_hdr.rx_flags = 0;
395 if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK))
396 radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
397 //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
398
399 // lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100));
400
401 /* chop the rxpd */
402 skb_pull(skb, sizeof(struct rxpd));
403
404 /* add space for the new radio header */
405 if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
406 pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0,
407 GFP_ATOMIC)) {
408 lbs_pr_alert( "%s: couldn't pskb_expand_head\n",
409 __func__);
410 }
411
412 pradiotap_hdr =
413 (struct rx_radiotap_hdr *)skb_push(skb,
414 sizeof(struct
415 rx_radiotap_hdr));
416 memcpy(pradiotap_hdr, &radiotap_hdr,
417 sizeof(struct rx_radiotap_hdr));
418 //lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100));
419 break;
420
421 default:
422 /* unknown header */
423 lbs_pr_alert( "Unknown radiomode (%i)\n",
424 priv->adapter->radiomode);
425 /* don't export any header */
426 /* chop the rxpd */
427 skb_pull(skb, sizeof(struct rxpd));
428 break;
429 }
430
431 /* Take the data rate from the rxpd structure
432 * only if the rate is auto
433 */
434 if (adapter->is_datarate_auto) {
435 adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate);
436 }
437
438 wlan_compute_rssi(priv, prxpd);
439
440 lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len);
441
442 if (libertas_upload_rx_packet(priv, skb)) {
443 lbs_pr_debug(1, "RX error: libertas_upload_rx_packet "
444 "returns failure\n");
445 ret = -1;
446 goto done;
447 }
448
449 priv->stats.rx_bytes += skb->len;
450 priv->stats.rx_packets++;
451
452 ret = 0;
453done:
454 LEAVE();
455
456 skb->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */
457
458 return (ret);
459}