diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 103 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/main.c | 25 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 5 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 19 | ||||
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 11 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 48 | ||||
-rw-r--r-- | net/mac80211/rx.c | 116 | ||||
-rw-r--r-- | net/mac80211/tx.c | 117 | ||||
-rw-r--r-- | net/mac80211/util.c | 1 | ||||
-rw-r--r-- | net/mac80211/wep.c | 4 | ||||
-rw-r--r-- | net/mac80211/wme.c | 9 |
12 files changed, 293 insertions, 167 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8e7ba0e62cf..297c257864c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -81,6 +81,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { + struct ieee80211_local *local = wiphy_priv(wiphy); struct net_device *dev; enum ieee80211_if_types itype; struct ieee80211_sub_if_data *sdata; @@ -95,6 +96,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, if (itype == IEEE80211_IF_TYPE_INVALID) return -EINVAL; + if (dev == local->mdev) + return -EOPNOTSUPP; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); ret = ieee80211_if_change_type(sdata, itype); @@ -117,12 +121,16 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, u8 *mac_addr, struct key_params *params) { + struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_sub_if_data *sdata; struct sta_info *sta = NULL; enum ieee80211_key_alg alg; struct ieee80211_key *key; int err; + if (dev == local->mdev) + return -EOPNOTSUPP; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); switch (params->cipher) { @@ -167,10 +175,14 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, u8 *mac_addr) { + struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_sub_if_data *sdata; struct sta_info *sta; int ret; + if (dev == local->mdev) + return -EOPNOTSUPP; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); rcu_read_lock(); @@ -211,7 +223,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, void (*callback)(void *cookie, struct key_params *params)) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata; struct sta_info *sta = NULL; u8 seq[6] = {0}; struct key_params params; @@ -220,6 +233,11 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, u16 iv16; int err = -ENOENT; + if (dev == local->mdev) + return -EOPNOTSUPP; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + rcu_read_lock(); if (mac_addr) { @@ -293,8 +311,12 @@ static int ieee80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx) { + struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_sub_if_data *sdata; + if (dev == local->mdev) + return -EOPNOTSUPP; + rcu_read_lock(); sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -475,9 +497,15 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, struct beacon_parameters *params) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata; struct beacon_data *old; + if (dev == local->mdev) + return -EOPNOTSUPP; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type != IEEE80211_IF_TYPE_AP) return -EINVAL; @@ -492,9 +520,15 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, struct beacon_parameters *params) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata; struct beacon_data *old; + if (dev == local->mdev) + return -EOPNOTSUPP; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type != IEEE80211_IF_TYPE_AP) return -EINVAL; @@ -508,9 +542,15 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata; struct beacon_data *old; + if (dev == local->mdev) + return -EOPNOTSUPP; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type != IEEE80211_IF_TYPE_AP) return -EINVAL; @@ -646,11 +686,14 @@ static void sta_apply_parameters(struct ieee80211_local *local, static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_parameters *params) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_local *local = wiphy_priv(wiphy); struct sta_info *sta; struct ieee80211_sub_if_data *sdata; int err; + if (dev == local->mdev || params->vlan == local->mdev) + return -EOPNOTSUPP; + /* Prevent a race with changing the rate control algorithm */ if (!netif_running(dev)) return -ENETDOWN; @@ -701,10 +744,15 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = sdata->local; + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata; struct sta_info *sta; + if (dev == local->mdev) + return -EOPNOTSUPP; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (mac) { rcu_read_lock(); @@ -730,10 +778,13 @@ static int ieee80211_change_station(struct wiphy *wiphy, u8 *mac, struct station_parameters *params) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_local *local = wiphy_priv(wiphy); struct sta_info *sta; struct ieee80211_sub_if_data *vlansdata; + if (dev == local->mdev || params->vlan == local->mdev) + return -EOPNOTSUPP; + rcu_read_lock(); /* XXX: get sta belonging to dev */ @@ -752,7 +803,7 @@ static int ieee80211_change_station(struct wiphy *wiphy, return -EINVAL; } - sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); + sta->sdata = vlansdata; ieee80211_send_layer2_update(sta); } @@ -767,15 +818,20 @@ static int ieee80211_change_station(struct wiphy *wiphy, static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, u8 *dst, u8 *next_hop) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata; struct mesh_path *mpath; struct sta_info *sta; int err; + if (dev == local->mdev) + return -EOPNOTSUPP; + if (!netif_running(dev)) return -ENETDOWN; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) return -ENOTSUPP; @@ -817,14 +873,19 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, struct net_device *dev, u8 *dst, u8 *next_hop) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata; struct mesh_path *mpath; struct sta_info *sta; + if (dev == local->mdev) + return -EOPNOTSUPP; + if (!netif_running(dev)) return -ENETDOWN; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) return -ENOTSUPP; @@ -891,9 +952,15 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev, u8 *dst, u8 *next_hop, struct mpath_info *pinfo) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata; struct mesh_path *mpath; + if (dev == local->mdev) + return -EOPNOTSUPP; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) return -ENOTSUPP; @@ -913,9 +980,15 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *dst, u8 *next_hop, struct mpath_info *pinfo) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata; struct mesh_path *mpath; + if (dev == local->mdev) + return -EOPNOTSUPP; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) return -ENOTSUPP; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a4f9a832722..ec59345af65 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -82,6 +82,7 @@ struct ieee80211_sta_bss { u8 bssid[ETH_ALEN]; u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 dtim_period; u16 capability; /* host byte order */ enum ieee80211_band band; int freq; @@ -586,6 +587,7 @@ struct ieee80211_local { struct timer_list sta_cleanup; unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; + unsigned long queues_pending_run[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES]; struct tasklet_struct tx_pending_tasklet; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f1a83d450ea..aa5a191598c 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -245,10 +245,13 @@ static int ieee80211_open(struct net_device *dev) case IEEE80211_IF_TYPE_AP: sdata->bss = &sdata->u.ap; break; + case IEEE80211_IF_TYPE_MESH_POINT: + /* mesh ifaces must set allmulti to forward mcast traffic */ + atomic_inc(&local->iff_allmultis); + break; case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_MNTR: case IEEE80211_IF_TYPE_IBSS: - case IEEE80211_IF_TYPE_MESH_POINT: /* no special treatment */ break; case IEEE80211_IF_TYPE_INVALID: @@ -495,6 +498,9 @@ static int ieee80211_stop(struct net_device *dev) netif_addr_unlock_bh(local->mdev); break; case IEEE80211_IF_TYPE_MESH_POINT: + /* allmulti is always set on mesh ifaces */ + atomic_dec(&local->iff_allmultis); + /* fall through */ case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: sdata->u.sta.state = IEEE80211_DISABLED; @@ -1233,18 +1239,12 @@ static void ieee80211_tasklet_handler(unsigned long data) /* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to * make a prepared TX frame (one that has been given to hw) to look like brand * new IEEE 802.11 frame that is ready to go through TX processing again. - * Also, tx_packet_data in cb is restored from tx_control. */ + */ static void ieee80211_remove_tx_extra(struct ieee80211_local *local, struct ieee80211_key *key, struct sk_buff *skb) { int hdrlen, iv_len, mic_len; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - info->flags &= IEEE80211_TX_CTL_REQ_TX_STATUS | - IEEE80211_TX_CTL_DO_NOT_ENCRYPT | - IEEE80211_TX_CTL_REQUEUE | - IEEE80211_TX_CTL_EAPOL_FRAME; hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -1695,6 +1695,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (local->hw.conf.beacon_int < 10) local->hw.conf.beacon_int = 100; + if (local->hw.max_listen_interval == 0) + local->hw.max_listen_interval = 1; + + local->hw.conf.listen_interval = local->hw.max_listen_interval; + local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC | IEEE80211_HW_SIGNAL_DB | IEEE80211_HW_SIGNAL_DBM) ? @@ -1731,8 +1736,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) result = ieee80211_wep_init(local); if (result < 0) { - printk(KERN_DEBUG "%s: Failed to initialize wep\n", - wiphy_name(local->hw.wiphy)); + printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n", + wiphy_name(local->hw.wiphy), result); goto fail_wep; } diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 669eafafe49..7495fbb0d21 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -214,8 +214,7 @@ void ieee80211s_stop(void); void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); /* Mesh paths */ -int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb, - struct net_device *dev); +int mesh_nexthop_lookup(struct sk_buff *skb, struct net_device *dev); void mesh_path_start_discovery(struct net_device *dev); struct mesh_path *mesh_path_lookup(u8 *dst, struct net_device *dev); struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev); @@ -286,6 +285,4 @@ static inline void mesh_path_activate(struct mesh_path *mpath) #define mesh_allocated 0 #endif -#define MESH_PREQ(skb) (skb->cb + 30) - #endif /* IEEE80211S_H */ diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 7fa149e230e..08aca446ca0 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -758,29 +758,30 @@ enddiscovery: /** * ieee80211s_lookup_nexthop - put the appropriate next hop on a mesh frame * - * @next_hop: output argument for next hop address - * @skb: frame to be sent + * @skb: 802.11 frame to be sent * @dev: network device the frame will be sent through + * @fwd_frame: true if this frame was originally from a different host * * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is * found, the function will start a path discovery and queue the frame so it is * sent when the path is resolved. This means the caller must not free the skb * in this case. */ -int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb, - struct net_device *dev) +int mesh_nexthop_lookup(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sk_buff *skb_to_free = NULL; struct mesh_path *mpath; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *dst_addr = hdr->addr3; int err = 0; rcu_read_lock(); - mpath = mesh_path_lookup(skb->data, dev); + mpath = mesh_path_lookup(dst_addr, dev); if (!mpath) { - mesh_path_add(skb->data, dev); - mpath = mesh_path_lookup(skb->data, dev); + mesh_path_add(dst_addr, dev); + mpath = mesh_path_lookup(dst_addr, dev); if (!mpath) { dev_kfree_skb(skb); sdata->u.sta.mshstats.dropped_frames_no_route++; @@ -792,13 +793,13 @@ int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb, if (mpath->flags & MESH_PATH_ACTIVE) { if (time_after(jiffies, mpath->exp_time - msecs_to_jiffies(sdata->u.sta.mshcfg.path_refresh_time)) - && skb->pkt_type != PACKET_OTHERHOST + && !memcmp(dev->dev_addr, hdr->addr4, ETH_ALEN) && !(mpath->flags & MESH_PATH_RESOLVING) && !(mpath->flags & MESH_PATH_FIXED)) { mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH); } - memcpy(next_hop, mpath->next_hop->addr, + memcpy(hdr->addr1, mpath->next_hop->addr, ETH_ALEN); } else { if (!(mpath->flags & MESH_PATH_RESOLVING)) { diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 5f88a2e6ee5..838ee60492a 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -388,18 +388,15 @@ void mesh_path_tx_pending(struct mesh_path *mpath) void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct mesh_path *mpath; u32 dsn = 0; - if (skb->pkt_type == PACKET_OTHERHOST) { - struct ieee80211s_hdr *prev_meshhdr; - int mshhdrlen; + if (memcmp(hdr->addr4, dev->dev_addr, ETH_ALEN) != 0) { u8 *ra, *da; - prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb); - mshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr); - da = skb->data; - ra = MESH_PREQ(skb); + da = hdr->addr3; + ra = hdr->addr2; mpath = mesh_path_lookup(da, dev); if (mpath) dsn = ++mpath->dsn; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d7c371e36bf..e1d11c9b672 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -551,6 +551,7 @@ static void ieee80211_set_associated(struct net_device *dev, /* set timing information */ sdata->bss_conf.beacon_int = bss->beacon_int; sdata->bss_conf.timestamp = bss->timestamp; + sdata->bss_conf.dtim_period = bss->dtim_period; changed |= ieee80211_handle_bss_capability(sdata, bss); @@ -606,7 +607,6 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, int encrypt) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_tx_info *info; sdata = IEEE80211_DEV_TO_SUB_IF(dev); skb->dev = sdata->local->mdev; @@ -614,11 +614,8 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, skb_set_network_header(skb, 0); skb_set_transport_header(skb, 0); - info = IEEE80211_SKB_CB(skb); - memset(info, 0, sizeof(struct ieee80211_tx_info)); - info->control.ifindex = sdata->dev->ifindex; - if (!encrypt) - info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + skb->iif = sdata->dev->ifindex; + skb->do_not_encrypt = !encrypt; dev_queue_xmit(skb); } @@ -777,7 +774,8 @@ static void ieee80211_send_assoc(struct net_device *dev, mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, IEEE80211_STYPE_REASSOC_REQ); mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); - mgmt->u.reassoc_req.listen_interval = cpu_to_le16(1); + mgmt->u.reassoc_req.listen_interval = + cpu_to_le16(local->hw.conf.listen_interval); memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid, ETH_ALEN); } else { @@ -785,7 +783,8 @@ static void ieee80211_send_assoc(struct net_device *dev, mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, IEEE80211_STYPE_ASSOC_REQ); mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); - mgmt->u.assoc_req.listen_interval = cpu_to_le16(1); + mgmt->u.reassoc_req.listen_interval = + cpu_to_le16(local->hw.conf.listen_interval); } /* SSID */ @@ -2692,6 +2691,16 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); + if (elems->tim) { + struct ieee80211_tim_ie *tim_ie = + (struct ieee80211_tim_ie *)elems->tim; + bss->dtim_period = tim_ie->dtim_period; + } + + /* set default value for buggy APs */ + if (!elems->tim || bss->dtim_period == 0) + bss->dtim_period = 1; + bss->supp_rates_len = 0; if (elems->supp_rates) { clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; @@ -3303,6 +3312,7 @@ void ieee80211_start_mesh(struct net_device *dev) ifsta = &sdata->u.sta; ifsta->state = IEEE80211_MESH_UP; ieee80211_sta_timer((unsigned long)sdata); + ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); } #endif @@ -3653,11 +3663,21 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ - if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 && - (bss = ieee80211_rx_bss_get(dev, bssid, - local->hw.conf.channel->center_freq, - ifsta->ssid, ifsta->ssid_len))) { + + if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { int ret; + int search_freq; + + if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) + search_freq = bss->freq; + else + search_freq = local->hw.conf.channel->center_freq; + + bss = ieee80211_rx_bss_get(dev, bssid, search_freq, + ifsta->ssid, ifsta->ssid_len); + if (!bss) + goto dont_join; + printk(KERN_DEBUG "%s: Selected IBSS BSSID %s" " based on configured SSID\n", dev->name, print_mac(mac, bssid)); @@ -3665,6 +3685,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, ieee80211_rx_bss_put(local, bss); return ret; } + +dont_join: #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG " did not try to join ibss\n"); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ @@ -3898,7 +3920,7 @@ done: if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { struct ieee80211_if_sta *ifsta = &sdata->u.sta; if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) || - (!ifsta->state == IEEE80211_IBSS_JOINED && + (!(ifsta->state == IEEE80211_IBSS_JOINED) && !ieee80211_sta_active_ibss(dev))) ieee80211_sta_find_ibss(dev, ifsta); } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6d9ae67c27c..6db85450519 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1109,20 +1109,9 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx) hdrlen = ieee80211_get_hdrlen(fc); - if (ieee80211_vif_is_mesh(&sdata->vif)) { - int meshhdrlen = ieee80211_get_mesh_hdrlen( + if (ieee80211_vif_is_mesh(&sdata->vif)) + hdrlen += ieee80211_get_mesh_hdrlen( (struct ieee80211s_hdr *) (skb->data + hdrlen)); - /* Copy on cb: - * - mesh header: to be used for mesh forwarding - * decision. It will also be used as mesh header template at - * tx.c:ieee80211_subif_start_xmit() if interface - * type is mesh and skb->pkt_type == PACKET_OTHERHOST - * - ta: to be used if a RERR needs to be sent. - */ - memcpy(skb->cb, skb->data + hdrlen, meshhdrlen); - memcpy(MESH_PREQ(skb), hdr->addr2, ETH_ALEN); - hdrlen += meshhdrlen; - } /* convert IEEE 802.11 header + possible LLC headers into Ethernet * header @@ -1269,38 +1258,6 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) } } - /* Mesh forwarding */ - if (ieee80211_vif_is_mesh(&sdata->vif)) { - u8 *mesh_ttl = &((struct ieee80211s_hdr *)skb->cb)->ttl; - (*mesh_ttl)--; - - if (is_multicast_ether_addr(skb->data)) { - if (*mesh_ttl > 0) { - xmit_skb = skb_copy(skb, GFP_ATOMIC); - if (xmit_skb) - xmit_skb->pkt_type = PACKET_OTHERHOST; - else if (net_ratelimit()) - printk(KERN_DEBUG "%s: failed to clone " - "multicast frame\n", dev->name); - } else - IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta, - dropped_frames_ttl); - } else if (skb->pkt_type != PACKET_OTHERHOST && - compare_ether_addr(dev->dev_addr, skb->data) != 0) { - if (*mesh_ttl == 0) { - IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta, - dropped_frames_ttl); - dev_kfree_skb(skb); - skb = NULL; - } else { - xmit_skb = skb; - xmit_skb->pkt_type = PACKET_OTHERHOST; - if (!(dev->flags & IFF_PROMISC)) - skb = NULL; - } - } - } - if (skb) { /* deliver to local stack */ skb->protocol = eth_type_trans(skb, dev); @@ -1431,6 +1388,63 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) } static ieee80211_rx_result debug_noinline +ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) +{ + struct ieee80211_hdr *hdr; + struct ieee80211s_hdr *mesh_hdr; + unsigned int hdrlen; + struct sk_buff *skb = rx->skb, *fwd_skb; + + hdr = (struct ieee80211_hdr *) skb->data; + hdrlen = ieee80211_hdrlen(hdr->frame_control); + mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); + + if (!ieee80211_is_data(hdr->frame_control)) + return RX_CONTINUE; + + if (!mesh_hdr->ttl) + /* illegal frame */ + return RX_DROP_MONITOR; + + if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0) + return RX_CONTINUE; + + mesh_hdr->ttl--; + + if (rx->flags & IEEE80211_RX_RA_MATCH) { + if (!mesh_hdr->ttl) + IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.sta, + dropped_frames_ttl); + else { + struct ieee80211_hdr *fwd_hdr; + fwd_skb = skb_copy(skb, GFP_ATOMIC); + + if (!fwd_skb && net_ratelimit()) + printk(KERN_DEBUG "%s: failed to clone mesh frame\n", + rx->dev->name); + + fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; + /* + * Save TA to addr1 to send TA a path error if a + * suitable next hop is not found + */ + 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; + fwd_skb->iif = rx->dev->ifindex; + dev_queue_xmit(fwd_skb); + } + } + + if (is_multicast_ether_addr(hdr->addr3) || + rx->dev->flags & IFF_PROMISC) + return RX_CONTINUE; + else + return RX_DROP_MONITOR; +} + + +static ieee80211_rx_result debug_noinline ieee80211_rx_h_data(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->dev; @@ -1663,10 +1677,12 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, rx->sdata = sdata; rx->dev = sdata->dev; -#define CALL_RXH(rxh) \ - res = rxh(rx); \ - if (res != RX_CONTINUE) \ - goto rxh_done; +#define CALL_RXH(rxh) \ + do { \ + res = rxh(rx); \ + if (res != RX_CONTINUE) \ + goto rxh_done; \ + } while (0); CALL_RXH(ieee80211_rx_h_passive_scan) CALL_RXH(ieee80211_rx_h_check) @@ -1678,6 +1694,8 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, /* must be after MMIC verify so header is counted in MPDU mic */ CALL_RXH(ieee80211_rx_h_remove_qos_control) CALL_RXH(ieee80211_rx_h_amsdu) + if (ieee80211_vif_is_mesh(&sdata->vif)) + CALL_RXH(ieee80211_rx_h_mesh_fwding); CALL_RXH(ieee80211_rx_h_data) CALL_RXH(ieee80211_rx_h_ctrl) CALL_RXH(ieee80211_rx_h_mgmt) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0fbadd8b983..4788f7b91f4 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -305,7 +305,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) rcu_read_unlock(); local->total_ps_buffered = total; -#ifdef MAC80211_VERBOSE_PS_DEBUG +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", wiphy_name(local->hw.wiphy), purged); #endif @@ -342,7 +342,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) purge_old_ps_buffers(tx->local); if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) { -#ifdef MAC80211_VERBOSE_PS_DEBUG +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG if (net_ratelimit()) { printk(KERN_DEBUG "%s: BC TX buffer full - " "dropping the oldest frame\n", @@ -389,7 +389,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) purge_old_ps_buffers(tx->local); if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf); -#ifdef MAC80211_VERBOSE_PS_DEBUG +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG if (net_ratelimit()) { printk(KERN_DEBUG "%s: STA %s TX " "buffer full - dropping oldest frame\n", @@ -439,14 +439,14 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); u16 fc = tx->fc; - if (unlikely(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) + if (unlikely(tx->skb->do_not_encrypt)) tx->key = NULL; else if (tx->sta && (key = rcu_dereference(tx->sta->key))) tx->key = key; else if ((key = rcu_dereference(tx->sdata->default_key))) tx->key = key; else if (tx->sdata->drop_unencrypted && - !(info->flags & IEEE80211_TX_CTL_EAPOL_FRAME) && + (tx->skb->protocol != cpu_to_be16(ETH_P_PAE)) && !(info->flags & IEEE80211_TX_CTL_INJECTED)) { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); return TX_DROP; @@ -476,7 +476,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) } if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) - info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + tx->skb->do_not_encrypt = 1; return TX_CONTINUE; } @@ -732,6 +732,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) memcpy(skb_put(frag, copylen), pos, copylen); memcpy(frag->cb, first->cb, sizeof(frag->cb)); skb_copy_queue_mapping(frag, first); + frag->do_not_encrypt = first->do_not_encrypt; pos += copylen; left -= copylen; @@ -852,7 +853,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, sband = tx->local->hw.wiphy->bands[tx->channel->band]; - info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + skb->do_not_encrypt = 1; info->flags |= IEEE80211_TX_CTL_INJECTED; tx->flags &= ~IEEE80211_TX_FRAGMENTED; @@ -925,8 +926,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, skb_trim(skb, skb->len - FCS_LEN); } if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) - info->flags &= - ~IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + tx->skb->do_not_encrypt = 0; if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) tx->flags |= IEEE80211_TX_FRAGMENTED; break; @@ -1042,10 +1042,9 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, struct sk_buff *skb, struct net_device *mdev) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct net_device *dev; - dev = dev_get_by_index(&init_net, info->control.ifindex); + dev = dev_get_by_index(&init_net, skb->iif); if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { dev_put(dev); dev = NULL; @@ -1061,13 +1060,14 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_tx_data *tx) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_info *info; int ret, i; - if (netif_subqueue_stopped(local->mdev, skb)) - return IEEE80211_TX_AGAIN; - if (skb) { + if (netif_subqueue_stopped(local->mdev, skb)) + return IEEE80211_TX_AGAIN; + info = IEEE80211_SKB_CB(skb); + ieee80211_dump_frame(wiphy_name(local->hw.wiphy), "TX to low-level driver", skb); ret = local->ops->tx(local_to_hw(local), skb); @@ -1216,6 +1216,7 @@ retry: if (ret == IEEE80211_TX_FRAG_AGAIN) skb = NULL; + set_bit(queue, local->queues_pending); smp_mb(); /* @@ -1300,14 +1301,15 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct net_device *odev = NULL; struct ieee80211_sub_if_data *osdata; int headroom; bool may_encrypt; int ret; - if (info->control.ifindex) - odev = dev_get_by_index(&init_net, info->control.ifindex); + if (skb->iif) + odev = dev_get_by_index(&init_net, skb->iif); if (unlikely(odev && !is_ieee80211_device(odev, dev))) { dev_put(odev); odev = NULL; @@ -1321,9 +1323,27 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, return 0; } + memset(info, 0, sizeof(*info)); + + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; + osdata = IEEE80211_DEV_TO_SUB_IF(odev); - may_encrypt = !(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT); + if (ieee80211_vif_is_mesh(&osdata->vif) && + ieee80211_is_data(hdr->frame_control)) { + if (ieee80211_is_data(hdr->frame_control)) { + if (is_multicast_ether_addr(hdr->addr3)) + memcpy(hdr->addr1, hdr->addr3, ETH_ALEN); + else + if (mesh_nexthop_lookup(skb, odev)) + return 0; + if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0) + IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.sta, + fwded_frames); + } + } + + may_encrypt = !skb->do_not_encrypt; headroom = osdata->local->tx_headroom; if (may_encrypt) @@ -1348,7 +1368,6 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_radiotap_header *prthdr = (struct ieee80211_radiotap_header *)skb->data; u16 len_rthdr; @@ -1371,11 +1390,11 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, skb->dev = local->mdev; /* needed because we set skb device to master */ - info->control.ifindex = dev->ifindex; + skb->iif = dev->ifindex; - info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; - /* Interfaces should always request a status report */ - info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; + /* sometimes we do encrypt injected frames, will be fixed + * up in radiotap parser if not wanted */ + skb->do_not_encrypt = 0; /* * fix up the pointers accounting for the radiotap @@ -1419,7 +1438,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_info *info; struct ieee80211_sub_if_data *sdata; int ret = 1, head_need; u16 ethertype, hdrlen, meshhdrlen = 0; @@ -1469,30 +1487,17 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, case IEEE80211_IF_TYPE_MESH_POINT: fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); /* RA TA DA SA */ - if (is_multicast_ether_addr(skb->data)) - memcpy(hdr.addr1, skb->data, ETH_ALEN); - else if (mesh_nexthop_lookup(hdr.addr1, skb, dev)) - return 0; + memset(hdr.addr1, 0, ETH_ALEN); memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); memcpy(hdr.addr3, skb->data, ETH_ALEN); memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); - if (skb->pkt_type == PACKET_OTHERHOST) { - /* Forwarded frame, keep mesh ttl and seqnum */ - struct ieee80211s_hdr *prev_meshhdr; - prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb); - meshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr); - memcpy(&mesh_hdr, prev_meshhdr, meshhdrlen); - sdata->u.sta.mshstats.fwded_frames++; - } else { - if (!sdata->u.sta.mshcfg.dot11MeshTTL) { - /* Do not send frames with mesh_ttl == 0 */ - sdata->u.sta.mshstats.dropped_frames_ttl++; - ret = 0; - goto fail; - } - meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, - sdata); + if (!sdata->u.sta.mshcfg.dot11MeshTTL) { + /* Do not send frames with mesh_ttl == 0 */ + sdata->u.sta.mshstats.dropped_frames_ttl++; + ret = 0; + goto fail; } + meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata); hdrlen = 30; break; #endif @@ -1540,7 +1545,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, * Drop unicast frames to unauthorised stations unless they are * EAPOL frames from the local station. */ - if (unlikely(!is_multicast_ether_addr(hdr.addr1) && + if (!ieee80211_vif_is_mesh(&sdata->vif) && + unlikely(!is_multicast_ether_addr(hdr.addr1) && !(sta_flags & WLAN_STA_AUTHORIZED) && !(ethertype == ETH_P_PAE && compare_ether_addr(dev->dev_addr, @@ -1645,14 +1651,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, nh_pos += hdrlen; h_pos += hdrlen; - info = IEEE80211_SKB_CB(skb); - memset(info, 0, sizeof(*info)); - info->control.ifindex = dev->ifindex; - if (ethertype == ETH_P_PAE) - info->flags |= IEEE80211_TX_CTL_EAPOL_FRAME; - - /* Interfaces should always request a status report */ - info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; + skb->iif = dev->ifindex; skb->dev = local->mdev; dev->stats.tx_packets++; @@ -1714,14 +1713,19 @@ void ieee80211_tx_pending(unsigned long data) netif_tx_lock_bh(dev); for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) { /* Check that this queue is ok */ - if (__netif_subqueue_stopped(local->mdev, i)) + if (__netif_subqueue_stopped(local->mdev, i) && + !test_bit(i, local->queues_pending_run)) continue; if (!test_bit(i, local->queues_pending)) { + clear_bit(i, local->queues_pending_run); ieee80211_wake_queue(&local->hw, i); continue; } + clear_bit(i, local->queues_pending_run); + netif_start_subqueue(local->mdev, i); + store = &local->pending_packet[i]; tx.extra_frag = store->extra_frag; tx.num_extra_frag = store->num_extra_frag; @@ -1922,6 +1926,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, info = IEEE80211_SKB_CB(skb); + skb->do_not_encrypt = 1; + info->band = band; rate_control_get_rate(local->mdev, sband, skb, &rsel); @@ -1931,7 +1937,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, "no rate found\n", wiphy_name(local->hw.wiphy)); } - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); skb = NULL; goto out; } @@ -1940,7 +1946,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, info->tx_rate_idx = rsel.rate_idx; info->flags |= IEEE80211_TX_CTL_NO_ACK; - info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; if (sdata->bss_conf.use_short_preamble && diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 19f85e1b369..0d463c80c40 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -361,6 +361,7 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) struct ieee80211_local *local = hw_to_local(hw); if (test_bit(queue, local->queues_pending)) { + set_bit(queue, local->queues_pending_run); tasklet_schedule(&local->tx_pending_tasklet); } else { netif_wake_subqueue(local->mdev, queue); diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 872d2fcd1a5..5c2bf0a3d4d 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -31,13 +31,13 @@ int ieee80211_wep_init(struct ieee80211_local *local) local->wep_tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(local->wep_tx_tfm)) - return -ENOMEM; + return PTR_ERR(local->wep_tx_tfm); local->wep_rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(local->wep_rx_tfm)) { crypto_free_blkcipher(local->wep_tx_tfm); - return -ENOMEM; + return PTR_ERR(local->wep_rx_tfm); } return 0; diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 07edda0b8a5..4310e2f6566 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -188,6 +188,9 @@ int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, { int i; + /* XXX: currently broken due to cb/requeue use */ + return -EPERM; + /* prepare the filter and save it for the SW queue * matching the received HW queue */ @@ -238,12 +241,14 @@ void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, } else { struct netdev_queue *txq; spinlock_t *root_lock; + struct Qdisc *q; txq = netdev_get_tx_queue(local->mdev, agg_queue); - root_lock = qdisc_root_lock(txq->qdisc); + q = rcu_dereference(txq->qdisc); + root_lock = qdisc_lock(q); spin_lock_bh(root_lock); - qdisc_reset(txq->qdisc); + qdisc_reset(q); spin_unlock_bh(root_lock); } } |