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 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 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_giwrate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rate, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; struct ieee80211_sub_if_data *sdata; struct ieee80211_supported_band *sband; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == IEEE80211_IF_TYPE_STA) sta = sta_info_get(local, sdata->u.sta.bssid); else return -EOPNOTSUPP; if (!sta) return -ENODEV; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; if (sta->txrate_idx < sband->n_bitrates) rate->value = sband->bitrates[sta->txrate_idx].bitrate; else rate->value = 0; rate->value *= 100000; return 0; }
/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct iw_statistics *wstats = &local->wstats; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta = NULL; rcu_read_lock(); if (sdata->vif.type == NL80211_IFTYPE_STATION || sdata->vif.type == NL80211_IFTYPE_ADHOC) sta = sta_info_get(local, sdata->u.sta.bssid); if (!sta) { wstats->discard.fragment = 0; wstats->discard.misc = 0; wstats->qual.qual = 0; wstats->qual.level = 0; wstats->qual.noise = 0; wstats->qual.updated = IW_QUAL_ALL_INVALID; } else { wstats->qual.level = sta->last_signal; wstats->qual.qual = sta->last_qual; wstats->qual.noise = sta->last_noise; wstats->qual.updated = local->wstats_flags; } rcu_read_unlock(); return wstats; }
static int ieee80211_ioctl_giwrate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rate, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; struct ieee80211_sub_if_data *sdata; struct ieee80211_supported_band *sband; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type != NL80211_IFTYPE_STATION) return -EOPNOTSUPP; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; rcu_read_lock(); sta = sta_info_get(local, sdata->u.sta.bssid); if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate; else rate->value = 0; rcu_read_unlock(); if (!sta) return -ENODEV; rate->value *= 100000; return 0; }
static int ieee80211_ioctl_siwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == IEEE80211_IF_TYPE_STA) sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ if (freq->e == 0) { if (freq->m < 0) { if (sdata->vif.type == IEEE80211_IF_TYPE_STA) sdata->u.sta.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL; return 0; } else return ieee80211_set_freq(local, ieee80211_channel_to_frequency(freq->m)); } else { int i, div = 1000000; for (i = 0; i < freq->e; i++) div /= 10; if (div > 0) return ieee80211_set_freq(local, freq->m / div); else return -EINVAL; } }
static int ieee80211_ioctl_siwpower(struct net_device *dev, struct iw_request_info *info, struct iw_param *wrq, char *extra) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_conf *conf = &local->hw.conf; int ret = 0, timeout = 0; bool ps; if (sdata->vif.type != NL80211_IFTYPE_STATION) return -EINVAL; if (wrq->disabled) { ps = false; timeout = 0; goto set; } switch (wrq->flags & IW_POWER_MODE) { case IW_POWER_ON: /* If not specified */ case IW_POWER_MODE: /* If set all mask */ case IW_POWER_ALL_R: /* If explicitely state all */ ps = true; break; default: /* Otherwise we ignore */ break; } if (wrq->flags & IW_POWER_TIMEOUT) timeout = wrq->value / 1000; set: if (ps == local->powersave && timeout == local->dynamic_ps_timeout) return ret; local->powersave = ps; local->dynamic_ps_timeout = timeout; if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) && local->dynamic_ps_timeout > 0) mod_timer(&local->dynamic_ps_timer, jiffies + msecs_to_jiffies(local->dynamic_ps_timeout)); else { if (local->powersave) conf->flags |= IEEE80211_CONF_PS; else conf->flags &= ~IEEE80211_CONF_PS; } ret = ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); } return ret; }
static int ieee80211_ioctl_giwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); freq->m = local->hw.conf.channel->center_freq; freq->e = 6; return 0; }
static int ieee80211_ioctl_giwpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); wrqu->power.disabled = !local->powersave; return 0; }
static int ieee80211_ioctl_giwrts(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); rts->value = local->rts_threshold; rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD); rts->fixed = 1; return 0; }
static int ieee80211_ioctl_giwfrag(struct net_device *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); frag->value = local->fragmentation_threshold; frag->disabled = (frag->value >= IEEE80211_MAX_RTS_THRESHOLD); frag->fixed = 1; return 0; }
static int ieee80211_ioctl_giwtxpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *data, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); data->txpower.fixed = 1; data->txpower.disabled = !(local->hw.conf.radio_enabled); data->txpower.value = local->hw.conf.power_level; data->txpower.flags = IW_TXPOW_DBM; return 0; }
static struct ieee80211_rate * rate_control_simple_get_rate(void *priv, struct net_device *dev, struct sk_buff *skb, struct rate_control_extra *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_hw_mode *mode = extra->mode; struct sta_info *sta; int rateidx, nonerp_idx; u16 fc; memset(extra, 0, sizeof(*extra)); fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || (hdr->addr1[0] & 0x01)) { /* Send management frames and broadcast/multicast data using * lowest rate. */ /* TODO: this could probably be improved.. */ return rate_control_lowest_rate(local, mode); } sta = sta_info_get(local, hdr->addr1); if (!sta) return rate_control_lowest_rate(local, mode); sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) sta->txrate = sdata->bss->force_unicast_rateidx; rateidx = sta->txrate; if (rateidx >= mode->num_rates) rateidx = mode->num_rates - 1; sta->last_txrate = rateidx; nonerp_idx = rateidx; while (nonerp_idx > 0 && ((mode->rates[nonerp_idx].flags & IEEE80211_RATE_ERP) || !(mode->rates[nonerp_idx].flags & IEEE80211_RATE_SUPPORTED) || !(sta->supp_rates & BIT(nonerp_idx)))) nonerp_idx--; extra->nonerp = &mode->rates[nonerp_idx]; sta_info_put(sta); return &mode->rates[rateidx]; }
struct ath6kl *ath6kl_core_alloc(struct device *sdev) { struct net_device *dev; struct ath6kl *ar; struct wireless_dev *wdev; wdev = ath6kl_cfg80211_init(sdev); if (!wdev) { ath6kl_err("ath6kl_cfg80211_init failed\n"); return NULL; } ar = wdev_priv(wdev); ar->dev = sdev; ar->wdev = wdev; wdev->iftype = NL80211_IFTYPE_STATION; dev = alloc_netdev(0, "wlan%d", ether_setup); if (!dev) { ath6kl_err("no memory for network device instance\n"); ath6kl_cfg80211_deinit(ar); return NULL; } dev->ieee80211_ptr = wdev; SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); wdev->netdev = dev; ar->sme_state = SME_DISCONNECTED; ar->auto_auth_stage = AUTH_IDLE; init_netdev(dev); ar->net_dev = dev; set_bit(WLAN_ENABLED, &ar->flag); ar->wlan_pwr_state = WLAN_POWER_STATE_ON; spin_lock_init(&ar->lock); ath6kl_init_control_info(ar); init_waitqueue_head(&ar->event_wq); sema_init(&ar->sem, 1); clear_bit(DESTROY_IN_PROGRESS, &ar->flag); INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue); setup_timer(&ar->disconnect_timer, disconnect_timer_handler, (unsigned long) dev); return ar; }
static void rate_control_pid_get_rate(void *priv, struct net_device *dev, struct ieee80211_supported_band *sband, struct sk_buff *skb, struct rate_selection *sel) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_sub_if_data *sdata; struct sta_info *sta; int rateidx; u16 fc; rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); /* Send management frames and broadcast/multicast data using lowest * rate. */ fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1) || !sta) { sel->rate = rate_lowest(local, sband, sta); rcu_read_unlock(); return; } /* If a forced rate is in effect, select it. */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) sta->txrate_idx = sdata->bss->force_unicast_rateidx; rateidx = sta->txrate_idx; if (rateidx >= sband->n_bitrates) rateidx = sband->n_bitrates - 1; sta->last_txrate_idx = rateidx; rcu_read_unlock(); sel->rate = &sband->bitrates[rateidx]; #ifdef CONFIG_MAC80211_DEBUGFS rate_control_pid_event_tx_rate( &((struct rc_pid_sta_info *) sta->rate_ctrl_priv)->events, rateidx, sband->bitrates[rateidx].bitrate); #endif }
static int ieee80211_ioctl_siwtxpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *data, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); bool need_reconfig = 0; int new_power_level; if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) return -EINVAL; if (data->txpower.flags & IW_TXPOW_RANGE) return -EINVAL; if (data->txpower.fixed) { new_power_level = data->txpower.value; } else { /* * Automatic power level. Use maximum power for the current * channel. Should be part of rate control. */ struct ieee80211_channel* chan = local->hw.conf.channel; if (!chan) return -EINVAL; new_power_level = chan->max_power; } if (local->hw.conf.power_level != new_power_level) { local->hw.conf.power_level = new_power_level; need_reconfig = 1; } if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { local->hw.conf.radio_enabled = !(data->txpower.disabled); need_reconfig = 1; ieee80211_led_radio(local, local->hw.conf.radio_enabled); } if (need_reconfig) { ieee80211_hw_config(local); /* The return value of hw_config is not of big interest here, * as it doesn't say that it failed because of _this_ config * change or something else. Ignore it. */ } return 0; }
static int ieee80211_ioctl_giwscan(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) { int res; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); if (local->sta_sw_scanning || local->sta_hw_scanning) return -EAGAIN; res = ieee80211_sta_scan_results(dev, extra, data->length); if (res >= 0) { data->length = res; return 0; } data->length = 0; return res; }
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->fixed) 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; } return 0; }
/** * mesh_send_path error - Sends a PERR mesh management frame * * @dst: broken destination * @dst_dsn: dsn of the broken destination * @ra: node this frame is addressed to */ int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); struct ieee80211_mgmt *mgmt; u8 *pos; int ie_len; if (!skb) return -1; skb_reserve(skb, local->hw.extra_tx_headroom); /* 25 is the size of the common mgmt part (24) plus the size of the * common action part (1) */ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action)); memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action)); mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, IEEE80211_STYPE_ACTION); memcpy(mgmt->da, ra, ETH_ALEN); memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); /* BSSID is left zeroed, wildcard value */ mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; mgmt->u.action.u.mesh_action.action_code = MPATH_PERR; ie_len = 12; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PERR; *pos++ = ie_len; /* mode flags, reserved */ *pos++ = 0; /* number of destinations */ *pos++ = 1; memcpy(pos, dst, ETH_ALEN); pos += ETH_ALEN; memcpy(pos, &dst_dsn, 4); ieee80211_sta_tx(dev, skb, 0); return 0; }
static int ieee80211_ioctl_giwscan(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) { int res; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (local->sw_scanning || local->hw_scanning) return -EAGAIN; res = ieee80211_scan_results(local, info, extra, data->length); if (res >= 0) { data->length = res; return 0; } data->length = 0; return res; }
static int ieee80211_ioctl_siwrate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rate, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); int i, err = -EINVAL; u32 target_rate = rate->value / 100000; struct ieee80211_sub_if_data *sdata; struct ieee80211_supported_band *sband; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (!sdata->bss) return -ENODEV; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates * target_rate = X, rate->fixed = 1 means only rate X * target_rate = X, rate->fixed = 0 means all rates <= X */ sdata->bss->max_ratectrl_rateidx = -1; sdata->bss->force_unicast_rateidx = -1; if (rate->value < 0) return 0; for (i=0; i< sband->n_bitrates; i++) { struct ieee80211_rate *brate = &sband->bitrates[i]; int this_rate = brate->bitrate; if (target_rate == this_rate) { sdata->bss->max_ratectrl_rateidx = i; if (rate->fixed) sdata->bss->force_unicast_rateidx = i; err = 0; break; } } return err; }
static int ieee80211_ioctl_giwretry(struct net_device *dev, struct iw_request_info *info, struct iw_param *retry, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); retry->disabled = 0; if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) { /* first return min value, iwconfig will ask max value * later if needed */ retry->flags |= IW_RETRY_LIMIT; retry->value = local->short_retry_limit; if (local->long_retry_limit != local->short_retry_limit) retry->flags |= IW_RETRY_MIN; return 0; } if (retry->flags & IW_RETRY_MAX) { retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; retry->value = local->long_retry_limit; } return 0; }
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->hw.conf.long_frame_max_tx_count = retry->value; } else if (retry->flags & IW_RETRY_MIN) { local->hw.conf.short_frame_max_tx_count = retry->value; } else { local->hw.conf.long_frame_max_tx_count = retry->value; local->hw.conf.short_frame_max_tx_count = retry->value; } ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); return 0; }
static int ieee80211_ioctl_siwtxpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *data, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_channel* chan = local->hw.conf.channel; u32 reconf_flags = 0; int new_power_level; if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) return -EINVAL; if (data->txpower.flags & IW_TXPOW_RANGE) return -EINVAL; if (!chan) return -EINVAL; if (data->txpower.fixed) new_power_level = min(data->txpower.value, chan->max_power); else /* Automatic power level setting */ new_power_level = chan->max_power; if (local->hw.conf.power_level != new_power_level) { local->hw.conf.power_level = new_power_level; reconf_flags |= IEEE80211_CONF_CHANGE_POWER; } if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { local->hw.conf.radio_enabled = !(data->txpower.disabled); reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED; ieee80211_led_radio(local, local->hw.conf.radio_enabled); } if (reconf_flags) ieee80211_hw_config(local, reconf_flags); return 0; }
/** * lbs_add_card - adds the card. It will probe the * card, allocate the lbs_priv and initialize the device. * * @card: A pointer to card * @dmdev: A pointer to &struct device * returns: A pointer to &struct lbs_private structure */ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) { struct net_device *dev; struct wireless_dev *wdev; struct lbs_private *priv = NULL; lbs_deb_enter(LBS_DEB_MAIN); /* Allocate an Ethernet device and register it */ wdev = lbs_cfg_alloc(dmdev); if (IS_ERR(wdev)) { pr_err("cfg80211 init failed\n"); goto done; } wdev->iftype = NL80211_IFTYPE_STATION; priv = wdev_priv(wdev); priv->wdev = wdev; if (lbs_init_adapter(priv)) { pr_err("failed to initialize adapter structure\n"); goto err_wdev; } dev = alloc_netdev(0, "wlan%d", ether_setup); if (!dev) { dev_err(dmdev, "no memory for network device instance\n"); goto err_adapter; } dev->ieee80211_ptr = wdev; dev->ml_priv = priv; SET_NETDEV_DEV(dev, dmdev); wdev->netdev = dev; priv->dev = dev; dev->netdev_ops = &lbs_netdev_ops; dev->watchdog_timeo = 5 * HZ; dev->ethtool_ops = &lbs_ethtool_ops; dev->flags |= IFF_BROADCAST | IFF_MULTICAST; priv->card = card; strcpy(dev->name, "wlan%d"); lbs_deb_thread("Starting main thread...\n"); init_waitqueue_head(&priv->waitq); priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main"); if (IS_ERR(priv->main_thread)) { lbs_deb_thread("Error creating main thread.\n"); goto err_ndev; } priv->work_thread = create_singlethread_workqueue("lbs_worker"); INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); priv->wol_criteria = EHS_REMOVE_WAKEUP; priv->wol_gpio = 0xff; priv->wol_gap = 20; priv->ehs_remove_supported = true; goto done; err_ndev: free_netdev(dev); err_adapter: lbs_free_adapter(priv); err_wdev: lbs_cfg_free(priv); priv = NULL; done: lbs_deb_leave_args(LBS_DEB_MAIN, "priv %p", priv); return priv; }
static ssize_t sta_agg_status_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct sta_info *sta = file->private_data; struct net_device *dev = sta->sdata->dev; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hw *hw = &local->hw; u8 *da = sta->addr; static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static int tid_static_rx[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; char *endp; char buf[32]; int buf_size, rs; unsigned int tid_num; char state[4]; memset(buf, 0x00, sizeof(buf)); buf_size = min(count, (sizeof(buf)-1)); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; tid_num = simple_strtoul(buf, &endp, 0); if (endp == buf) return -EINVAL; if ((tid_num >= 100) && (tid_num <= 115)) { /* toggle Rx aggregation command */ tid_num = tid_num - 100; if (tid_static_rx[tid_num] == 1) { strcpy(state, "off "); ieee80211_sta_stop_rx_ba_session(dev, da, tid_num, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); sta->ampdu_mlme.tid_state_rx[tid_num] |= HT_AGG_STATE_DEBUGFS_CTL; tid_static_rx[tid_num] = 0; } else { strcpy(state, "on "); sta->ampdu_mlme.tid_state_rx[tid_num] &= ~HT_AGG_STATE_DEBUGFS_CTL; tid_static_rx[tid_num] = 1; } printk(KERN_DEBUG "debugfs - try switching tid %u %s\n", tid_num, state); } else if ((tid_num >= 0) && (tid_num <= 15)) { /* toggle Tx aggregation command */ if (tid_static_tx[tid_num] == 0) { strcpy(state, "on "); rs = ieee80211_start_tx_ba_session(hw, da, tid_num); if (rs == 0) tid_static_tx[tid_num] = 1; } else { strcpy(state, "off"); rs = ieee80211_stop_tx_ba_session(hw, da, tid_num, 1); if (rs == 0) tid_static_tx[tid_num] = 0; } printk(KERN_DEBUG "debugfs - switching tid %u %s, return=%d\n", tid_num, state, rs); } return count; }
static void rate_control_pid_tx_status(void *priv, struct net_device *dev, struct sk_buff *skb, struct ieee80211_tx_status *status) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_sub_if_data *sdata; struct rc_pid_info *pinfo = priv; struct sta_info *sta; struct rc_pid_sta_info *spinfo; unsigned long period; struct ieee80211_supported_band *sband; rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; if (!sta) goto unlock; /* Don't update the state if we're not controlling the rate. */ sdata = sta->sdata; if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { sta->txrate_idx = sdata->bss->max_ratectrl_rateidx; goto unlock; } /* Ignore all frames that were sent with a different rate than the rate * we currently advise mac80211 to use. */ if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) goto unlock; spinfo = sta->rate_ctrl_priv; spinfo->tx_num_xmit++; #ifdef CONFIG_MAC80211_DEBUGFS rate_control_pid_event_tx_status(&spinfo->events, status); #endif /* We count frames that totally failed to be transmitted as two bad * frames, those that made it out but had some retries as one good and * one bad frame. */ if (status->excessive_retries) { spinfo->tx_num_failed += 2; spinfo->tx_num_xmit++; } else if (status->retry_count) { spinfo->tx_num_failed++; spinfo->tx_num_xmit++; } if (status->excessive_retries) { sta->tx_retry_failed++; sta->tx_num_consecutive_failures++; sta->tx_num_mpdu_fail++; } else { sta->tx_num_consecutive_failures = 0; sta->tx_num_mpdu_ok++; } sta->tx_retry_count += status->retry_count; sta->tx_num_mpdu_fail += status->retry_count; /* Update PID controller state. */ period = (HZ * pinfo->sampling_period + 500) / 1000; if (!period) period = 1; if (time_after(jiffies, spinfo->last_sample + period)) rate_control_pid_sample(pinfo, local, sta); unlock: rcu_read_unlock(); }
static inline void *ar6k_priv(struct net_device *dev) { return wdev_priv(dev->ieee80211_ptr); }
static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, u8 *orig_addr, __le32 orig_dsn, u8 dst_flags, u8 *dst, __le32 dst_dsn, u8 *da, u8 hop_count, u8 ttl, __le32 lifetime, __le32 metric, __le32 preq_id, struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); struct ieee80211_mgmt *mgmt; u8 *pos; int ie_len; if (!skb) return -1; skb_reserve(skb, local->hw.extra_tx_headroom); /* 25 is the size of the common mgmt part (24) plus the size of the * common action part (1) */ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action)); memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action)); mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, IEEE80211_STYPE_ACTION); memcpy(mgmt->da, da, ETH_ALEN); memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); /* BSSID is left zeroed, wildcard value */ mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; mgmt->u.action.u.mesh_action.action_code = action; switch (action) { case MPATH_PREQ: ie_len = 37; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PREQ; break; case MPATH_PREP: ie_len = 31; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PREP; break; default: kfree(skb); return -ENOTSUPP; break; } *pos++ = ie_len; *pos++ = flags; *pos++ = hop_count; *pos++ = ttl; if (action == MPATH_PREQ) { memcpy(pos, &preq_id, 4); pos += 4; } memcpy(pos, orig_addr, ETH_ALEN); pos += ETH_ALEN; memcpy(pos, &orig_dsn, 4); pos += 4; memcpy(pos, &lifetime, 4); pos += 4; memcpy(pos, &metric, 4); pos += 4; if (action == MPATH_PREQ) { /* destination count */ *pos++ = 1; *pos++ = dst_flags; } memcpy(pos, dst, ETH_ALEN); pos += ETH_ALEN; memcpy(pos, &dst_dsn, 4); ieee80211_sta_tx(dev, skb, 0); return 0; }