static int ieee80211_ioctl_giwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) { size_t len; struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == IEEE80211_IF_TYPE_STA || sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { int res = ieee80211_sta_get_ssid(dev, ssid, &len); if (res == 0) { data->length = len; data->flags = 1; } else data->flags = 0; return res; } if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { len = sdata->u.ap.ssid_len; if (len > IW_ESSID_MAX_SIZE) len = IW_ESSID_MAX_SIZE; memcpy(ssid, sdata->u.ap.ssid, len); data->length = len; data->flags = 1; return 0; } return -EOPNOTSUPP; }
static int ieee80211_ioctl_siwscan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct iw_scan_req *req = NULL; u8 *ssid = NULL; size_t ssid_len = 0; if (!netif_running(dev)) return -ENETDOWN; if (sdata->vif.type != NL80211_IFTYPE_STATION && sdata->vif.type != NL80211_IFTYPE_ADHOC && sdata->vif.type != NL80211_IFTYPE_MESH_POINT) return -EOPNOTSUPP; /* if SSID was specified explicitly then use that */ if (wrqu->data.length == sizeof(struct iw_scan_req) && wrqu->data.flags & IW_SCAN_THIS_ESSID) { req = (struct iw_scan_req *)extra; ssid = req->essid; ssid_len = req->essid_len; } return ieee80211_request_scan(sdata, ssid, ssid_len); }
static int ieee80211_ioctl_siwmode(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); int type; if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) return -EOPNOTSUPP; switch (*mode) { case IW_MODE_INFRA: type = IEEE80211_IF_TYPE_STA; break; case IW_MODE_ADHOC: type = IEEE80211_IF_TYPE_IBSS; break; case IW_MODE_MONITOR: type = IEEE80211_IF_TYPE_MNTR; break; default: return -EINVAL; } if (type == sdata->vif.type) return 0; if (netif_running(dev)) return -EBUSY; ieee80211_if_reinit(dev); ieee80211_if_set_type(dev, type); return 0; }
static int netdev_notify(struct notifier_block *nb, unsigned long state, void *ndev) { struct net_device *dev = ndev; struct dentry *dir; struct ieee80211_sub_if_data *sdata; char buf[10+IFNAMSIZ]; if (state != NETDEV_CHANGENAME) return 0; if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) return 0; if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) return 0; sdata = IEEE80211_DEV_TO_SUB_IF(dev); dir = sdata->debugfsdir; if (!dir) return 0; sprintf(buf, "netdev:%s", dev->name); if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " "dir to %s\n", buf); return 0; }
static int ieee80211_ioctl_siwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) { struct ieee80211_sub_if_data *sdata; size_t len = data->length; /* iwconfig uses nul termination in SSID.. */ if (len > 0 && ssid[len - 1] == '\0') len--; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_STATION || sdata->vif.type == NL80211_IFTYPE_ADHOC) { int ret; if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { if (len > IEEE80211_MAX_SSID_LEN) return -EINVAL; memcpy(sdata->u.sta.ssid, ssid, len); sdata->u.sta.ssid_len = len; return 0; } if (data->flags) sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; else sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL; ret = ieee80211_sta_set_ssid(sdata, ssid, len); if (ret) return ret; ieee80211_sta_req_auth(sdata, &sdata->u.sta); return 0; } return -EOPNOTSUPP; }
static int ieee80211_ioctl_giwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_STATION || sdata->vif.type == NL80211_IFTYPE_ADHOC) { if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATED || sdata->u.sta.state == IEEE80211_STA_MLME_IBSS_JOINED) { ap_addr->sa_family = ARPHRD_ETHER; memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN); return 0; } else { memset(&ap_addr->sa_data, 0, ETH_ALEN); return 0; } } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { ap_addr->sa_family = ARPHRD_ETHER; memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); return 0; } return -EOPNOTSUPP; }
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; }
void mesh_path_timer(unsigned long data) { struct ieee80211_sub_if_data *sdata; struct mesh_path *mpath; rcu_read_lock(); mpath = (struct mesh_path *) data; mpath = rcu_dereference(mpath); if (!mpath) goto endmpathtimer; spin_lock_bh(&mpath->state_lock); sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev); if (mpath->flags & MESH_PATH_RESOLVED || (!(mpath->flags & MESH_PATH_RESOLVING))) mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED); else if (mpath->discovery_retries < max_preq_retries(sdata)) { ++mpath->discovery_retries; mpath->discovery_timeout *= 2; mesh_queue_preq(mpath, 0); } else { mpath->flags = 0; mpath->exp_time = jiffies; mesh_path_flush_pending(mpath); } spin_unlock_bh(&mpath->state_lock); endmpathtimer: rcu_read_unlock(); }
static int ieee80211_ioctl_giwmode(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra) { struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); switch (sdata->vif.type) { case IEEE80211_IF_TYPE_AP: *mode = IW_MODE_MASTER; break; case IEEE80211_IF_TYPE_STA: *mode = IW_MODE_INFRA; break; case IEEE80211_IF_TYPE_IBSS: *mode = IW_MODE_ADHOC; break; case IEEE80211_IF_TYPE_MNTR: *mode = IW_MODE_MONITOR; break; case IEEE80211_IF_TYPE_WDS: *mode = IW_MODE_REPEAT; break; case IEEE80211_IF_TYPE_VLAN: *mode = IW_MODE_SECOND; /* FIXME */ break; default: *mode = IW_MODE_AUTO; break; } 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_siwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_STATION) 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 == NL80211_IFTYPE_STATION) sdata->u.sta.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL; return 0; } else return ieee80211_set_freq(sdata, 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(sdata, freq->m / div); else return -EINVAL; } }
static void rate_control_rate_dec(struct ieee80211_local *local, struct sta_info *sta) { struct ieee80211_sub_if_data *sdata; struct ieee80211_hw_mode *mode; int i = sta->txrate; sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { /* forced unicast rate - do not change STA rate */ return; } mode = local->oper_hw_mode; if (i > mode->num_rates) i = mode->num_rates; while (i > 0) { i--; if (sta->supp_rates & BIT(i) && mode->rates[i].flags & IEEE80211_RATE_SUPPORTED) { sta->txrate = i; break; } } }
/* Adjust the rate while ensuring that we won't switch to a lower rate if it * exhibited a worse failed frames behaviour and we'll choose the highest rate * whose failed frames behaviour is not worse than the one of the original rate * target. While at it, check that the new rate is valid. */ static void rate_control_pid_adjust_rate(struct ieee80211_local *local, struct sta_info *sta, int adj, struct rc_pid_rateinfo *rinfo) { struct ieee80211_sub_if_data *sdata; struct ieee80211_hw_mode *mode; int cur_sorted, new_sorted, probe, tmp, n_bitrates; int cur = sta->txrate; sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); mode = local->oper_hw_mode; n_bitrates = mode->num_rates; /* Map passed arguments to sorted values. */ cur_sorted = rinfo[cur].rev_index; new_sorted = cur_sorted + adj; /* Check limits. */ if (new_sorted < 0) new_sorted = rinfo[0].rev_index; else if (new_sorted >= n_bitrates) new_sorted = rinfo[n_bitrates - 1].rev_index; tmp = new_sorted; if (adj < 0) { /* Ensure that the rate decrease isn't disadvantageous. */ for (probe = cur_sorted; probe >= new_sorted; probe--) if (rinfo[probe].diff <= rinfo[cur_sorted].diff && rate_supported(sta, mode, rinfo[probe].index)) tmp = probe; } else { /* Look for rate increase with zero (or below) cost. */ for (probe = new_sorted + 1; probe < n_bitrates; probe++) if (rinfo[probe].diff <= rinfo[new_sorted].diff && rate_supported(sta, mode, rinfo[probe].index)) tmp = probe; } /* Fit the rate found to the nearest supported rate. */ do { if (rate_supported(sta, mode, rinfo[tmp].index)) { sta->txrate = rinfo[tmp].index; break; } if (adj < 0) tmp--; else tmp++; } while (tmp < n_bitrates && tmp >= 0); #ifdef CONFIG_MAC80211_DEBUGFS rate_control_pid_event_rate_change( &((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events, cur, mode->rates[cur].rate); #endif }
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; }
/** * 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 * @dev: network device the frame will be sent through * * 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) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sk_buff *skb_to_free = NULL; struct mesh_path *mpath; int err = 0; rcu_read_lock(); mpath = mesh_path_lookup(skb->data, dev); if (!mpath) { mesh_path_add(skb->data, dev); mpath = mesh_path_lookup(skb->data, dev); if (!mpath) { dev_kfree_skb(skb); sdata->u.sta.mshstats.dropped_frames_no_route++; err = -ENOSPC; goto endlookup; } } 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 && !(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, ETH_ALEN); } else { if (!(mpath->flags & MESH_PATH_RESOLVING)) { /* Start discovery only if it is not running yet */ mesh_queue_preq(mpath, PREQ_Q_F_START); } if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN) { skb_to_free = mpath->frame_queue.next; skb_unlink(skb_to_free, &mpath->frame_queue); } skb_queue_tail(&mpath->frame_queue, skb); if (skb_to_free) mesh_path_discard_frame(skb_to_free, dev); err = -ENOENT; } endlookup: rcu_read_unlock(); return err; }
static int ieee80211_ioctl_giwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { struct ieee80211_sub_if_data *sdata; int idx, i; sdata = IEEE80211_DEV_TO_SUB_IF(dev); idx = erq->flags & IW_ENCODE_INDEX; if (idx < 1 || idx > 4) { idx = -1; if (!sdata->default_key) idx = 0; else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { if (sdata->default_key == sdata->keys[i]) { idx = i; break; } } if (idx < 0) return -EINVAL; } else idx--; erq->flags = idx + 1; if (!sdata->keys[idx]) { erq->length = 0; erq->flags |= IW_ENCODE_DISABLED; return 0; } memcpy(key, sdata->keys[idx]->conf.key, min_t(int, erq->length, sdata->keys[idx]->conf.keylen)); erq->length = sdata->keys[idx]->conf.keylen; erq->flags |= IW_ENCODE_ENABLED; if (sdata->vif.type == NL80211_IFTYPE_STATION) { struct ieee80211_if_sta *ifsta = &sdata->u.sta; switch (ifsta->auth_alg) { case WLAN_AUTH_OPEN: case WLAN_AUTH_LEAP: erq->flags |= IW_ENCODE_OPEN; break; case WLAN_AUTH_SHARED_KEY: erq->flags |= IW_ENCODE_RESTRICTED; break; } } 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]; }
static int ieee80211_ioctl_siwencodeext(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *extra) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; int uninitialized_var(alg), idx, i, remove = 0; switch (ext->alg) { case IW_ENCODE_ALG_NONE: remove = 1; break; case IW_ENCODE_ALG_WEP: alg = ALG_WEP; break; case IW_ENCODE_ALG_TKIP: alg = ALG_TKIP; break; case IW_ENCODE_ALG_CCMP: alg = ALG_CCMP; break; default: return -EOPNOTSUPP; } if (erq->flags & IW_ENCODE_DISABLED) remove = 1; idx = erq->flags & IW_ENCODE_INDEX; if (idx < 1 || idx > 4) { idx = -1; if (!sdata->default_key) idx = 0; else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { if (sdata->default_key == sdata->keys[i]) { idx = i; break; } } if (idx < 0) return -EINVAL; } else idx--; return ieee80211_set_encryption(sdata, ext->addr.sa_data, idx, alg, remove, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, ext->key, ext->key_len); }
static ssize_t ieee80211_if_show(struct class_device *cd, char *buf, ssize_t (*format)(const struct ieee80211_sub_if_data *, char *)) { struct net_device *dev = to_net_dev(cd); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); ssize_t ret = -EINVAL; read_lock(&dev_base_lock); if (dev->reg_state == NETREG_REGISTERED) { ret = (*format)(sdata, buf); } read_unlock(&dev_base_lock); return ret; }
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_siwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_STATION || sdata->vif.type == NL80211_IFTYPE_ADHOC) { int ret; if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data, ETH_ALEN); return 0; } if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL; else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL; else sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data); if (ret) return ret; ieee80211_sta_req_auth(sdata, &sdata->u.sta); return 0; } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { /* * If it is necessary to update the WDS peer address * while the interface is running, then we need to do * more work here, namely if it is running we need to * add a new and remove the old STA entry, this is * normally handled by _open() and _stop(). */ if (netif_running(dev)) return -EBUSY; memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, ETH_ALEN); return 0; } return -EOPNOTSUPP; }
static int ieee80211_ioctl_siwauth(struct net_device *dev, struct iw_request_info *info, struct iw_param *data, char *extra) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); int ret = 0; switch (data->flags & IW_AUTH_INDEX) { case IW_AUTH_WPA_VERSION: case IW_AUTH_CIPHER_PAIRWISE: case IW_AUTH_CIPHER_GROUP: case IW_AUTH_WPA_ENABLED: case IW_AUTH_RX_UNENCRYPTED_EAPOL: case IW_AUTH_KEY_MGMT: break; case IW_AUTH_DROP_UNENCRYPTED: sdata->drop_unencrypted = !!data->value; break; case IW_AUTH_PRIVACY_INVOKED: if (sdata->vif.type != NL80211_IFTYPE_STATION) ret = -EINVAL; else { sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; /* * Privacy invoked by wpa_supplicant, store the * value and allow associating to a protected * network without having a key up front. */ if (data->value) sdata->u.sta.flags |= IEEE80211_STA_PRIVACY_INVOKED; } break; case IW_AUTH_80211_AUTH_ALG: if (sdata->vif.type == NL80211_IFTYPE_STATION || sdata->vif.type == NL80211_IFTYPE_ADHOC) sdata->u.sta.auth_algs = data->value; else ret = -EOPNOTSUPP; break; default: ret = -EOPNOTSUPP; break; } return ret; }
/** * mesh_queue_preq - queue a PREQ to a given destination * * @mpath: mesh path to discover * @flags: special attributes of the PREQ to be sent * * Locking: the function must be called from within a rcu read lock block. * */ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev); struct ieee80211_if_sta *ifsta = &sdata->u.sta; struct mesh_preq_queue *preq_node; preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_KERNEL); if (!preq_node) { printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n"); return; } spin_lock(&ifsta->mesh_preq_queue_lock); if (ifsta->preq_queue_len == MAX_PREQ_QUEUE_LEN) { spin_unlock(&ifsta->mesh_preq_queue_lock); kfree(preq_node); if (printk_ratelimit()) printk(KERN_DEBUG "Mesh HWMP: PREQ node queue full\n"); return; } memcpy(preq_node->dst, mpath->dst, ETH_ALEN); preq_node->flags = flags; list_add_tail(&preq_node->list, &ifsta->preq_queue.list); ++ifsta->preq_queue_len; spin_unlock(&ifsta->mesh_preq_queue_lock); if (time_after(jiffies, ifsta->last_preq + min_preq_int_jiff(sdata))) queue_work(sdata->local->hw.workqueue, &ifsta->work); else if (time_before(jiffies, ifsta->last_preq)) { /* avoid long wait if did not send preqs for a long time * and jiffies wrapped around */ ifsta->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; queue_work(sdata->local->hw.workqueue, &ifsta->work); } else mod_timer(&ifsta->mesh_path_timer, ifsta->last_preq + min_preq_int_jiff(sdata)); }
static int ieee80211_ioctl_giwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) { size_t len; struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_STATION || sdata->vif.type == NL80211_IFTYPE_ADHOC) { int res = ieee80211_sta_get_ssid(sdata, ssid, &len); if (res == 0) { data->length = len; data->flags = 1; } else data->flags = 0; return res; } return -EOPNOTSUPP; }
static int ieee80211_ioctl_giwauth(struct net_device *dev, struct iw_request_info *info, struct iw_param *data, char *extra) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); int ret = 0; switch (data->flags & IW_AUTH_INDEX) { case IW_AUTH_80211_AUTH_ALG: if (sdata->vif.type == NL80211_IFTYPE_STATION || sdata->vif.type == NL80211_IFTYPE_ADHOC) data->value = sdata->u.sta.auth_algs; else ret = -EOPNOTSUPP; break; default: ret = -EOPNOTSUPP; break; } return ret; }
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_giwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { struct ieee80211_sub_if_data *sdata; int idx, i; sdata = IEEE80211_DEV_TO_SUB_IF(dev); idx = erq->flags & IW_ENCODE_INDEX; if (idx < 1 || idx > 4) { idx = -1; if (!sdata->default_key) idx = 0; else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { if (sdata->default_key == sdata->keys[i]) { idx = i; break; } } if (idx < 0) return -EINVAL; } else idx--; erq->flags = idx + 1; if (!sdata->keys[idx]) { erq->length = 0; erq->flags |= IW_ENCODE_DISABLED; return 0; } memcpy(key, sdata->keys[idx]->conf.key, min_t(int, erq->length, sdata->keys[idx]->conf.keylen)); erq->length = sdata->keys[idx]->conf.keylen; erq->flags |= IW_ENCODE_ENABLED; return 0; }
static int ieee80211_ioctl_siwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *keybuf) { struct ieee80211_sub_if_data *sdata; int idx, i, alg = ALG_WEP; u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; int remove = 0; sdata = IEEE80211_DEV_TO_SUB_IF(dev); idx = erq->flags & IW_ENCODE_INDEX; if (idx == 0) { if (sdata->default_key) for (i = 0; i < NUM_DEFAULT_KEYS; i++) { if (sdata->default_key == sdata->keys[i]) { idx = i; break; } } } else if (idx < 1 || idx > 4) return -EINVAL; else idx--; if (erq->flags & IW_ENCODE_DISABLED) remove = 1; else if (erq->length == 0) { /* No key data - just set the default TX key index */ ieee80211_set_default_key(sdata, idx); return 0; } return ieee80211_set_encryption( sdata, bcaddr, idx, alg, remove, !sdata->default_key, keybuf, erq->length); }
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; }