static void e100_get_defaults(struct nic *nic)
{
- struct param_range rfds = { .min = 16, .max = 256, .count = 256 };
- struct param_range cbs = { .min = 64, .max = 256, .count = 128 };
+ struct param_range rfds = { .min = 16, .max = 256, .count = 64 };
+ struct param_range cbs = { .min = 64, .max = 256, .count = 64 };
pci_read_config_byte(nic->pdev, PCI_REVISION_ID, &nic->rev_id);
/* MAC type is encoded as rev ID; exception: ICH is treated as 82559 */
c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
}
- /********************************************************/
- /* Micro code for 8086:1229 Rev 8 */
- /********************************************************/
-
- /* Parameter values for the D101M B-step */
- #define D101M_CPUSAVER_TIMER_DWORD 78
- #define D101M_CPUSAVER_BUNDLE_DWORD 65
- #define D101M_CPUSAVER_MIN_SIZE_DWORD 126
-
- #define D101M_B_RCVBUNDLE_UCODE \
- {\
- 0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \
- 0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \
- 0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \
- 0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \
- 0x00380438, 0x00000000, 0x00140000, 0x00380555, \
- 0x00308000, 0x00100662, 0x00100561, 0x000E0408, \
- 0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
- 0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
- 0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \
- 0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \
- 0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \
- 0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \
- 0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \
- 0x00041000, 0x00010004, 0x00130826, 0x000C0006, \
- 0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
- 0x00101210, 0x00380C34, 0x00000000, 0x00000000, \
- 0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \
- 0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \
- 0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \
- 0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \
- 0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \
- 0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \
- 0x00130826, 0x000C0001, 0x00220559, 0x00101313, \
- 0x00380559, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00130831, 0x0010090B, 0x00124813, \
- 0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \
- 0x003806A8, 0x00000000, 0x00000000, 0x00000000, \
- }
-
- /********************************************************/
- /* Micro code for 8086:1229 Rev 9 */
- /********************************************************/
-
- /* Parameter values for the D101S */
- #define D101S_CPUSAVER_TIMER_DWORD 78
- #define D101S_CPUSAVER_BUNDLE_DWORD 67
- #define D101S_CPUSAVER_MIN_SIZE_DWORD 128
-
- #define D101S_RCVBUNDLE_UCODE \
- {\
- 0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \
- 0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \
- 0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \
- 0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \
- 0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \
- 0x00308000, 0x00100610, 0x00100561, 0x000E0408, \
- 0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
- 0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
- 0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \
- 0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \
- 0x003A047E, 0x00044010, 0x00380819, 0x00000000, \
- 0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \
- 0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \
- 0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \
- 0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \
- 0x00101313, 0x00380700, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
- 0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \
- 0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \
- 0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \
- 0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \
- 0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \
- 0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \
- 0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \
- 0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \
- 0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00130831, \
- 0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \
- 0x00041000, 0x00010004, 0x00380700 \
- }
-
- /********************************************************/
- /* Micro code for the 8086:1229 Rev F/10 */
- /********************************************************/
-
- /* Parameter values for the D102 E-step */
- #define D102_E_CPUSAVER_TIMER_DWORD 42
- #define D102_E_CPUSAVER_BUNDLE_DWORD 54
- #define D102_E_CPUSAVER_MIN_SIZE_DWORD 46
-
- #define D102_E_RCVBUNDLE_UCODE \
- {\
- 0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x0EF70E36, 0x1FFF1FFF, \
- 0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \
- 0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \
- 0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \
- 0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \
- 0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \
- 0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \
- 0x00300006, 0x00E014FB, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000, \
- 0x00906EFD, 0x00900EFD, 0x00E00EF8, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
- }
-
static void e100_load_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb)
{
- /* *INDENT-OFF* */
- static struct {
- u32 ucode[UCODE_SIZE + 1];
- u8 mac;
- u8 timer_dword;
- u8 bundle_dword;
- u8 min_size_dword;
- } ucode_opts[] = {
- { D101M_B_RCVBUNDLE_UCODE,
- mac_82559_D101M,
- D101M_CPUSAVER_TIMER_DWORD,
- D101M_CPUSAVER_BUNDLE_DWORD,
- D101M_CPUSAVER_MIN_SIZE_DWORD },
- { D101S_RCVBUNDLE_UCODE,
- mac_82559_D101S,
- D101S_CPUSAVER_TIMER_DWORD,
- D101S_CPUSAVER_BUNDLE_DWORD,
- D101S_CPUSAVER_MIN_SIZE_DWORD },
- { D102_E_RCVBUNDLE_UCODE,
- mac_82551_F,
- D102_E_CPUSAVER_TIMER_DWORD,
- D102_E_CPUSAVER_BUNDLE_DWORD,
- D102_E_CPUSAVER_MIN_SIZE_DWORD },
- { D102_E_RCVBUNDLE_UCODE,
- mac_82551_10,
- D102_E_CPUSAVER_TIMER_DWORD,
- D102_E_CPUSAVER_BUNDLE_DWORD,
- D102_E_CPUSAVER_MIN_SIZE_DWORD },
- { {0}, 0, 0, 0, 0}
- }, *opts;
- /* *INDENT-ON* */
-
- #define BUNDLESMALL 1
- #define BUNDLEMAX 50
- #define INTDELAY 15000
-
- opts = ucode_opts;
-
- /* do not load u-code for ICH devices */
- if (nic->flags & ich)
- return;
-
- /* Search for ucode match against h/w rev_id */
- while (opts->mac) {
- if (nic->mac == opts->mac) {
- int i;
- u32 *ucode = opts->ucode;
-
- /* Insert user-tunable settings */
- ucode[opts->timer_dword] &= 0xFFFF0000;
- ucode[opts->timer_dword] |=
- (u16) INTDELAY;
- ucode[opts->bundle_dword] &= 0xFFFF0000;
- ucode[opts->bundle_dword] |= (u16) BUNDLEMAX;
- ucode[opts->min_size_dword] &= 0xFFFF0000;
- ucode[opts->min_size_dword] |=
- (BUNDLESMALL) ? 0xFFFF : 0xFF80;
-
- for(i = 0; i < UCODE_SIZE; i++)
- cb->u.ucode[i] = cpu_to_le32(ucode[i]);
- cb->command = cpu_to_le16(cb_ucode);
- return;
- }
- opts++;
- }
-
- cb->command = cpu_to_le16(cb_nop);
+ int i;
+ static const u32 ucode[UCODE_SIZE] = {
+ /* NFS packets are misinterpreted as TCO packets and
+ * incorrectly routed to the BMC over SMBus. This
+ * microcode patch checks the fragmented IP bit in the
+ * NFS/UDP header to distinguish between NFS and TCO. */
+ 0x0EF70E36, 0x1FFF1FFF, 0x1FFF1FFF, 0x1FFF1FFF, 0x1FFF1FFF,
+ 0x1FFF1FFF, 0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000,
+ 0x00906EFD, 0x00900EFD, 0x00E00EF8,
+ };
+
+ if(nic->mac == mac_82551_F || nic->mac == mac_82551_10) {
+ for(i = 0; i < UCODE_SIZE; i++)
+ cb->u.ucode[i] = cpu_to_le32(ucode[i]);
+ cb->command = cpu_to_le16(cb_ucode);
+ } else
+ cb->command = cpu_to_le16(cb_nop);
}
static void e100_setup_iaaddr(struct nic *nic, struct cb *cb,
.phys_id = e100_phys_id,
.get_stats_count = e100_get_stats_count,
.get_ethtool_stats = e100_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
e100_phy_init(nic);
memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
- if(!is_valid_ether_addr(netdev->dev_addr)) {
+ memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN);
+ if(!is_valid_ether_addr(netdev->perm_addr)) {
DPRINTK(PROBE, ERR, "Invalid MAC address from "
"EEPROM, aborting.\n");
err = -EAGAIN;
/******************************************************************************
- Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
+ Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
This program is free software; you can redistribute it and/or modify it
under the terms of version 2 of the GNU General Public License as
static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
-static inline int ieee80211_put_snap(u8 * data, u16 h_proto)
+static inline int ieee80211_copy_snap(u8 * data, u16 h_proto)
{
struct ieee80211_snap_hdr *snap;
u8 *oui;
struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
int res;
-#ifdef CONFIG_IEEE80211_CRYPT_TKIP
- struct ieee80211_hdr *header;
-
- if (ieee->tkip_countermeasures &&
- crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) {
- header = (struct ieee80211_hdr *)frag->data;
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "TX packet to " MAC_FMT "\n",
- ieee->dev->name, MAC_ARG(header->addr1));
- }
- return -1;
- }
-#endif
/* To encrypt, frame format is:
* IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
-
- // PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption.
- /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
- * call both MSDU and MPDU encryption functions from here. */
atomic_inc(&crypt->refcnt);
res = 0;
- if (crypt->ops->encrypt_msdu)
- res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv);
- if (res == 0 && crypt->ops->encrypt_mpdu)
+ if (crypt->ops->encrypt_mpdu)
res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv);
atomic_dec(&crypt->refcnt);
}
static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size,
- unsigned int __nocast gfp_mask)
+ gfp_t gfp_mask)
{
struct ieee80211_txb *txb;
int i;
return txb;
}
-/* SKBs are added to the ieee->tx_queue. */
+/* Incoming skb is converted to a txb which consists of
+ * a block of 802.11 fragment packets (stored as skbs) */
int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ieee80211_device *ieee = netdev_priv(dev);
struct ieee80211_txb *txb = NULL;
- struct ieee80211_hdr *frag_hdr;
- int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size;
+ struct ieee80211_hdr_3addr *frag_hdr;
+ int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
+ rts_required;
unsigned long flags;
struct net_device_stats *stats = &ieee->stats;
- int ether_type, encrypt;
+ int ether_type, encrypt, host_encrypt, host_encrypt_msdu, host_build_iv;
int bytes, fc, hdr_len;
struct sk_buff *skb_frag;
- struct ieee80211_hdr header = { /* Ensure zero initialized */
+ struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */
.duration_id = 0,
.seq_ctl = 0
};
u8 dest[ETH_ALEN], src[ETH_ALEN];
-
struct ieee80211_crypt_data *crypt;
+ int priority = skb->priority;
+ int snapped = 0;
+
+ if (ieee->is_queue_full && (*ieee->is_queue_full) (dev, priority))
+ return NETDEV_TX_BUSY;
spin_lock_irqsave(&ieee->lock, flags);
crypt = ieee->crypt[ieee->tx_keyidx];
encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) &&
- ieee->host_encrypt && crypt && crypt->ops;
+ ieee->sec.encrypt;
+
+ host_encrypt = ieee->host_encrypt && encrypt;
+ host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt;
+ host_build_iv = ieee->host_build_iv && encrypt;
if (!encrypt && ieee->ieee802_1x &&
ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
}
/* Save source and destination addresses */
- memcpy(&dest, skb->data, ETH_ALEN);
- memcpy(&src, skb->data + ETH_ALEN, ETH_ALEN);
+ memcpy(dest, skb->data, ETH_ALEN);
+ memcpy(src, skb->data + ETH_ALEN, ETH_ALEN);
/* Advance the SKB to the start of the payload */
skb_pull(skb, sizeof(struct ethhdr));
/* Determine total amount of storage required for TXB packets */
bytes = skb->len + SNAP_SIZE + sizeof(u16);
- if (encrypt)
+ if (host_encrypt)
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
IEEE80211_FCTL_PROTECTED;
else
if (ieee->iw_mode == IW_MODE_INFRA) {
fc |= IEEE80211_FCTL_TODS;
- /* To DS: Addr1 = BSSID, Addr2 = SA,
- Addr3 = DA */
- memcpy(&header.addr1, ieee->bssid, ETH_ALEN);
- memcpy(&header.addr2, &src, ETH_ALEN);
- memcpy(&header.addr3, &dest, ETH_ALEN);
+ /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
+ memcpy(header.addr1, ieee->bssid, ETH_ALEN);
+ memcpy(header.addr2, src, ETH_ALEN);
+ memcpy(header.addr3, dest, ETH_ALEN);
} else if (ieee->iw_mode == IW_MODE_ADHOC) {
- /* not From/To DS: Addr1 = DA, Addr2 = SA,
- Addr3 = BSSID */
- memcpy(&header.addr1, dest, ETH_ALEN);
- memcpy(&header.addr2, src, ETH_ALEN);
- memcpy(&header.addr3, ieee->bssid, ETH_ALEN);
+ /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
+ memcpy(header.addr1, dest, ETH_ALEN);
+ memcpy(header.addr2, src, ETH_ALEN);
+ memcpy(header.addr3, ieee->bssid, ETH_ALEN);
}
header.frame_ctl = cpu_to_le16(fc);
hdr_len = IEEE80211_3ADDR_LEN;
- /* Determine fragmentation size based on destination (multicast
- * and broadcast are not fragmented) */
- if (is_multicast_ether_addr(dest) || is_broadcast_ether_addr(dest))
- frag_size = MAX_FRAG_THRESHOLD;
- else
- frag_size = ieee->fts;
+ /* Encrypt msdu first on the whole data packet. */
+ if ((host_encrypt || host_encrypt_msdu) &&
+ crypt && crypt->ops && crypt->ops->encrypt_msdu) {
+ int res = 0;
+ int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len +
+ crypt->ops->extra_msdu_postfix_len;
+ struct sk_buff *skb_new = dev_alloc_skb(len);
+
+ if (unlikely(!skb_new))
+ goto failed;
+
+ skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len);
+ memcpy(skb_put(skb_new, hdr_len), &header, hdr_len);
+ snapped = 1;
+ ieee80211_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)),
+ ether_type);
+ memcpy(skb_put(skb_new, skb->len), skb->data, skb->len);
+ res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv);
+ if (res < 0) {
+ IEEE80211_ERROR("msdu encryption failed\n");
+ dev_kfree_skb_any(skb_new);
+ goto failed;
+ }
+ dev_kfree_skb_any(skb);
+ skb = skb_new;
+ bytes += crypt->ops->extra_msdu_prefix_len +
+ crypt->ops->extra_msdu_postfix_len;
+ skb_pull(skb, hdr_len);
+ }
- /* Determine amount of payload per fragment. Regardless of if
- * this stack is providing the full 802.11 header, one will
- * eventually be affixed to this fragment -- so we must account for
- * it when determining the amount of payload space. */
- bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN;
- if (ieee->config &
- (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
- bytes_per_frag -= IEEE80211_FCS_LEN;
-
- /* Each fragment may need to have room for encryptiong pre/postfix */
- if (encrypt)
- bytes_per_frag -= crypt->ops->extra_prefix_len +
- crypt->ops->extra_postfix_len;
-
- /* Number of fragments is the total bytes_per_frag /
- * payload_per_fragment */
- nr_frags = bytes / bytes_per_frag;
- bytes_last_frag = bytes % bytes_per_frag;
- if (bytes_last_frag)
+ if (host_encrypt || ieee->host_open_frag) {
+ /* Determine fragmentation size based on destination (multicast
+ * and broadcast are not fragmented) */
+ if (is_multicast_ether_addr(dest))
+ frag_size = MAX_FRAG_THRESHOLD;
+ else
+ frag_size = ieee->fts;
+
+ /* Determine amount of payload per fragment. Regardless of if
+ * this stack is providing the full 802.11 header, one will
+ * eventually be affixed to this fragment -- so we must account
+ * for it when determining the amount of payload space. */
+ bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN;
+ if (ieee->config &
+ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
+ bytes_per_frag -= IEEE80211_FCS_LEN;
+
+ /* Each fragment may need to have room for encryptiong
+ * pre/postfix */
+ if (host_encrypt)
+ bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
+ crypt->ops->extra_mpdu_postfix_len;
+
+ /* Number of fragments is the total
+ * bytes_per_frag / payload_per_fragment */
+ nr_frags = bytes / bytes_per_frag;
+ bytes_last_frag = bytes % bytes_per_frag;
+ if (bytes_last_frag)
+ nr_frags++;
+ else
+ bytes_last_frag = bytes_per_frag;
+ } else {
+ nr_frags = 1;
+ bytes_per_frag = bytes_last_frag = bytes;
+ frag_size = bytes + IEEE80211_3ADDR_LEN;
+ }
+
+ rts_required = (frag_size > ieee->rts
+ && ieee->config & CFG_IEEE80211_RTS);
+ if (rts_required)
nr_frags++;
- else
- bytes_last_frag = bytes_per_frag;
/* When we allocate the TXB we allocate enough space for the reserve
* and full fragment bytes (bytes_per_frag doesn't include prefix,
goto failed;
}
txb->encrypted = encrypt;
- txb->payload_size = bytes;
+ if (host_encrypt)
+ txb->payload_size = frag_size * (nr_frags - 1) +
+ bytes_last_frag;
+ else
+ txb->payload_size = bytes;
+
+ if (rts_required) {
+ skb_frag = txb->fragments[0];
+ frag_hdr =
+ (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len);
+
+ /*
+ * Set header frame_ctl to the RTS.
+ */
+ header.frame_ctl =
+ cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS);
+ memcpy(frag_hdr, &header, hdr_len);
- for (i = 0; i < nr_frags; i++) {
+ /*
+ * Restore header frame_ctl to the original data setting.
+ */
+ header.frame_ctl = cpu_to_le16(fc);
+
+ if (ieee->config &
+ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
+ skb_put(skb_frag, 4);
+
+ txb->rts_included = 1;
+ i = 1;
+ } else
+ i = 0;
+
+ for (; i < nr_frags; i++) {
skb_frag = txb->fragments[i];
- if (encrypt)
- skb_reserve(skb_frag, crypt->ops->extra_prefix_len);
+ if (host_encrypt || host_build_iv)
+ skb_reserve(skb_frag,
+ crypt->ops->extra_mpdu_prefix_len);
- frag_hdr = (struct ieee80211_hdr *)skb_put(skb_frag, hdr_len);
+ frag_hdr =
+ (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len);
memcpy(frag_hdr, &header, hdr_len);
/* If this is not the last fragment, then add the MOREFRAGS
bytes = bytes_last_frag;
}
- /* Put a SNAP header on the first fragment */
- if (i == 0) {
- ieee80211_put_snap(skb_put
- (skb_frag, SNAP_SIZE + sizeof(u16)),
- ether_type);
+ if (i == 0 && !snapped) {
+ ieee80211_copy_snap(skb_put
+ (skb_frag, SNAP_SIZE + sizeof(u16)),
+ ether_type);
bytes -= SNAP_SIZE + sizeof(u16);
}
/* Encryption routine will move the header forward in order
* to insert the IV between the header and the payload */
- if (encrypt)
+ if (host_encrypt)
ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
+ else if (host_build_iv) {
+ struct ieee80211_crypt_data *crypt;
+
+ crypt = ieee->crypt[ieee->tx_keyidx];
+ atomic_inc(&crypt->refcnt);
+ if (crypt->ops->build_iv)
+ crypt->ops->build_iv(skb_frag, hdr_len,
+ crypt->priv);
+ atomic_dec(&crypt->refcnt);
+ }
+
if (ieee->config &
(CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
skb_put(skb_frag, 4);
dev_kfree_skb_any(skb);
if (txb) {
- if ((*ieee->hard_start_xmit) (txb, dev) == 0) {
+ int ret = (*ieee->hard_start_xmit) (txb, dev, priority);
+ if (ret == 0) {
stats->tx_packets++;
stats->tx_bytes += txb->payload_size;
return 0;
}
+
+ if (ret == NETDEV_TX_BUSY) {
+ printk(KERN_ERR "%s: NETDEV_TX_BUSY returned; "
+ "driver should report queue full via "
+ "ieee_device->is_queue_full.\n",
+ ieee->dev->name);
+ }
+
ieee80211_txb_free(txb);
}
netif_stop_queue(dev);
stats->tx_errors++;
return 1;
+}
+
+/* Incoming 802.11 strucure is converted to a TXB
+ * a block of 802.11 fragment packets (stored as skbs) */
+int ieee80211_tx_frame(struct ieee80211_device *ieee,
+ struct ieee80211_hdr *frame, int len)
+{
+ struct ieee80211_txb *txb = NULL;
+ unsigned long flags;
+ struct net_device_stats *stats = &ieee->stats;
+ struct sk_buff *skb_frag;
+ int priority = -1;
+
+ spin_lock_irqsave(&ieee->lock, flags);
+ /* If there is no driver handler to take the TXB, dont' bother
+ * creating it... */
+ if (!ieee->hard_start_xmit) {
+ printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
+ goto success;
+ }
+
+ if (unlikely(len < 24)) {
+ printk(KERN_WARNING "%s: skb too small (%d).\n",
+ ieee->dev->name, len);
+ goto success;
+ }
+
+ /* When we allocate the TXB we allocate enough space for the reserve
+ * and full fragment bytes (bytes_per_frag doesn't include prefix,
+ * postfix, header, FCS, etc.) */
+ txb = ieee80211_alloc_txb(1, len, GFP_ATOMIC);
+ if (unlikely(!txb)) {
+ printk(KERN_WARNING "%s: Could not allocate TXB\n",
+ ieee->dev->name);
+ goto failed;
+ }
+ txb->encrypted = 0;
+ txb->payload_size = len;
+
+ skb_frag = txb->fragments[0];
+
+ memcpy(skb_put(skb_frag, len), frame, len);
+
+ if (ieee->config &
+ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
+ skb_put(skb_frag, 4);
+
+ success:
+ spin_unlock_irqrestore(&ieee->lock, flags);
+
+ if (txb) {
+ if ((*ieee->hard_start_xmit) (txb, ieee->dev, priority) == 0) {
+ stats->tx_packets++;
+ stats->tx_bytes += txb->payload_size;
+ return 0;
+ }
+ ieee80211_txb_free(txb);
+ }
+ return 0;
+
+ failed:
+ spin_unlock_irqrestore(&ieee->lock, flags);
+ stats->tx_errors++;
+ return 1;
}
+EXPORT_SYMBOL(ieee80211_tx_frame);
EXPORT_SYMBOL(ieee80211_txb_free);