Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[pandora-kernel.git] / drivers / net / wireless / mac80211_hwsim.c
index 7916ca3..e9b5442 100644 (file)
@@ -15,6 +15,8 @@
 
 #include <linux/list.h>
 #include <linux/spinlock.h>
+#include <net/dst.h>
+#include <net/xfrm.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
 #include <linux/if_arp.h>
@@ -314,7 +316,7 @@ static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        /* TODO: allow packet injection */
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
@@ -409,6 +411,13 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
        if (data->ps != PS_DISABLED)
                hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
 
+       /* release the skb's source info */
+       skb_orphan(skb);
+       skb_dst_drop(skb);
+       skb->mark = 0;
+       secpath_reset(skb);
+       nf_reset(skb);
+
        /* Copy skb to all enabled radios that are on the current frequency */
        spin_lock(&hwsim_radio_lock);
        list_for_each_entry(data2, &hwsim_radios, list) {
@@ -430,7 +439,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
                if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr,
                           ETH_ALEN) == 0)
                        ack = true;
-               ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status);
+               memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
+               ieee80211_rx_irqsafe(data2->hw, nskb);
        }
        spin_unlock(&hwsim_radio_lock);
 
@@ -690,6 +700,74 @@ static int mac80211_hwsim_conf_tx(
        return 0;
 }
 
+#ifdef CONFIG_NL80211_TESTMODE
+/*
+ * This section contains example code for using netlink
+ * attributes with the testmode command in nl80211.
+ */
+
+/* These enums need to be kept in sync with userspace */
+enum hwsim_testmode_attr {
+       __HWSIM_TM_ATTR_INVALID = 0,
+       HWSIM_TM_ATTR_CMD       = 1,
+       HWSIM_TM_ATTR_PS        = 2,
+
+       /* keep last */
+       __HWSIM_TM_ATTR_AFTER_LAST,
+       HWSIM_TM_ATTR_MAX       = __HWSIM_TM_ATTR_AFTER_LAST - 1
+};
+
+enum hwsim_testmode_cmd {
+       HWSIM_TM_CMD_SET_PS             = 0,
+       HWSIM_TM_CMD_GET_PS             = 1,
+};
+
+static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = {
+       [HWSIM_TM_ATTR_CMD] = { .type = NLA_U32 },
+       [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 },
+};
+
+static int hwsim_fops_ps_write(void *dat, u64 val);
+
+static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
+                                      void *data, int len)
+{
+       struct mac80211_hwsim_data *hwsim = hw->priv;
+       struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1];
+       struct sk_buff *skb;
+       int err, ps;
+
+       err = nla_parse(tb, HWSIM_TM_ATTR_MAX, data, len,
+                       hwsim_testmode_policy);
+       if (err)
+               return err;
+
+       if (!tb[HWSIM_TM_ATTR_CMD])
+               return -EINVAL;
+
+       switch (nla_get_u32(tb[HWSIM_TM_ATTR_CMD])) {
+       case HWSIM_TM_CMD_SET_PS:
+               if (!tb[HWSIM_TM_ATTR_PS])
+                       return -EINVAL;
+               ps = nla_get_u32(tb[HWSIM_TM_ATTR_PS]);
+               return hwsim_fops_ps_write(hwsim, ps);
+       case HWSIM_TM_CMD_GET_PS:
+               skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+                                               nla_total_size(sizeof(u32)));
+               if (!skb)
+                       return -ENOMEM;
+               NLA_PUT_U32(skb, HWSIM_TM_ATTR_PS, hwsim->ps);
+               return cfg80211_testmode_reply(skb);
+       default:
+               return -EOPNOTSUPP;
+       }
+
+ nla_put_failure:
+       kfree_skb(skb);
+       return -ENOBUFS;
+}
+#endif
+
 static const struct ieee80211_ops mac80211_hwsim_ops =
 {
        .tx = mac80211_hwsim_tx,
@@ -703,6 +781,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
        .sta_notify = mac80211_hwsim_sta_notify,
        .set_tim = mac80211_hwsim_set_tim,
        .conf_tx = mac80211_hwsim_conf_tx,
+       CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
 };