static void ieee80211_tasklet_handler(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *) data; struct sk_buff *skb; while ((skb = skb_dequeue(&local->skb_queue)) || (skb = skb_dequeue(&local->skb_queue_unreliable))) { switch (skb->pkt_type) { case IEEE80211_RX_MSG: /* Clear skb->pkt_type in order to not confuse kernel * netstack. */ skb->pkt_type = 0; ieee80211_rx(local_to_hw(local), skb); break; case IEEE80211_TX_STATUS_MSG: skb->pkt_type = 0; ieee80211_tx_status(local_to_hw(local), skb); break; default: WARN(1, "mac80211: Packet is of unknown type %d\n", skb->pkt_type); dev_kfree_skb(skb); break; } } }
static int ieee80211_ioctl_siwrts(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); if (rts->disabled) local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; else if (!rts->fixed) /* if the rts value is not fixed, then take default */ local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD) return -EINVAL; else local->rts_threshold = rts->value; /* If the wlan card performs RTS/CTS in hardware/firmware, * configure it here */ if (local->ops->set_rts_threshold) local->ops->set_rts_threshold(local_to_hw(local), local->rts_threshold); return 0; }
static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) { const u8 *addr; int ret; DECLARE_MAC_BUF(mac); assert_key_lock(); might_sleep(); if (!key->local->ops->set_key) return; addr = get_mac_for_key(key); ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY, key->sdata->dev->dev_addr, addr, &key->conf); if (!ret) { spin_lock(&todo_lock); key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; spin_unlock(&todo_lock); } if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) printk(KERN_ERR "mac80211-%s: failed to set key " "(%d, %s) to hardware (%d)\n", wiphy_name(key->local->hw.wiphy), key->conf.keyidx, print_mac(mac, addr), ret); }
static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) { const u8 *addr; int ret; DECLARE_MAC_BUF(mac); assert_key_lock(); might_sleep(); if (!key || !key->local->ops->set_key) return; spin_lock(&todo_lock); if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { spin_unlock(&todo_lock); return; } spin_unlock(&todo_lock); addr = get_mac_for_key(key); ret = key->local->ops->set_key(local_to_hw(key->local), DISABLE_KEY, key->sdata->dev->dev_addr, addr, &key->conf); if (ret) printk(KERN_ERR "mac80211-%s: failed to remove key " "(%d, %s) from hardware (%d)\n", wiphy_name(key->local->hw.wiphy), key->conf.keyidx, print_mac(mac, addr), ret); spin_lock(&todo_lock); key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; spin_unlock(&todo_lock); }
static int ieee80211_ioctl_siwretry(struct net_device *dev, struct iw_request_info *info, struct iw_param *retry, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); if (retry->disabled || (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) return -EINVAL; if (retry->flags & IW_RETRY_MAX) local->long_retry_limit = retry->value; else if (retry->flags & IW_RETRY_MIN) local->short_retry_limit = retry->value; else { local->long_retry_limit = retry->value; local->short_retry_limit = retry->value; } if (local->ops->set_retry_limit) { return local->ops->set_retry_limit( local_to_hw(local), local->short_retry_limit, local->long_retry_limit); } return 0; }
static int ieee80211_ioctl_siwfrag(struct net_device *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); if (frag->disabled) local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; else if (frag->value < 256 || frag->value > IEEE80211_MAX_FRAG_THRESHOLD) return -EINVAL; else { /* Fragment length must be even, so strip LSB. */ local->fragmentation_threshold = frag->value & ~0x1; } /* If the wlan card performs fragmentation in hardware/firmware, * configure it here */ if (local->ops->set_frag_threshold) local->ops->set_frag_threshold( local_to_hw(local), local->fragmentation_threshold); return 0; }
static ssize_t ieee80211_stats_show(struct class_device *dev, char *buf, ssize_t (*format)(struct ieee80211_low_level_stats *, char *)) { struct ieee80211_local *local = to_ieee80211_local(dev); struct ieee80211_low_level_stats stats; ssize_t ret = -EINVAL; if (!local->ops->get_stats) return -EOPNOTSUPP; ret = rtnl_lock_local(local); if (ret) return ret; ret = local->ops->get_stats(local_to_hw(local), &stats); rtnl_unlock(); if (!ret) ret = (*format)(&stats, buf); return ret; }
static ssize_t format_devstat_counter(struct ieee80211_local *local, char __user *userbuf, size_t count, loff_t *ppos, int (*printvalue)(struct ieee80211_low_level_stats *stats, char *buf, int buflen)) { struct ieee80211_low_level_stats stats; char buf[20]; int res; if (!local->ops->get_stats) return -EOPNOTSUPP; rtnl_lock(); res = local->ops->get_stats(local_to_hw(local), &stats); rtnl_unlock(); if (!res) res = printvalue(&stats, buf, sizeof(buf)); return simple_read_from_buffer(userbuf, count, ppos, buf, res); }
int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, struct sta_info *sta, u16 tid) { 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 */ if (!local->hw.ampdu_queues) return -EPERM; /* try to get a Qdisc from the pool */ for (i = local->hw.queues; i < ieee80211_num_queues(&local->hw); i++) if (!test_and_set_bit(i, local->queue_pool)) { ieee80211_stop_queue(local_to_hw(local), i); sta->tid_to_tx_q[tid] = i; /* IF there are already pending packets * on this tid first we need to drain them * on the previous queue * since HT is strict in order */ #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) { DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "allocated aggregation queue" " %d tid %d addr %s pool=0x%lX\n", i, tid, print_mac(mac, sta->sta.addr), local->queue_pool[0]); } #endif /* CONFIG_MAC80211_HT_DEBUG */ return 0; } return -EAGAIN; }
const struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,const struct ieee80211_ops *ops) { struct net_device *mdev; struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; int priv_size; //struct wiphy *wiphy; priv_size = ((sizeof(struct ieee80211_local) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) + priv_data_len; /* wiphy = wiphy_new(&mac80211_config_ops, priv_size); if (!wiphy) return NULL; wiphy->privid = mac80211_wiphy_privid; local = wiphy_priv(wiphy); local->hw.wiphy = wiphy; */ local=(struct ieee80211_local*)IOMalloc(priv_size); memset(local,0,priv_size); local->hw.priv = (char*)local + ((sizeof(struct ieee80211_local) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); local->ops = ops; /* for now, mdev needs sub_if_data :/ */ /* mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "wmaster%d", ether_setup); if (!mdev) { wiphy_free(wiphy); return NULL; } sdata = IEEE80211_DEV_TO_SUB_IF(mdev); mdev->ieee80211_ptr = &sdata->wdev; sdata->wdev.wiphy = wiphy; */ mdev=(struct net_device*)IOMalloc(sizeof(struct ieee80211_sub_if_data)); memset(mdev,0,sizeof(struct ieee80211_sub_if_data)); sdata = (struct ieee80211_sub_if_data*)netdev_priv(mdev); mdev->ieee80211_ptr=local; local->mdev=mdev; local->hw.queues = 1; /* default */ /* local->mdev = mdev; local->rx_pre_handlers = ieee80211_rx_pre_handlers; local->rx_handlers = ieee80211_rx_handlers; local->tx_handlers = ieee80211_tx_handlers; */ local->bridge_packets = 1; local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; local->short_retry_limit = 7; local->long_retry_limit = 4; local->hw.conf.radio_enabled = 1; //local->rate_ctrl_num_up = RATE_CONTROL_NUM_UP; //local->rate_ctrl_num_down = RATE_CONTROL_NUM_DOWN; local->enabled_modes = (unsigned int) -1; INIT_LIST_HEAD(&local->modes_list); // rwlock_init(&local->sub_if_lock); INIT_LIST_HEAD(&local->sub_if_list); // INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); // init_timer(&local->stat_timer); // local->stat_timer.function = ieee80211_stat_refresh; //local->stat_timer.data = (unsigned long) local; // ieee80211_rx_bss_list_init(mdev); //sta_info_init(local); INIT_LIST_HEAD(&local->sta_list); INIT_LIST_HEAD(&local->deleted_sta_list); //local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; //local->sta_cleanup.data = (unsigned long) local; /* mdev->hard_start_xmit = ieee80211_master_start_xmit; mdev->open = ieee80211_master_open; mdev->stop = ieee80211_master_stop; mdev->type = ARPHRD_IEEE80211; mdev->hard_header_parse = header_parse_80211;*/ sdata->type = IEEE80211_IF_TYPE_AP; sdata->dev = mdev; sdata->local = local; sdata->u.ap.force_unicast_rateidx = -1; sdata->u.ap.max_ratectrl_rateidx = -1; ieee80211_if_sdata_init(sdata); list_add_tail(&sdata->list, &local->sub_if_list); /* tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, (unsigned long)local); tasklet_disable(&local->tx_pending_tasklet); tasklet_init(&local->tasklet, ieee80211_tasklet_handler, (unsigned long) local); tasklet_disable(&local->tasklet); skb_queue_head_init(&local->skb_queue); skb_queue_head_init(&local->skb_queue_unreliable); */ //INIT_LIST_HEAD(&local->skb_queue); //INIT_LIST_HEAD(&local->skb_queue_unreliable); return local_to_hw(local); }
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops) { struct ieee80211_local *local; int priv_size, i; struct wiphy *wiphy; /* Ensure 32-byte alignment of our private data and hw private data. * We use the wiphy priv data for both our ieee80211_local and for * the driver's private data * * In memory it'll be like this: * * +-------------------------+ * | struct wiphy | * +-------------------------+ * | struct ieee80211_local | * +-------------------------+ * | driver's private data | * +-------------------------+ * */ priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; wiphy = wiphy_new(&mac80211_config_ops, priv_size); if (!wiphy) return NULL; wiphy->mgmt_stypes = ieee80211_default_mgmt_stypes; wiphy->privid = mac80211_wiphy_privid; wiphy->flags |= WIPHY_FLAG_NETNS_OK | WIPHY_FLAG_4ADDR_AP | WIPHY_FLAG_4ADDR_STATION; if (!ops->set_key) wiphy->flags |= WIPHY_FLAG_IBSS_RSN; wiphy->bss_priv_size = sizeof(struct ieee80211_bss); local = wiphy_priv(wiphy); local->hw.wiphy = wiphy; local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); BUG_ON(!ops->tx); BUG_ON(!ops->start); BUG_ON(!ops->stop); BUG_ON(!ops->config); BUG_ON(!ops->add_interface); BUG_ON(!ops->remove_interface); BUG_ON(!ops->configure_filter); local->ops = ops; /* set up some defaults */ local->hw.queues = 1; local->hw.max_rates = 1; local->hw.max_report_rates = 0; local->hw.max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; local->user_power_level = -1; local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; INIT_LIST_HEAD(&local->interfaces); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) __hw_addr_init(&local->mc_list); #endif mutex_init(&local->iflist_mtx); mutex_init(&local->mtx); mutex_init(&local->key_mtx); spin_lock_init(&local->filter_lock); spin_lock_init(&local->queue_stop_reason_lock); /* * The rx_skb_queue is only accessed from tasklets, * but other SKB queues are used from within IRQ * context. Therefore, this one needs a different * locking class so our direct, non-irq-safe use of * the queue's lock doesn't throw lockdep warnings. */ skb_queue_head_init_class(&local->rx_skb_queue, &ieee80211_rx_skb_queue_class); INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); ieee80211_work_init(local); INIT_WORK(&local->restart_work, ieee80211_restart_work); INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work); local->smps_mode = IEEE80211_SMPS_OFF; INIT_WORK(&local->dynamic_ps_enable_work, ieee80211_dynamic_ps_enable_work); INIT_WORK(&local->dynamic_ps_disable_work, ieee80211_dynamic_ps_disable_work); setup_timer(&local->dynamic_ps_timer, ieee80211_dynamic_ps_timer, (unsigned long) local); INIT_WORK(&local->sched_scan_stopped_work, ieee80211_sched_scan_stopped_work); sta_info_init(local); for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { skb_queue_head_init(&local->pending[i]); atomic_set(&local->agg_queue_stop[i], 0); } tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, (unsigned long)local); tasklet_init(&local->tasklet, ieee80211_tasklet_handler, (unsigned long) local); skb_queue_head_init(&local->skb_queue); skb_queue_head_init(&local->skb_queue_unreliable); /* init dummy netdev for use w/ NAPI */ init_dummy_netdev(&local->napi_dev); ieee80211_led_names(local); ieee80211_hw_roc_setup(local); return local_to_hw(local); }
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops) { struct ieee80211_local *local; int priv_size, i; struct wiphy *wiphy; /* Ensure 32-byte alignment of our private data and hw private data. * We use the wiphy priv data for both our ieee80211_local and for * the driver's private data * * In memory it'll be like this: * * +-------------------------+ * | struct wiphy | * +-------------------------+ * | struct ieee80211_local | * +-------------------------+ * | driver's private data | * +-------------------------+ * */ priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; wiphy = wiphy_new(&mac80211_config_ops, priv_size); if (!wiphy) return NULL; wiphy->flags |= WIPHY_FLAG_NETNS_OK | WIPHY_FLAG_4ADDR_AP | WIPHY_FLAG_4ADDR_STATION; wiphy->privid = mac80211_wiphy_privid; wiphy->bss_priv_size = sizeof(struct ieee80211_bss); local = wiphy_priv(wiphy); local->hw.wiphy = wiphy; local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); BUG_ON(!ops->tx); BUG_ON(!ops->start); BUG_ON(!ops->stop); BUG_ON(!ops->config); BUG_ON(!ops->add_interface); BUG_ON(!ops->remove_interface); BUG_ON(!ops->configure_filter); local->ops = ops; /* set up some defaults */ local->hw.queues = 1; local->hw.max_rates = 1; local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; local->user_power_level = -1; local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; INIT_LIST_HEAD(&local->interfaces); __hw_addr_init(&local->mc_list); mutex_init(&local->iflist_mtx); mutex_init(&local->scan_mtx); mutex_init(&local->key_mtx); spin_lock_init(&local->filter_lock); spin_lock_init(&local->queue_stop_reason_lock); INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); ieee80211_work_init(local); INIT_WORK(&local->restart_work, ieee80211_restart_work); INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work); local->smps_mode = IEEE80211_SMPS_OFF; INIT_WORK(&local->dynamic_ps_enable_work, ieee80211_dynamic_ps_enable_work); INIT_WORK(&local->dynamic_ps_disable_work, ieee80211_dynamic_ps_disable_work); setup_timer(&local->dynamic_ps_timer, ieee80211_dynamic_ps_timer, (unsigned long) local); sta_info_init(local); for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { skb_queue_head_init(&local->pending[i]); atomic_set(&local->agg_queue_stop[i], 0); } tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, (unsigned long)local); tasklet_init(&local->tasklet, ieee80211_tasklet_handler, (unsigned long) local); skb_queue_head_init(&local->skb_queue); skb_queue_head_init(&local->skb_queue_unreliable); return local_to_hw(local); }