• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/src/linux/linux-2.6/drivers/net/wireless/bcm43xx/
1/*
2
3  Broadcom BCM43xx wireless driver
4
5  Transmission (TX/RX) related functions.
6
7  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
8                     Stefano Brivio <st3@riseup.net>
9                     Michael Buesch <mbuesch@freenet.de>
10                     Danny van Dyk <kugelfang@gentoo.org>
11                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
12
13  This program is free software; you can redistribute it and/or modify
14  it under the terms of the GNU General Public License as published by
15  the Free Software Foundation; either version 2 of the License, or
16  (at your option) any later version.
17
18  This program is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  GNU General Public License for more details.
22
23  You should have received a copy of the GNU General Public License
24  along with this program; see the file COPYING.  If not, write to
25  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
26  Boston, MA 02110-1301, USA.
27
28*/
29
30#include "bcm43xx_xmit.h"
31
32#include <linux/etherdevice.h>
33
34
35/* Extract the bitrate out of a CCK PLCP header. */
36static u8 bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr4 *plcp)
37{
38	switch (plcp->raw[0]) {
39	case 0x0A:
40		return IEEE80211_CCK_RATE_1MB;
41	case 0x14:
42		return IEEE80211_CCK_RATE_2MB;
43	case 0x37:
44		return IEEE80211_CCK_RATE_5MB;
45	case 0x6E:
46		return IEEE80211_CCK_RATE_11MB;
47	}
48	assert(0);
49	return 0;
50}
51
52/* Extract the bitrate out of an OFDM PLCP header. */
53static u8 bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr4 *plcp)
54{
55	switch (plcp->raw[0] & 0xF) {
56	case 0xB:
57		return IEEE80211_OFDM_RATE_6MB;
58	case 0xF:
59		return IEEE80211_OFDM_RATE_9MB;
60	case 0xA:
61		return IEEE80211_OFDM_RATE_12MB;
62	case 0xE:
63		return IEEE80211_OFDM_RATE_18MB;
64	case 0x9:
65		return IEEE80211_OFDM_RATE_24MB;
66	case 0xD:
67		return IEEE80211_OFDM_RATE_36MB;
68	case 0x8:
69		return IEEE80211_OFDM_RATE_48MB;
70	case 0xC:
71		return IEEE80211_OFDM_RATE_54MB;
72	}
73	assert(0);
74	return 0;
75}
76
77u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate)
78{
79	switch (bitrate) {
80	case IEEE80211_CCK_RATE_1MB:
81		return 0x0A;
82	case IEEE80211_CCK_RATE_2MB:
83		return 0x14;
84	case IEEE80211_CCK_RATE_5MB:
85		return 0x37;
86	case IEEE80211_CCK_RATE_11MB:
87		return 0x6E;
88	}
89	assert(0);
90	return 0;
91}
92
93u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate)
94{
95	switch (bitrate) {
96	case IEEE80211_OFDM_RATE_6MB:
97		return 0xB;
98	case IEEE80211_OFDM_RATE_9MB:
99		return 0xF;
100	case IEEE80211_OFDM_RATE_12MB:
101		return 0xA;
102	case IEEE80211_OFDM_RATE_18MB:
103		return 0xE;
104	case IEEE80211_OFDM_RATE_24MB:
105		return 0x9;
106	case IEEE80211_OFDM_RATE_36MB:
107		return 0xD;
108	case IEEE80211_OFDM_RATE_48MB:
109		return 0x8;
110	case IEEE80211_OFDM_RATE_54MB:
111		return 0xC;
112	}
113	assert(0);
114	return 0;
115}
116
117static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
118				      const u16 octets, const u8 bitrate,
119				      const int ofdm_modulation)
120{
121	__le32 *data = &(plcp->data);
122	__u8 *raw = plcp->raw;
123
124	if (ofdm_modulation) {
125		*data = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
126		assert(!(octets & 0xF000));
127		*data |= (octets << 5);
128		*data = cpu_to_le32(*data);
129	} else {
130		u32 plen;
131
132		plen = octets * 16 / bitrate;
133		if ((octets * 16 % bitrate) > 0) {
134			plen++;
135			if ((bitrate == IEEE80211_CCK_RATE_11MB)
136			    && ((octets * 8 % 11) < 4)) {
137				raw[1] = 0x84;
138			} else
139				raw[1] = 0x04;
140		} else
141			raw[1] = 0x04;
142		*data |= cpu_to_le32(plen << 16);
143		raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate);
144	}
145}
146
147static u8 bcm43xx_calc_fallback_rate(u8 bitrate)
148{
149	switch (bitrate) {
150	case IEEE80211_CCK_RATE_1MB:
151		return IEEE80211_CCK_RATE_1MB;
152	case IEEE80211_CCK_RATE_2MB:
153		return IEEE80211_CCK_RATE_1MB;
154	case IEEE80211_CCK_RATE_5MB:
155		return IEEE80211_CCK_RATE_2MB;
156	case IEEE80211_CCK_RATE_11MB:
157		return IEEE80211_CCK_RATE_5MB;
158	case IEEE80211_OFDM_RATE_6MB:
159		return IEEE80211_CCK_RATE_5MB;
160	case IEEE80211_OFDM_RATE_9MB:
161		return IEEE80211_OFDM_RATE_6MB;
162	case IEEE80211_OFDM_RATE_12MB:
163		return IEEE80211_OFDM_RATE_9MB;
164	case IEEE80211_OFDM_RATE_18MB:
165		return IEEE80211_OFDM_RATE_12MB;
166	case IEEE80211_OFDM_RATE_24MB:
167		return IEEE80211_OFDM_RATE_18MB;
168	case IEEE80211_OFDM_RATE_36MB:
169		return IEEE80211_OFDM_RATE_24MB;
170	case IEEE80211_OFDM_RATE_48MB:
171		return IEEE80211_OFDM_RATE_36MB;
172	case IEEE80211_OFDM_RATE_54MB:
173		return IEEE80211_OFDM_RATE_48MB;
174	}
175	assert(0);
176	return 0;
177}
178
179static
180__le16 bcm43xx_calc_duration_id(const struct ieee80211_hdr *wireless_header,
181				u8 bitrate)
182{
183	const u16 frame_ctl = le16_to_cpu(wireless_header->frame_ctl);
184	__le16 duration_id = wireless_header->duration_id;
185
186	switch (WLAN_FC_GET_TYPE(frame_ctl)) {
187	case IEEE80211_FTYPE_DATA:
188	case IEEE80211_FTYPE_MGMT:
189		//TODO: Steal the code from ieee80211, once it is completed there.
190		break;
191	case IEEE80211_FTYPE_CTL:
192		/* Use the original duration/id. */
193		break;
194	default:
195		assert(0);
196	}
197
198	return duration_id;
199}
200
201static inline
202u16 ceiling_div(u16 dividend, u16 divisor)
203{
204	return ((dividend + divisor - 1) / divisor);
205}
206
207static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy,
208				 struct bcm43xx_txhdr *txhdr,
209				 u16 *flags,
210				 u8 bitrate,
211				 const struct ieee80211_hdr_4addr *wlhdr)
212{
213	u16 fctl;
214	u16 dur;
215	u8 fallback_bitrate;
216	int ofdm_modulation;
217	int fallback_ofdm_modulation;
218//	u8 *sa, *da;
219	u16 flen;
220
221	fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
222	ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
223	fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
224
225	flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + IEEE80211_FCS_LEN,
226	bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp),
227				  flen, bitrate,
228				  !ieee80211_is_cck_rate(bitrate));
229	bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp),
230				  flen, fallback_bitrate,
231				  !ieee80211_is_cck_rate(fallback_bitrate));
232	fctl = IEEE80211_FTYPE_CTL;
233	fctl |= IEEE80211_STYPE_RTS;
234	dur = le16_to_cpu(wlhdr->duration_id);
235assert(dur);
236	if (phy->type == BCM43xx_PHYTYPE_A) {
237		/* Three times SIFS */
238		dur += 16 * 3;
239		/* Add ACK duration. */
240		dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
241				   bitrate * 4);
242		/* Add CTS duration. */
243		dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
244				   bitrate * 4);
245	} else {
246		/* Three times SIFS */
247		dur += 10 * 3;
248		/* Add ACK duration. */
249		dur += ceiling_div(8 * (14 /*bytes*/) * 10,
250				   bitrate);
251		/* Add CTS duration. */
252		dur += ceiling_div(8 * (14 /*bytes*/) * 10,
253				   bitrate);
254	}
255
256	txhdr->rts_cts_frame_control = cpu_to_le16(fctl);
257	txhdr->rts_cts_dur = cpu_to_le16(dur);
258//printk(BCM43xx_MACFMT "  " BCM43xx_MACFMT "  " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3));
259//printk(BCM43xx_MACFMT "  " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da));
260	memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);
261//	memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN);
262
263	*flags |= BCM43xx_TXHDRFLAG_RTSCTS;
264	*flags |= BCM43xx_TXHDRFLAG_RTS;
265	if (ofdm_modulation)
266		*flags |= BCM43xx_TXHDRFLAG_RTSCTS_OFDM;
267	if (fallback_ofdm_modulation)
268		*flags |= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM;
269}
270
271void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
272			    struct bcm43xx_txhdr *txhdr,
273			    const unsigned char *fragment_data,
274			    const unsigned int fragment_len,
275			    const int is_first_fragment,
276			    const u16 cookie)
277{
278	const struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
279	const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data;
280	const struct ieee80211_security *secinfo = &bcm->ieee->sec;
281	u8 bitrate;
282	u8 fallback_bitrate;
283	int ofdm_modulation;
284	int fallback_ofdm_modulation;
285	u16 plcp_fragment_len = fragment_len;
286	u16 flags = 0;
287	u16 control = 0;
288	u16 wsec_rate = 0;
289	u16 encrypt_frame;
290	const u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(wireless_header->frame_ctl));
291	const int is_mgt = (ftype == IEEE80211_FTYPE_MGMT);
292
293	/* Now construct the TX header. */
294	memset(txhdr, 0, sizeof(*txhdr));
295
296	bitrate = ieee80211softmac_suggest_txrate(bcm->softmac,
297		is_multicast_ether_addr(wireless_header->addr1), is_mgt);
298	ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
299	fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
300	fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
301
302	/* Set Frame Control from 80211 header. */
303	txhdr->frame_control = wireless_header->frame_ctl;
304	/* Copy address1 from 80211 header. */
305	memcpy(txhdr->mac1, wireless_header->addr1, 6);
306	/* Set the fallback duration ID. */
307	txhdr->fallback_dur_id = bcm43xx_calc_duration_id((const struct ieee80211_hdr *)wireless_header,
308							  fallback_bitrate);
309	/* Set the cookie (used as driver internal ID for the frame) */
310	txhdr->cookie = cpu_to_le16(cookie);
311
312	/* Hardware appends FCS. */
313	plcp_fragment_len += IEEE80211_FCS_LEN;
314
315	/* Hardware encryption. */
316	encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED;
317	if (encrypt_frame && !bcm->ieee->host_encrypt) {
318		const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header;
319		memcpy(txhdr->wep_iv, hdr->payload, 4);
320		/* Hardware appends ICV. */
321		plcp_fragment_len += 4;
322
323		wsec_rate |= (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT)
324			     & BCM43xx_TXHDR_WSEC_ALGO_MASK;
325		wsec_rate |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT)
326			     & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK;
327	}
328
329	/* Generate the PLCP header and the fallback PLCP header. */
330	bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp),
331				  plcp_fragment_len,
332				  bitrate, ofdm_modulation);
333	bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, plcp_fragment_len,
334				  fallback_bitrate, fallback_ofdm_modulation);
335
336	/* Set the CONTROL field */
337	if (ofdm_modulation)
338		control |= BCM43xx_TXHDRCTL_OFDM;
339	if (bcm->short_preamble)
340		control |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE;
341	control |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT)
342		   & BCM43xx_TXHDRCTL_ANTENNADIV_MASK;
343
344	/* Set the FLAGS field */
345	if (!is_multicast_ether_addr(wireless_header->addr1) &&
346	    !is_broadcast_ether_addr(wireless_header->addr1))
347		flags |= BCM43xx_TXHDRFLAG_EXPECTACK;
348	if (1)
349		flags |= 0x10;
350	if (fallback_ofdm_modulation)
351		flags |= BCM43xx_TXHDRFLAG_FALLBACKOFDM;
352	if (is_first_fragment)
353		flags |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT;
354
355	/* Set WSEC/RATE field */
356	wsec_rate |= (txhdr->plcp.raw[0] << BCM43xx_TXHDR_RATE_SHIFT)
357		     & BCM43xx_TXHDR_RATE_MASK;
358
359	/* Generate the RTS/CTS packet, if required. */
360	if (0) {
361		bcm43xx_generate_rts(phy, txhdr, &flags,
362				     0,
363				     wireless_header);
364	}
365
366	txhdr->flags = cpu_to_le16(flags);
367	txhdr->control = cpu_to_le16(control);
368	txhdr->wsec_rate = cpu_to_le16(wsec_rate);
369}
370
371static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm,
372				   u8 in_rssi, int ofdm,
373				   int adjust_2053, int adjust_2050)
374{
375	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
376	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
377	s32 tmp;
378
379	switch (radio->version) {
380	case 0x2050:
381		if (ofdm) {
382			tmp = in_rssi;
383			if (tmp > 127)
384				tmp -= 256;
385			tmp *= 73;
386			tmp /= 64;
387			if (adjust_2050)
388				tmp += 25;
389			else
390				tmp -= 3;
391		} else {
392			if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
393				if (in_rssi > 63)
394					in_rssi = 63;
395				tmp = radio->nrssi_lt[in_rssi];
396				tmp = 31 - tmp;
397				tmp *= -131;
398				tmp /= 128;
399				tmp -= 57;
400			} else {
401				tmp = in_rssi;
402				tmp = 31 - tmp;
403				tmp *= -149;
404				tmp /= 128;
405				tmp -= 68;
406			}
407			if (phy->type == BCM43xx_PHYTYPE_G &&
408			    adjust_2050)
409				tmp += 25;
410		}
411		break;
412	case 0x2060:
413		if (in_rssi > 127)
414			tmp = in_rssi - 256;
415		else
416			tmp = in_rssi;
417		break;
418	default:
419		tmp = in_rssi;
420		tmp -= 11;
421		tmp *= 103;
422		tmp /= 64;
423		if (adjust_2053)
424			tmp -= 109;
425		else
426			tmp -= 83;
427	}
428
429	return (s8)tmp;
430}
431
432//TODO
433
434int bcm43xx_rx(struct bcm43xx_private *bcm,
435	       struct sk_buff *skb,
436	       struct bcm43xx_rxhdr *rxhdr)
437{
438	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
439	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
440	struct bcm43xx_plcp_hdr4 *plcp;
441	struct ieee80211_rx_stats stats;
442	struct ieee80211_hdr_4addr *wlhdr;
443	u16 frame_ctl;
444	int is_packet_for_us = 0;
445	int err = -EINVAL;
446	const u16 rxflags1 = le16_to_cpu(rxhdr->flags1);
447	const u16 rxflags2 = le16_to_cpu(rxhdr->flags2);
448	const u16 rxflags3 = le16_to_cpu(rxhdr->flags3);
449	const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM);
450
451	if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) {
452		plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2);
453		/* Skip two unknown bytes and the PLCP header. */
454		skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6));
455	} else {
456		plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data);
457		/* Skip the PLCP header. */
458		skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6));
459	}
460	/* The SKB contains the PAYLOAD (wireless header + data)
461	 * at this point. The FCS at the end is stripped.
462	 */
463
464	memset(&stats, 0, sizeof(stats));
465	stats.mac_time = le16_to_cpu(rxhdr->mactime);
466	stats.rssi = rxhdr->rssi;
467	stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
468					      !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
469					      !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
470	stats.noise = bcm->stats.noise;
471	if (is_ofdm)
472		stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
473	else
474		stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
475	stats.received_channel = radio->channel;
476	stats.mask = IEEE80211_STATMASK_SIGNAL |
477		     IEEE80211_STATMASK_NOISE |
478		     IEEE80211_STATMASK_RATE |
479		     IEEE80211_STATMASK_RSSI;
480	if (phy->type == BCM43xx_PHYTYPE_A)
481		stats.freq = IEEE80211_52GHZ_BAND;
482	else
483		stats.freq = IEEE80211_24GHZ_BAND;
484	stats.len = skb->len;
485
486	bcm->stats.last_rx = jiffies;
487	if (bcm->ieee->iw_mode == IW_MODE_MONITOR) {
488		err = ieee80211_rx(bcm->ieee, skb, &stats);
489		return (err == 0) ? -EINVAL : 0;
490	}
491
492	wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
493
494	switch (bcm->ieee->iw_mode) {
495	case IW_MODE_ADHOC:
496		if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
497		    memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
498		    is_broadcast_ether_addr(wlhdr->addr1) ||
499		    is_multicast_ether_addr(wlhdr->addr1) ||
500		    bcm->net_dev->flags & IFF_PROMISC)
501			is_packet_for_us = 1;
502		break;
503	case IW_MODE_INFRA:
504	default:
505		/* When receiving multicast or broadcast packets, filter out
506		   the packets we send ourself; we shouldn't see those */
507		if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
508		    memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
509		    (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) &&
510		     (is_broadcast_ether_addr(wlhdr->addr1) ||
511		      is_multicast_ether_addr(wlhdr->addr1) ||
512		      bcm->net_dev->flags & IFF_PROMISC)))
513			is_packet_for_us = 1;
514		break;
515	}
516
517	frame_ctl = le16_to_cpu(wlhdr->frame_ctl);
518	switch (WLAN_FC_GET_TYPE(frame_ctl)) {
519	case IEEE80211_FTYPE_MGMT:
520		ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats);
521		break;
522	case IEEE80211_FTYPE_DATA:
523		if (is_packet_for_us) {
524			err = ieee80211_rx(bcm->ieee, skb, &stats);
525			err = (err == 0) ? -EINVAL : 0;
526		}
527		break;
528	case IEEE80211_FTYPE_CTL:
529		break;
530	default:
531		assert(0);
532		return -EINVAL;
533	}
534
535	return err;
536}
537