Merge branch 'master'
authorJeff Garzik <jgarzik@pobox.com>
Fri, 14 Oct 2005 01:22:27 +0000 (21:22 -0400)
committerJeff Garzik <jgarzik@pobox.com>
Fri, 14 Oct 2005 01:22:27 +0000 (21:22 -0400)
1  2 
drivers/net/bonding/bond_main.c
drivers/net/e100.c
drivers/net/ns83820.c
net/ieee80211/ieee80211_tx.c

@@@ -1289,12 -1289,13 +1289,13 @@@ static void bond_mc_list_destroy(struc
  /*
   * Copy all the Multicast addresses from src to the bonding device dst
   */
- static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond, int gpf_flag)
+ static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond,
+                            gfp_t gfp_flag)
  {
        struct dev_mc_list *dmi, *new_dmi;
  
        for (dmi = mc_list; dmi; dmi = dmi->next) {
-               new_dmi = kmalloc(sizeof(struct dev_mc_list), gpf_flag);
+               new_dmi = kmalloc(sizeof(struct dev_mc_list), gfp_flag);
  
                if (!new_dmi) {
                        /* FIXME: Potential memory leak !!! */
        return 0;
  }
  
 +static void bond_activebackup_xmit_copy(struct sk_buff *skb,
 +                                         struct bonding *bond,
 +                                         struct slave *slave)
 +{
 +      struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
 +      struct ethhdr *eth_data;
 +      u8 *hwaddr;
 +      int res;
 +
 +      if (!skb2) {
 +              printk(KERN_ERR DRV_NAME ": Error: "
 +                     "bond_activebackup_xmit_copy(): skb_copy() failed\n");
 +              return;
 +      }
 +
 +      skb2->mac.raw = (unsigned char *)skb2->data;
 +      eth_data = eth_hdr(skb2);
 +
 +      /* Pick an appropriate source MAC address */
 +      hwaddr = slave->perm_hwaddr;
 +      if (!memcmp(eth_data->h_source, hwaddr, ETH_ALEN))
 +              hwaddr = bond->curr_active_slave->perm_hwaddr;
 +
 +      /* Set source MAC address appropriately */
 +      memcpy(eth_data->h_source, hwaddr, ETH_ALEN);
 +
 +      res = bond_dev_queue_xmit(bond, skb2, slave->dev);
 +      if (res)
 +              dev_kfree_skb(skb2);
 +
 +      return;
 +}
 +
  /*
   * in active-backup mode, we know that bond->curr_active_slave is always valid if
   * the bond has a usable interface.
@@@ -4289,26 -4257,10 +4290,26 @@@ static int bond_xmit_activebackup(struc
                goto out;
        }
  
 -      if (bond->curr_active_slave) { /* one usable interface */
 -              res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev);
 +      if (!bond->curr_active_slave)
 +              goto out;
 +
 +      /* Xmit IGMP frames on all slaves to ensure rapid fail-over
 +         for multicast traffic on snooping switches */
 +      if (skb->protocol == __constant_htons(ETH_P_IP) &&
 +          skb->nh.iph->protocol == IPPROTO_IGMP) {
 +              struct slave *slave, *active_slave;
 +              int i;
 +
 +              active_slave = bond->curr_active_slave;
 +              bond_for_each_slave_from_to(bond, slave, i, active_slave->next,
 +                                          active_slave->prev)
 +                      if (IS_UP(slave->dev) &&
 +                          (slave->link == BOND_LINK_UP))
 +                              bond_activebackup_xmit_copy(skb, bond, slave);
        }
  
 +      res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev);
 +
  out:
        if (res) {
                /* no suitable interface, frame not sent */
diff --combined drivers/net/e100.c
@@@ -903,8 -903,8 +903,8 @@@ static void mdio_write(struct net_devic
  
  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 */
@@@ -1007,213 -1007,25 +1007,25 @@@ static void e100_configure(struct nic *
                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,
@@@ -2389,7 -2201,6 +2201,7 @@@ static struct ethtool_ops e100_ethtool_
        .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)
@@@ -2540,8 -2351,7 +2352,8 @@@ static int __devinit e100_probe(struct 
        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;
diff --combined drivers/net/ns83820.c
@@@ -584,7 -584,7 +584,7 @@@ static inline int ns83820_add_rx_skb(st
        return 0;
  }
  
- static inline int rx_refill(struct net_device *ndev, unsigned int __nocast gfp)
+ static inline int rx_refill(struct net_device *ndev, gfp_t gfp)
  {
        struct ns83820 *dev = PRIV(ndev);
        unsigned i;
@@@ -1632,7 -1632,8 +1632,7 @@@ static void ns83820_run_bist(struct net
                        timed_out = 1;
                        break;
                }
 -              set_current_state(TASK_UNINTERRUPTIBLE);
 -              schedule_timeout(1);
 +              schedule_timeout_uninterruptible(1);
        }
  
        if (status & fail)
@@@ -1,6 -1,6 +1,6 @@@
  /******************************************************************************
  
 -  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
@@@ -128,7 -128,7 +128,7 @@@ payload of each frame is reduced to 49
  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;
@@@ -157,11 -157,31 +157,11 @@@ static inline int ieee80211_encrypt_fra
        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);
@@@ -187,7 -207,7 +187,7 @@@ void ieee80211_txb_free(struct ieee8021
  }
  
  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);