--- net/mac80211/ieee80211_ioctl.c | 102 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) --- everything.orig/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:32.281514919 +0100 +++ everything/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:33.681513453 +0100 @@ -125,6 +125,105 @@ static int ieee80211_ioctl_siwgenie(stru return -EOPNOTSUPP; } +/* + * Wow. This ioctl interface is such crap, it's tied + * to internal definitions. I hope it dies soon. + */ +static int mode_to_hostapd_mode(enum ieee80211_phymode mode) +{ + switch (mode) { + case MODE_IEEE80211A: + return 0; + case MODE_IEEE80211B: + return 1; + case MODE_IEEE80211G: + return 3; + case NUM_IEEE80211_MODES: + WARN_ON(1); + break; + } + WARN_ON(1); + return -1; +} + +static int channel_flags_to_hostapd_flags(int flags) +{ + int res = 0; + + if (flags & IEEE80211_CHAN_W_SCAN) + res |= 1; + if (flags & IEEE80211_CHAN_W_ACTIVE_SCAN) + res |= 2; + if (flags & IEEE80211_CHAN_W_IBSS) + res |= 4; + + return res; +} + +struct ieee80211_channel_data { + short chan; /* channel number (IEEE 802.11) */ + short freq; /* frequency in MHz */ + int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */ +}; + +struct ieee80211_rate_data { + int rate; /* rate in 100 kbps */ + int flags; /* IEEE80211_RATE_ flags */ +}; + +static int ieee80211_ioctl_get_hw_features(struct net_device *dev, + struct prism2_hostapd_param *param, + int param_len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + u8 *pos = param->u.hw_features.data; + int left = param_len - (pos - (u8 *) param); + int i; + struct hostapd_ioctl_hw_modes_hdr *hdr; + struct ieee80211_rate_data *rate; + struct ieee80211_channel_data *chan; + struct ieee80211_hw_mode *mode; + + param->u.hw_features.flags = 0; + + param->u.hw_features.num_modes = 0; + list_for_each_entry(mode, &local->modes_list, list) { + int clen, rlen; + + param->u.hw_features.num_modes++; + clen = + mode->num_channels * sizeof(struct ieee80211_channel_data); + rlen = mode->num_rates * sizeof(struct ieee80211_rate_data); + if (left < sizeof(*hdr) + clen + rlen) + return -E2BIG; + left -= sizeof(*hdr) + clen + rlen; + + hdr = (struct hostapd_ioctl_hw_modes_hdr *)pos; + hdr->mode = mode_to_hostapd_mode(mode->mode); + hdr->num_channels = mode->num_channels; + hdr->num_rates = mode->num_rates; + + pos = (u8 *) (hdr + 1); + chan = (struct ieee80211_channel_data *)pos; + for (i = 0; i < mode->num_channels; i++) { + chan[i].chan = mode->channels[i].chan; + chan[i].freq = mode->channels[i].freq; + chan[i].flag = channel_flags_to_hostapd_flags( + mode->channels[i].flag); + } + pos += clen; + + rate = (struct ieee80211_rate_data *)pos; + for (i = 0; i < mode->num_rates; i++) { + rate[i].rate = mode->rates[i].rate; + rate[i].flags = mode->rates[i].flags; + } + pos += rlen; + } + + return 0; +} + static int ieee80211_ioctl_priv_hostapd(struct net_device *dev, struct iw_point *p) @@ -151,6 +250,9 @@ static int ieee80211_ioctl_priv_hostapd( } switch (param->cmd) { + case PRISM2_HOSTAPD_GET_HW_FEATURES: + ret = ieee80211_ioctl_get_hw_features(dev, param, p->length); + break; default: ret = -EOPNOTSUPP; break;