Commit 3b8d81e0 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: remove master netdev

With the internal 'pending' queue system in place, we can simply
put packets there instead of pushing them off to the master dev,
getting rid of the master interface completely.
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent c4029083
......@@ -241,6 +241,8 @@ struct ieee80211_bss_conf {
* it can be sent out.
* @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211,
* used to indicate that a frame was already retried due to PS
* @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
* used to indicate frame should not be encrypted
*/
enum mac80211_tx_control_flags {
IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0),
......@@ -259,6 +261,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_INTFL_RCALGO = BIT(13),
IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14),
IEEE80211_TX_INTFL_RETRIED = BIT(15),
IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16),
};
/**
......
......@@ -383,9 +383,6 @@ static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) {
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
/* mark queue as pending, it is stopped already */
__set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING,
&local->queue_stop_reasons[queue]);
/* copy over remaining packets */
skb_queue_splice_tail_init(
&sta->ampdu_mlme.tid_tx[tid]->pending,
......
......@@ -175,7 +175,7 @@ static ssize_t queues_read(struct file *file, char __user *user_buf,
for (q = 0; q < local->hw.queues; q++)
res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q,
local->queue_stop_reasons[q],
__netif_subqueue_stopped(local->mdev, q));
skb_queue_len(&local->pending[q]));
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
return simple_read_from_buffer(user_buf, count, ppos, buf, res);
......
......@@ -567,14 +567,9 @@ enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_CSA,
IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
IEEE80211_QUEUE_STOP_REASON_PENDING,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
};
struct ieee80211_master_priv {
struct ieee80211_local *local;
};
struct ieee80211_local {
/* embed the driver visible part.
* don't cast (use the static inlines below), but we keep
......@@ -587,13 +582,20 @@ struct ieee80211_local {
/* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
spinlock_t queue_stop_reason_lock;
struct net_device *mdev; /* wmaster# - "master" 802.11 device */
int open_count;
int monitors, cooked_mntrs;
/* number of interfaces with corresponding FIF_ flags */
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
unsigned int filter_flags; /* FIF_* */
struct iw_statistics wstats;
/* protects the aggregated multicast list and filter calls */
spinlock_t filter_lock;
/* aggregated multicast list */
struct dev_addr_list *mc_list;
int mc_count;
bool tim_in_locked_section; /* see ieee80211_beacon_get() */
/*
......@@ -813,10 +815,6 @@ struct ieee80211_local {
static inline struct ieee80211_sub_if_data *
IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
BUG_ON(!local || local->mdev == dev);
return netdev_priv(dev);
}
......@@ -996,7 +994,6 @@ void ieee80211_recalc_idle(struct ieee80211_local *local);
/* tx handling */
void ieee80211_clear_tx_pending(struct ieee80211_local *local);
void ieee80211_tx_pending(unsigned long data);
int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
......
......@@ -190,10 +190,6 @@ static int ieee80211_open(struct net_device *dev)
ETH_ALEN);
}
if (compare_ether_addr(null_addr, local->mdev->dev_addr) == 0)
memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr,
ETH_ALEN);
/*
* Validate the MAC address for this device.
*/
......@@ -229,9 +225,9 @@ static int ieee80211_open(struct net_device *dev)
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
local->fif_other_bss++;
netif_addr_lock_bh(local->mdev);
spin_lock_bh(&local->filter_lock);
ieee80211_configure_filter(local);
netif_addr_unlock_bh(local->mdev);
spin_unlock_bh(&local->filter_lock);
break;
default:
conf.vif = &sdata->vif;
......@@ -243,9 +239,9 @@ static int ieee80211_open(struct net_device *dev)
if (ieee80211_vif_is_mesh(&sdata->vif)) {
local->fif_other_bss++;
netif_addr_lock_bh(local->mdev);
spin_lock_bh(&local->filter_lock);
ieee80211_configure_filter(local);
netif_addr_unlock_bh(local->mdev);
spin_unlock_bh(&local->filter_lock);
ieee80211_start_mesh(sdata);
}
......@@ -279,10 +275,6 @@ static int ieee80211_open(struct net_device *dev)
}
if (local->open_count == 0) {
res = dev_open(local->mdev);
WARN_ON(res);
if (res)
goto err_del_interface;
tasklet_enable(&local->tx_pending_tasklet);
tasklet_enable(&local->tasklet);
}
......@@ -393,7 +385,14 @@ static int ieee80211_stop(struct net_device *dev)
if (sdata->flags & IEEE80211_SDATA_PROMISC)
atomic_dec(&local->iff_promiscs);
dev_mc_unsync(local->mdev, dev);
netif_addr_lock_bh(dev);
spin_lock_bh(&local->filter_lock);
__dev_addr_unsync(&local->mc_list, &local->mc_count,
&dev->mc_list, &dev->mc_count);
ieee80211_configure_filter(local);
spin_unlock_bh(&local->filter_lock);
netif_addr_unlock_bh(dev);
del_timer_sync(&local->dynamic_ps_timer);
cancel_work_sync(&local->dynamic_ps_enable_work);
......@@ -442,9 +441,9 @@ static int ieee80211_stop(struct net_device *dev)
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
local->fif_other_bss--;
netif_addr_lock_bh(local->mdev);
spin_lock_bh(&local->filter_lock);
ieee80211_configure_filter(local);
netif_addr_unlock_bh(local->mdev);
spin_unlock_bh(&local->filter_lock);
break;
case NL80211_IFTYPE_STATION:
del_timer_sync(&sdata->u.mgd.chswitch_timer);
......@@ -487,9 +486,9 @@ static int ieee80211_stop(struct net_device *dev)
local->fif_other_bss--;
atomic_dec(&local->iff_allmultis);
netif_addr_lock_bh(local->mdev);
spin_lock_bh(&local->filter_lock);
ieee80211_configure_filter(local);
netif_addr_unlock_bh(local->mdev);
spin_unlock_bh(&local->filter_lock);
ieee80211_stop_mesh(sdata);
}
......@@ -535,9 +534,6 @@ static int ieee80211_stop(struct net_device *dev)
ieee80211_recalc_ps(local, -1);
if (local->open_count == 0) {
if (netif_running(local->mdev))
dev_close(local->mdev);
drv_stop(local);
ieee80211_led_radio(local, false);
......@@ -584,8 +580,11 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
atomic_dec(&local->iff_promiscs);
sdata->flags ^= IEEE80211_SDATA_PROMISC;
}
dev_mc_sync(local->mdev, dev);
spin_lock_bh(&local->filter_lock);
__dev_addr_sync(&local->mc_list, &local->mc_count,
&dev->mc_list, &dev->mc_count);
ieee80211_configure_filter(local);
spin_unlock_bh(&local->filter_lock);
}
/*
......
......@@ -83,75 +83,14 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
new_flags |= (1<<31);
drv_configure_filter(local, changed_flags, &new_flags,
local->mdev->mc_count,
local->mdev->mc_list);
local->mc_count,
local->mc_list);
WARN_ON(new_flags & (1<<31));
local->filter_flags = new_flags & ~(1<<31);
}
/* master interface */
static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
{
memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
return ETH_ALEN;
}
static const struct header_ops ieee80211_header_ops = {
.create = eth_header,
.parse = header_parse_80211,
.rebuild = eth_rebuild_header,
.cache = eth_header_cache,
.cache_update = eth_header_cache_update,
};
static int ieee80211_master_open(struct net_device *dev)
{
struct ieee80211_master_priv *mpriv = netdev_priv(dev);
struct ieee80211_local *local = mpriv->local;
struct ieee80211_sub_if_data *sdata;
int res = -EOPNOTSUPP;
/* we hold the RTNL here so can safely walk the list */
list_for_each_entry(sdata, &local->interfaces, list) {
if (netif_running(sdata->dev)) {
res = 0;
break;
}
}
if (res)
return res;
netif_tx_start_all_queues(local->mdev);
return 0;
}
static int ieee80211_master_stop(struct net_device *dev)
{
struct ieee80211_master_priv *mpriv = netdev_priv(dev);
struct ieee80211_local *local = mpriv->local;
struct ieee80211_sub_if_data *sdata;
/* we hold the RTNL here so can safely walk the list */
list_for_each_entry(sdata, &local->interfaces, list)
if (netif_running(sdata->dev))
dev_close(sdata->dev);
return 0;
}
static void ieee80211_master_set_multicast_list(struct net_device *dev)
{
struct ieee80211_master_priv *mpriv = netdev_priv(dev);
struct ieee80211_local *local = mpriv->local;
ieee80211_configure_filter(local);
}
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
{
struct ieee80211_channel *chan, *scan_chan;
......@@ -310,7 +249,6 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int tmp;
skb->dev = local->mdev;
skb->pkt_type = IEEE80211_TX_STATUS_MSG;
skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
&local->skb_queue : &local->skb_queue_unreliable, skb);
......@@ -716,7 +654,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
mutex_init(&local->scan_mtx);
spin_lock_init(&local->key_lock);
spin_lock_init(&local->filter_lock);
spin_lock_init(&local->queue_stop_reason_lock);
INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
......@@ -752,30 +690,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
}
EXPORT_SYMBOL(ieee80211_alloc_hw);
static const struct net_device_ops ieee80211_master_ops = {
.ndo_start_xmit = ieee80211_master_start_xmit,
.ndo_open = ieee80211_master_open,
.ndo_stop = ieee80211_master_stop,
.ndo_set_multicast_list = ieee80211_master_set_multicast_list,
.ndo_select_queue = ieee80211_select_queue,
};
static void ieee80211_master_setup(struct net_device *mdev)
{
mdev->type = ARPHRD_IEEE80211;
mdev->netdev_ops = &ieee80211_master_ops;
mdev->header_ops = &ieee80211_header_ops;
mdev->tx_queue_len = 1000;
mdev->addr_len = ETH_ALEN;
}
int ieee80211_register_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
int result;
enum ieee80211_band band;
struct net_device *mdev;
struct ieee80211_master_priv *mpriv;
int channels, i, j, max_bitrates;
bool supp_ht;
static const u32 cipher_suites[] = {
......@@ -874,16 +793,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (hw->queues > IEEE80211_MAX_QUEUES)
hw->queues = IEEE80211_MAX_QUEUES;
mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv),
"wmaster%d", ieee80211_master_setup,
hw->queues);
if (!mdev)
goto fail_mdev_alloc;
mpriv = netdev_priv(mdev);
mpriv->local = local;
local->mdev = mdev;
local->hw.workqueue =
create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
if (!local->hw.workqueue) {
......@@ -918,17 +827,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
}
rtnl_lock();
result = dev_alloc_name(local->mdev, local->mdev->name);
if (result < 0)
goto fail_dev;
memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy));
local->mdev->features |= NETIF_F_NETNS_LOCAL;
result = register_netdevice(local->mdev);
if (result < 0)
goto fail_dev;
result = ieee80211_init_rate_ctrl_alg(local,
hw->rate_control_algorithm);
......@@ -981,9 +879,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
ieee80211_led_exit(local);
ieee80211_remove_interfaces(local);
fail_rate:
unregister_netdevice(local->mdev);
local->mdev = NULL;
fail_dev:
rtnl_unlock();
ieee80211_wep_free(local);
fail_wep:
......@@ -992,9 +887,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
debugfs_hw_del(local);
destroy_workqueue(local->hw.workqueue);
fail_workqueue:
if (local->mdev)
free_netdev(local->mdev);
fail_mdev_alloc:
wiphy_unregister(local->hw.wiphy);
fail_wiphy_register:
kfree(local->int_scan_req.channels);
......@@ -1019,13 +911,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
* because the driver cannot be handing us frames any
* more and the tasklet is killed.
*/
/* First, we remove all virtual interfaces. */
ieee80211_remove_interfaces(local);
/* then, finally, remove the master interface */
unregister_netdevice(local->mdev);
rtnl_unlock();
ieee80211_clear_tx_pending(local);
......@@ -1044,7 +931,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
wiphy_unregister(local->hw.wiphy);
ieee80211_wep_free(local);
ieee80211_led_exit(local);
free_netdev(local->mdev);
kfree(local->int_scan_req.channels);
}
EXPORT_SYMBOL(ieee80211_unregister_hw);
......
......@@ -287,7 +287,7 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
struct rate_control_ref *ref, *old;
ASSERT_RTNL();
if (local->open_count || netif_running(local->mdev))
if (local->open_count)
return -EBUSY;
ref = rate_control_alloc(name, local);
......
......@@ -1478,6 +1478,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
struct ieee80211s_hdr *mesh_hdr;
unsigned int hdrlen;
struct sk_buff *skb = rx->skb, *fwd_skb;
struct ieee80211_local *local = rx->local;
hdr = (struct ieee80211_hdr *) skb->data;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
......@@ -1520,6 +1521,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
dropped_frames_ttl);
else {
struct ieee80211_hdr *fwd_hdr;
struct ieee80211_tx_info *info;
fwd_skb = skb_copy(skb, GFP_ATOMIC);
if (!fwd_skb && net_ratelimit())
......@@ -1533,9 +1536,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
*/
memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN);
memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN);
fwd_skb->dev = rx->local->mdev;
info = IEEE80211_SKB_CB(fwd_skb);
memset(info, 0, sizeof(*info));
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
fwd_skb->iif = rx->dev->ifindex;
dev_queue_xmit(fwd_skb);
ieee80211_select_queue(local, fwd_skb);
ieee80211_add_pending_skb(local, fwd_skb);
}
}
......@@ -1803,8 +1809,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
return RX_DROP_MONITOR;
}
static void ieee80211_rx_michael_mic_report(struct net_device *dev,
struct ieee80211_hdr *hdr,
static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
struct ieee80211_rx_data *rx)
{
int keyidx;
......@@ -2114,7 +2119,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
}
if ((status->flag & RX_FLAG_MMIC_ERROR)) {
ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx);
ieee80211_rx_michael_mic_report(hdr, &rx);
return;
}
......@@ -2483,7 +2488,6 @@ void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb)
BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
skb->dev = local->mdev;
skb->pkt_type = IEEE80211_RX_MSG;
skb_queue_tail(&local->skb_queue, skb);
tasklet_schedule(&local->tasklet);
......
......@@ -294,16 +294,13 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
if (was_hw_scan)
goto done;
netif_tx_lock_bh(local->mdev);
netif_addr_lock(local->mdev);
spin_lock_bh(&local->filter_lock);
local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
&local->filter_flags,
local->mdev->mc_count,
local->mdev->mc_list);
netif_addr_unlock(local->mdev);
netif_tx_unlock_bh(local->mdev);
local->mc_count,
local->mc_list);
spin_unlock_bh(&local->filter_lock);
drv_sw_scan_complete(local);
......@@ -382,13 +379,13 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
local->scan_state = SCAN_SET_CHANNEL;
local->scan_channel_idx = 0;
netif_addr_lock_bh(local->mdev);
spin_lock_bh(&local->filter_lock);
local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
&local->filter_flags,
local->mdev->mc_count,
local->mdev->mc_list);
netif_addr_unlock_bh(local->mdev);
local->mc_count,
local->mc_list);
spin_unlock_bh(&local->filter_lock);
/* TODO: start scan as soon as all nullfunc frames are ACKed */
queue_delayed_work(local->hw.workqueue, &local->scan_work,
......
......@@ -451,7 +451,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
if (unlikely(tx->skb->do_not_encrypt))
if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
tx->key = NULL;
else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
tx->key = key;
......@@ -497,7 +497,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
}
if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
tx->skb->do_not_encrypt = 1;
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
return TX_CONTINUE;
}
......@@ -774,9 +774,7 @@ static int ieee80211_fragment(struct ieee80211_local *local,
memcpy(tmp->cb, skb->cb, sizeof(tmp->cb));
skb_copy_queue_mapping(tmp, skb);
tmp->priority = skb->priority;
tmp->do_not_encrypt = skb->do_not_encrypt;
tmp->dev = skb->dev;
tmp->iif = skb->iif;
/* copy header and data */
memcpy(skb_put(tmp, hdrlen), skb->data, hdrlen);
......@@ -804,7 +802,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
/*
* Warn when submitting a fragmented A-MPDU frame and drop it.
* This scenario is handled in __ieee80211_tx_prepare but extra
* This scenario is handled in ieee80211_tx_prepare but extra
* caution taken here as fragmented ampdu may cause Tx stop.
*/
if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
......@@ -943,11 +941,12 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
struct ieee80211_radiotap_header *rthdr =
(struct ieee80211_radiotap_header *) skb->data;
struct ieee80211_supported_band *sband;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
sband = tx->local->hw.wiphy->bands[tx->channel->band];
skb->do_not_encrypt = 1;
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
tx->flags &= ~IEEE80211_TX_FRAGMENTED;
/*
......@@ -985,7 +984,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
skb_trim(skb, skb->len - FCS_LEN);
}
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
tx->skb->do_not_encrypt = 0;
info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
tx->flags |= IEEE80211_TX_FRAGMENTED;
break;
......@@ -1018,13 +1017,12 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
* initialises @tx
*/
static ieee80211_tx_result
__ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
struct sk_buff *skb,
struct net_device *dev)
ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
struct ieee80211_tx_data *tx,
struct sk_buff *skb)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_local *local = sdata->local;
struct ieee80211_hdr *hdr;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int hdrlen, tid;
u8 *qc, *state;
......@@ -1032,9 +1030,9 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
memset(tx, 0, sizeof(*tx));
tx->skb = skb;
tx->dev = dev; /* use original interface */
tx->dev = sdata->dev; /* use original interface */
tx->local = local;
tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
tx->sdata = sdata;
tx->channel = local->hw.conf.channel;
/*
* Set this flag (used below to indicate "automatic fragmentation"),
......@@ -1043,7 +1041,6 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
tx->flags |= IEEE80211_TX_FRAGMENTED;
/* process and remove the injection radiotap header */
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) {
if (!__ieee80211_parse_tx_radiotap(tx, skb))
return TX_DROP;
......@@ -1139,50 +1136,28 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
return TX_CONTINUE;
}
/*
* NB: @tx is uninitialised when passed in here
*/
static int ieee80211_tx_prepare(struct ieee80211_local *local,
struct ieee80211_tx_data *tx,
struct sk_buff *skb)
{
struct net_device *dev;
dev = dev_get_by_index(&init_net, skb->iif);
if (unlikely(dev && !is_ieee80211_device(local, dev))) {
dev_put(dev);
dev = NULL;
}
if (unlikely(!dev))
return -ENODEV;
/*
* initialises tx with control
*
* return value is safe to ignore here because this function
* can only be invoked for multicast frames
*
* XXX: clean up
*/
__ieee80211_tx_prepare(tx, skb, dev);
dev_put(dev);
return 0;
}
static int __ieee80211_tx(struct ieee80211_local *local,
struct sk_buff **skbp,
struct sta_info *sta)
struct sta_info *sta,
bool txpending)
{
struct sk_buff *skb = *skbp, *next;
struct ieee80211_tx_info *info;
unsigned long flags;
int ret, len;
bool fragm = false;
local->mdev->trans_start = jiffies;
while (skb) {
if (ieee80211_queue_stopped(&local->hw,
skb_get_queue_mapping(skb)))