📄 hostap_ioctl.c
字号:
/* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */#ifdef in_atomic/* Get kernel_locked() for in_atomic() */#include <linux/smp_lock.h>#endif#include <linux/ethtool.h>static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev){ struct hostap_interface *iface = dev->priv; local_info_t *local = iface->local; struct iw_statistics *wstats;#if WIRELESS_EXT > 16 /* Why are we doing that ? Jean II */ if (iface->type != HOSTAP_INTERFACE_MAIN) return NULL;#endif /* WIRELESS_EXT > 16 */ wstats = &local->wstats; wstats->status = 0; wstats->discard.code = local->comm_tallies.rx_discards_wep_undecryptable; wstats->discard.misc = local->comm_tallies.rx_fcs_errors + local->comm_tallies.rx_discards_no_buffer + local->comm_tallies.tx_discards_wrong_sa; wstats->discard.retries = local->comm_tallies.tx_retry_limit_exceeded; wstats->discard.fragment = local->comm_tallies.rx_message_in_bad_msg_fragments; if (local->iw_mode != IW_MODE_MASTER && local->iw_mode != IW_MODE_REPEAT) { int update = 1;#ifdef in_atomic /* RID reading might sleep and it must not be called in * interrupt context or while atomic. However, this * function seems to be called while atomic (at least in Linux * 2.5.59). Update signal quality values only if in suitable * context. Otherwise, previous values read from tick timer * will be used. */ if (in_atomic()) update = 0;#endif /* in_atomic */ if (update && prism2_update_comms_qual(dev) == 0) wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; wstats->qual.qual = local->comms_qual; wstats->qual.level = local->avg_signal; wstats->qual.noise = local->avg_noise; } else { wstats->qual.qual = 0; wstats->qual.level = 0; wstats->qual.noise = 0; wstats->qual.updated = IW_QUAL_ALL_INVALID; } return wstats;}static int prism2_get_datarates(struct net_device *dev, u8 *rates){ struct hostap_interface *iface = dev->priv; local_info_t *local = iface->local; u8 buf[12]; int len; u16 val; len = local->func->get_rid(dev, HFA384X_RID_SUPPORTEDDATARATES, buf, sizeof(buf), 0); if (len < 2) return 0; val = le16_to_cpu(*(u16 *) buf); /* string length */ if (len - 2 < val || val > 10) return 0; memcpy(rates, buf + 2, val); return val;}static int prism2_get_name(struct net_device *dev, struct iw_request_info *info, char *name, char *extra){ u8 rates[10]; int len, i, over2 = 0; len = prism2_get_datarates(dev, rates); for (i = 0; i < len; i++) { if (rates[i] == 0x0b || rates[i] == 0x16) { over2 = 1; break; } } strcpy(name, over2 ? "IEEE 802.11b" : "IEEE 802.11-DS"); return 0;}static void prism2_crypt_delayed_deinit(local_info_t *local, struct prism2_crypt_data **crypt){ struct prism2_crypt_data *tmp; unsigned long flags; tmp = *crypt; *crypt = NULL; if (tmp == NULL) return; /* must not run ops->deinit() while there may be pending encrypt or * decrypt operations. Use a list of delayed deinits to avoid needing * locking. */ spin_lock_irqsave(&local->lock, flags); list_add(&tmp->list, &local->crypt_deinit_list); if (!timer_pending(&local->crypt_deinit_timer)) { local->crypt_deinit_timer.expires = jiffies + HZ; add_timer(&local->crypt_deinit_timer); } spin_unlock_irqrestore(&local->lock, flags);}static int prism2_ioctl_siwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *keybuf){ struct hostap_interface *iface = dev->priv; local_info_t *local = iface->local; int i; struct prism2_crypt_data **crypt; i = erq->flags & IW_ENCODE_INDEX; if (i < 1 || i > 4) i = local->tx_keyidx; else i--; if (i < 0 || i >= WEP_KEYS) return -EINVAL; crypt = &local->crypt[i]; if (erq->flags & IW_ENCODE_DISABLED) { if (*crypt) prism2_crypt_delayed_deinit(local, crypt); goto done; } if (*crypt != NULL && (*crypt)->ops != NULL && strcmp((*crypt)->ops->name, "WEP") != 0) { /* changing to use WEP; deinit previously used algorithm */ prism2_crypt_delayed_deinit(local, crypt); } if (*crypt == NULL) { struct prism2_crypt_data *new_crypt; /* take WEP into use */ new_crypt = (struct prism2_crypt_data *) kmalloc(sizeof(struct prism2_crypt_data), GFP_KERNEL); if (new_crypt == NULL) return -ENOMEM; memset(new_crypt, 0, sizeof(struct prism2_crypt_data)); new_crypt->ops = hostap_get_crypto_ops("WEP"); if (!new_crypt->ops) { request_module("hostap_crypt_wep"); new_crypt->ops = hostap_get_crypto_ops("WEP"); } if (new_crypt->ops) new_crypt->priv = new_crypt->ops->init(i); if (!new_crypt->ops || !new_crypt->priv) { kfree(new_crypt); new_crypt = NULL; printk(KERN_WARNING "%s: could not initialize WEP: " "load module hostap_crypt_wep.o\n", dev->name); return -EOPNOTSUPP; } *crypt = new_crypt; } if (erq->length > 0) { int len = erq->length <= 5 ? 5 : 13; int first = 1, j; if (len > erq->length) memset(keybuf + erq->length, 0, len - erq->length); (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv); for (j = 0; j < WEP_KEYS; j++) { if (j != i && local->crypt[j]) { first = 0; break; } } if (first) local->tx_keyidx = i; } else { /* No key data - just set the default TX key index */ local->tx_keyidx = i; } done: local->open_wep = erq->flags & IW_ENCODE_OPEN; if (hostap_set_encryption(local)) { printk(KERN_DEBUG "%s: set_encryption failed\n", dev->name); return -EINVAL; } /* Do not reset port0 if card is in Managed mode since resetting will * generate new IEEE 802.11 authentication which may end up in looping * with IEEE 802.1X. Prism2 documentation seem to require port reset * after WEP configuration. However, keys are apparently changed at * least in Managed mode. */ if (local->iw_mode != IW_MODE_INFRA && local->func->reset_port(dev)) { printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); return -EINVAL; } return 0;}static int prism2_ioctl_giwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *key){ struct hostap_interface *iface = dev->priv; local_info_t *local = iface->local; int i, len; u16 val; struct prism2_crypt_data *crypt; i = erq->flags & IW_ENCODE_INDEX; if (i < 1 || i > 4) i = local->tx_keyidx; else i--; if (i < 0 || i >= WEP_KEYS) return -EINVAL; crypt = local->crypt[i]; erq->flags = i + 1; if (crypt == NULL || crypt->ops == NULL) { erq->length = 0; erq->flags |= IW_ENCODE_DISABLED; return 0; } if (strcmp(crypt->ops->name, "WEP") != 0) { /* only WEP is supported with wireless extensions, so just * report that encryption is used */ erq->length = 0; erq->flags |= IW_ENCODE_ENABLED; return 0; } /* Reads from HFA384X_RID_CNFDEFAULTKEY* return bogus values, so show * the keys from driver buffer */ len = crypt->ops->get_key(key, WEP_KEY_LEN, NULL, crypt->priv); erq->length = (len >= 0 ? len : 0); if (local->func->get_rid(dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, 1) < 0) { printk("CNFWEPFLAGS reading failed\n"); return -EOPNOTSUPP; } le16_to_cpus(&val); if (val & HFA384X_WEPFLAGS_PRIVACYINVOKED) erq->flags |= IW_ENCODE_ENABLED; else erq->flags |= IW_ENCODE_DISABLED; if (val & HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED) erq->flags |= IW_ENCODE_RESTRICTED; else erq->flags |= IW_ENCODE_OPEN; return 0;}#if WIRELESS_EXT <= 15static int prism2_ioctl_giwspy(struct net_device *dev, struct iw_request_info *info, struct iw_point *srq, char *extra){ struct hostap_interface *iface = dev->priv; local_info_t *local = iface->local; struct sockaddr addr[IW_MAX_SPY]; struct iw_quality qual[IW_MAX_SPY]; srq->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_SPY, 0); memcpy(extra, &addr, sizeof(addr[0]) * srq->length); memcpy(extra + sizeof(addr[0]) * srq->length, &qual, sizeof(qual[0]) * srq->length); return 0;}static int prism2_ioctl_siwspy(struct net_device *dev, struct iw_request_info *info, struct iw_point *srq, char *extra){ struct hostap_interface *iface = dev->priv; local_info_t *local = iface->local; struct sockaddr *addr; int i; if (srq->length > IW_MAX_SPY) return -E2BIG; addr = (struct sockaddr *) extra; for (i = 0; i < srq->length; i++, addr++) { hostap_add_sta(local->ap, addr->sa_data); /* TODO: how are these entries timed out? is the default * timeout suitable? probably not.. */ } return 0;}#endif /* WIRELESS_EXT <= 15 */static int hostap_set_rate(struct net_device *dev){ struct hostap_interface *iface = dev->priv; local_info_t *local = iface->local; int ret, basic_rates; basic_rates = local->basic_rates & local->tx_rate_control; if (!basic_rates || basic_rates != local->basic_rates) { printk(KERN_INFO "%s: updating basic rate set automatically " "to match with the new supported rate set\n", dev->name); if (!basic_rates) basic_rates = local->tx_rate_control; local->basic_rates = basic_rates; if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, basic_rates)) printk(KERN_WARNING "%s: failed to set " "cnfBasicRates\n", dev->name); } ret = (hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, local->tx_rate_control) || hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, local->tx_rate_control) || local->func->reset_port(dev)); if (ret) { printk(KERN_WARNING "%s: TXRateControl/cnfSupportedRates " "setting to 0x%x failed\n", dev->name, local->tx_rate_control); } /* Update TX rate configuration for all STAs based on new operational * rate set. */ hostap_update_rates(local); return ret;}static int prism2_ioctl_siwrate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra){ struct hostap_interface *iface = dev->priv; local_info_t *local = iface->local; if (rrq->fixed) { switch (rrq->value) { case 11000000: local->tx_rate_control = HFA384X_RATES_11MBPS; break; case 5500000: local->tx_rate_control = HFA384X_RATES_5MBPS; break; case 2000000: local->tx_rate_control = HFA384X_RATES_2MBPS; break; case 1000000: local->tx_rate_control = HFA384X_RATES_1MBPS; break; default: local->tx_rate_control = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | HFA384X_RATES_11MBPS; break; } } else { switch (rrq->value) { case 11000000: local->tx_rate_control = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | HFA384X_RATES_11MBPS; break; case 5500000: local->tx_rate_control = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS; break; case 2000000: local->tx_rate_control = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS; break; case 1000000: local->tx_rate_control = HFA384X_RATES_1MBPS; break; default: local->tx_rate_control = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | HFA384X_RATES_11MBPS; break; } } return hostap_set_rate(dev);}static int prism2_ioctl_giwrate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra){ u16 val; struct hostap_interface *iface = dev->priv; local_info_t *local = iface->local; int ret = 0; if (local->func->get_rid(dev, HFA384X_RID_TXRATECONTROL, &val, 2, 1) < 0) return -EINVAL; if ((val & 0x1) && (val > 1)) rrq->fixed = 0; else rrq->fixed = 1; if (local->iw_mode == IW_MODE_MASTER && local->ap != NULL && !local->fw_tx_rate_control) { /* HFA384X_RID_CURRENTTXRATE seems to always be 2 Mbps in * Host AP mode, so use the recorded TX rate of the last sent * frame */ rrq->value = local->ap->last_tx_rate > 0 ? local->ap->last_tx_rate * 100000 : 11000000; return 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -