This turns the PHY-modes list into a linked list. The advantage is that drivers can add modes dynamically, as they probe them and don't have to settle to a given arraysize at the beginning of probing.
Signed-off-by: Michael Buesch <[EMAIL PROTECTED]> -- Note that I will also send fixup patches for all other d80211 drivers, if no complaints are done against this patch. Index: bu3sch-wireless-dev/include/net/d80211.h =================================================================== --- bu3sch-wireless-dev.orig/include/net/d80211.h 2006-12-05 18:09:34.000000000 +0100 +++ bu3sch-wireless-dev/include/net/d80211.h 2006-12-13 19:40:05.000000000 +0100 @@ -76,12 +76,14 @@ struct ieee80211_rate { * optimizing channel utilization estimates */ }; -struct ieee80211_hw_modes { - int mode; - int num_channels; - struct ieee80211_channel *channels; - int num_rates; - struct ieee80211_rate *rates; +struct ieee80211_hw_mode { + int mode; /* MODE_IEEE80211... */ + int num_channels; /* Number of channels (below) */ + struct ieee80211_channel *channels; /* Array of supported channels */ + int num_rates; /* Number of rates (below) */ + struct ieee80211_rate *rates; /* Array of supported rates */ + + struct list_head list; /* Internal, don't touch */ }; struct ieee80211_tx_queue_params { @@ -420,9 +422,7 @@ typedef enum { SET_KEY, DISABLE_KEY, REMOVE_ALL_KEYS, } set_key_cmd; -/* This is driver-visible part of the per-hw state the stack keeps. - * If you change something in here, call ieee80211_update_hw() to - * notify the stack about the change. */ +/* This is driver-visible part of the per-hw state the stack keeps. */ struct ieee80211_hw { /* these are assigned by d80211, don't write */ int index; @@ -512,9 +512,6 @@ struct ieee80211_hw { /* This is maximum value for rssi reported by this device */ int maxssi; - int num_modes; - struct ieee80211_hw_modes *modes; - /* Number of available hardware TX queues for data packets. * WMM requires at least four queues. */ int queues; @@ -750,9 +747,9 @@ static inline char *ieee80211_get_rx_led #endif } -/* Call this function if you changed the hardware description after - * ieee80211_register_hw */ -int ieee80211_update_hw(struct ieee80211_hw *hw); +/* Register a new hardware PHYMODE capability to the stack. */ +int ieee80211_register_hwmode(struct ieee80211_hw *hw, + struct ieee80211_hw_mode *mode); /* Unregister a hardware device. This function instructs 802.11 code to free * allocated resources and unregister netdevices from the kernel. */ Index: bu3sch-wireless-dev/net/d80211/ieee80211.c =================================================================== --- bu3sch-wireless-dev.orig/net/d80211/ieee80211.c 2006-12-05 18:09:35.000000000 +0100 +++ bu3sch-wireless-dev/net/d80211/ieee80211.c 2006-12-13 19:40:05.000000000 +0100 @@ -1915,7 +1915,8 @@ int ieee80211_if_config_beacon(struct ne int ieee80211_hw_config(struct ieee80211_local *local) { - int i, ret = 0; + struct ieee80211_hw_mode *mode; + int ret = 0; #ifdef CONFIG_D80211_VERBOSE_DEBUG printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d " @@ -1926,12 +1927,10 @@ int ieee80211_hw_config(struct ieee80211 if (local->ops->config) ret = local->ops->config(local_to_hw(local), &local->hw.conf); - for (i = 0; i < local->hw.num_modes; i++) { - struct ieee80211_hw_modes *mode = &local->hw.modes[i]; + list_for_each_entry(mode, &local->modes_list, list) { if (mode->mode == local->hw.conf.phymode) { - if (local->curr_rates != mode->rates) { + if (local->curr_rates != mode->rates) rate_control_clear(local); - } local->curr_rates = mode->rates; local->num_curr_rates = mode->num_rates; ieee80211_prepare_rates(local); @@ -2511,10 +2510,10 @@ ieee80211_rx_h_data(struct ieee80211_txr static struct ieee80211_rate * ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate) { - int m, r; + struct ieee80211_hw_mode *mode; + int r; - for (m = 0; m < local->hw.num_modes; m++) { - struct ieee80211_hw_modes *mode = &local->hw.modes[m]; + list_for_each_entry(mode, &local->modes_list, list) { if (mode->mode != phymode) continue; for (r = 0; r < mode->num_rates; r++) { @@ -4351,24 +4350,6 @@ void ieee80211_if_mgmt_setup(struct net_ dev->destructor = ieee80211_if_free; } -static void ieee80211_precalc_modes(struct ieee80211_local *local) -{ - struct ieee80211_hw_modes *mode; - struct ieee80211_rate *rate; - struct ieee80211_hw *hw = &local->hw; - int m, r; - - local->hw_modes = 0; - for (m = 0; m < hw->num_modes; m++) { - mode = &hw->modes[m]; - local->hw_modes |= 1 << mode->mode; - for (r = 0; r < mode->num_rates; r++) { - rate = &mode->rates[r]; - rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate; - } - } -} - int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, const char *name) { @@ -4461,6 +4442,7 @@ struct ieee80211_hw *ieee80211_alloc_hw( local->hw.priv = (char *)mdev->priv + ((sizeof(struct ieee80211_sub_if_data) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); + local->hw.queues = 1; /* default */ local->mdev = mdev; local->rx_pre_handlers = ieee80211_rx_pre_handlers; @@ -4482,6 +4464,8 @@ struct ieee80211_hw *ieee80211_alloc_hw( init_timer(&local->scan.timer); /* clear it out */ + INIT_LIST_HEAD(&local->modes_list); + spin_lock_init(&local->sub_if_lock); INIT_LIST_HEAD(&local->sub_if_list); @@ -4546,9 +4530,6 @@ int ieee80211_register_hw(struct ieee802 local->hw.conf.beacon_int = 1000; - /* Don't care about the result */ - ieee80211_update_hw(local_to_hw(local)); - result = sta_info_start(local); if (result < 0) goto fail_sta_info; @@ -4633,35 +4614,38 @@ fail_sysfs: } EXPORT_SYMBOL(ieee80211_register_hw); -int ieee80211_update_hw(struct ieee80211_hw *hw) +int ieee80211_register_hwmode(struct ieee80211_hw *hw, + struct ieee80211_hw_mode *mode) { struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_rate *rate; + int i; - /* Backwards compatibility for low-level drivers that do not set number - * of TX queues. */ - if (hw->queues == 0) - hw->queues = 1; - - if (!hw->modes || !hw->modes->channels || !hw->modes->rates || - !hw->modes->num_channels || !hw->modes->num_rates) - return -1; + INIT_LIST_HEAD(&mode->list); + list_add_tail(&mode->list, &local->modes_list); - ieee80211_precalc_modes(local); - local->hw.conf.phymode = hw->modes[0].mode; - local->curr_rates = hw->modes[0].rates; - local->num_curr_rates = hw->modes[0].num_rates; - ieee80211_prepare_rates(local); - - local->hw.conf.freq = local->hw.modes[0].channels[0].freq; - local->hw.conf.channel = local->hw.modes[0].channels[0].chan; - local->hw.conf.channel_val = local->hw.modes[0].channels[0].val; + local->hw_modes |= (1 << mode->mode); + for (i = 0; i < mode->num_rates; i++) { + rate = &(mode->rates[i]); + rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate; + } + + if (!local->curr_rates) { + /* Default to this mode */ + local->hw.conf.phymode = mode->mode; + local->curr_rates = mode->rates; + local->num_curr_rates = mode->num_rates; + ieee80211_prepare_rates(local); + local->hw.conf.freq = mode->channels[0].freq; + local->hw.conf.channel = mode->channels[0].chan; + local->hw.conf.channel_val = mode->channels[0].val; + } ieee80211_init_client(local->mdev); - /* FIXME: Invoke config to allow driver to set the channel. */ return 0; } -EXPORT_SYMBOL(ieee80211_update_hw); +EXPORT_SYMBOL(ieee80211_register_hwmode); void ieee80211_unregister_hw(struct ieee80211_hw *hw) { Index: bu3sch-wireless-dev/net/d80211/ieee80211_i.h =================================================================== --- bu3sch-wireless-dev.orig/net/d80211/ieee80211_i.h 2006-12-05 18:09:35.000000000 +0100 +++ bu3sch-wireless-dev/net/d80211/ieee80211_i.h 2006-12-13 19:40:05.000000000 +0100 @@ -181,7 +181,7 @@ struct ieee80211_passive_scan { int channel; /* channel to be scanned */ int tries; - int mode_idx; + struct ieee80211_hw_mode *mode; int chan_idx; int freq; @@ -336,6 +336,9 @@ struct ieee80211_local { struct ieee80211_ops *ops; + /* List of registered struct ieee80211_hw_mode */ + struct list_head modes_list; + struct net_device *mdev; /* wmaster# - "master" 802.11 device */ struct net_device *apdev; /* wlan#ap - management frames (hostapd) */ int open_count; @@ -425,7 +428,7 @@ struct ieee80211_local { spinlock_t sub_if_lock; /* mutex for STA data structures */ struct list_head sub_if_list; int sta_scanning; - int scan_hw_mode_idx; + struct ieee80211_hw_mode *scan_hw_mode; int scan_channel_idx; enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; unsigned long last_scan_completed; Index: bu3sch-wireless-dev/net/d80211/ieee80211_ioctl.c =================================================================== --- bu3sch-wireless-dev.orig/net/d80211/ieee80211_ioctl.c 2006-12-05 18:09:35.000000000 +0100 +++ bu3sch-wireless-dev/net/d80211/ieee80211_ioctl.c 2006-12-13 19:40:05.000000000 +0100 @@ -120,43 +120,45 @@ static int ieee80211_ioctl_get_hw_featur struct ieee80211_local *local = dev->ieee80211_ptr; u8 *pos = param->u.hw_features.data; int left = param_len - (pos - (u8 *) param); - int mode, i; + 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; if (local->hw.flags & IEEE80211_HW_DATA_NULLFUNC_ACK) param->u.hw_features.flags |= HOSTAP_HW_FLAG_NULLFUNC_OK; - param->u.hw_features.num_modes = local->hw.num_modes; - for (mode = 0; mode < local->hw.num_modes; mode++) { + param->u.hw_features.num_modes = 0; + list_for_each_entry(mode, &local->modes_list, list) { int clen, rlen; - struct ieee80211_hw_modes *m = &local->hw.modes[mode]; - clen = m->num_channels * sizeof(struct ieee80211_channel_data); - rlen = m->num_rates * sizeof(struct ieee80211_rate_data); + + 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 = m->mode; - hdr->num_channels = m->num_channels; - hdr->num_rates = m->num_rates; + hdr->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 < m->num_channels; i++) { - chan[i].chan = m->channels[i].chan; - chan[i].freq = m->channels[i].freq; - chan[i].flag = m->channels[i].flag; + 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 = mode->channels[i].flag; } pos += clen; rate = (struct ieee80211_rate_data *) pos; - for (i = 0; i < m->num_rates; i++) { - rate[i].rate = m->rates[i].rate; - rate[i].flags = m->rates[i].flags; + for (i = 0; i < mode->num_rates; i++) { + rate[i].rate = mode->rates[i].rate; + rate[i].flags = mode->rates[i].flags; } pos += rlen; } @@ -198,8 +200,7 @@ static int ieee80211_ioctl_scan(struct n param->u.scan.last_rx = local->scan.rx_packets; local->scan.rx_packets = -1; } - param->u.scan.channel = local->hw.modes[local->scan.mode_idx]. - channels[local->scan.chan_idx].chan; + param->u.scan.channel = local->scan.mode->channels[local->scan.chan_idx].chan; return 0; } @@ -1357,19 +1358,16 @@ static int ieee80211_ioctl_set_channel_f struct prism2_hostapd_param *param) { struct ieee80211_local *local = dev->ieee80211_ptr; - struct ieee80211_hw_modes *mode = NULL; + struct ieee80211_hw_mode *mode; struct ieee80211_channel *chan = NULL; int i; - for (i = 0; i < local->hw.num_modes; i++) { - mode = &local->hw.modes[i]; + list_for_each_entry(mode, &local->modes_list, list) { if (mode->mode == param->u.set_channel_flag.mode) - break; - mode = NULL; + goto found; } - - if (!mode) - return -ENOENT; + return -ENOENT; +found: for (i = 0; i < mode->num_channels; i++) { chan = &mode->channels[i]; @@ -1706,10 +1704,10 @@ static void ieee80211_unmask_channel(str static int ieee80211_unmask_channels(struct net_device *dev) { struct ieee80211_local *local = dev->ieee80211_ptr; - int m, c; + struct ieee80211_hw_mode *mode; + int c; - for (m = 0; m < local->hw.num_modes; m++) { - struct ieee80211_hw_modes *mode = &local->hw.modes[m]; + list_for_each_entry(mode, &local->modes_list, list) { for (c = 0; c < mode->num_channels; c++) { ieee80211_unmask_channel(dev, mode->mode, &mode->channels[c]); @@ -1807,7 +1805,8 @@ int ieee80211_ioctl_siwfreq(struct net_d struct iw_freq *freq, char *extra) { struct ieee80211_local *local = dev->ieee80211_ptr; - int m, c, nfreq, set = 0; + struct ieee80211_hw_mode *mode; + int c, nfreq, set = 0; /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ if (freq->e == 0) @@ -1822,8 +1821,7 @@ int ieee80211_ioctl_siwfreq(struct net_d return -EINVAL; } - for (m = 0; m < local->hw.num_modes; m++) { - struct ieee80211_hw_modes *mode = &local->hw.modes[m]; + list_for_each_entry(mode, &local->modes_list, list) { for (c = 0; c < mode->num_channels; c++) { struct ieee80211_channel *chan = &mode->channels[c]; if (chan->flag & IEEE80211_CHAN_W_SCAN && @@ -2166,10 +2164,10 @@ static int ieee80211_ioctl_giwretry(stru static void ieee80211_ioctl_unmask_channels(struct ieee80211_local *local) { - int m, c; + struct ieee80211_hw_mode *mode; + int c; - for (m = 0; m < local->hw.num_modes; m++) { - struct ieee80211_hw_modes *mode = &local->hw.modes[m]; + list_for_each_entry(mode, &local->modes_list, list) { for (c = 0; c < mode->num_channels; c++) { struct ieee80211_channel *chan = &mode->channels[c]; chan->flag |= IEEE80211_CHAN_W_SCAN; Index: bu3sch-wireless-dev/net/d80211/ieee80211_scan.c =================================================================== --- bu3sch-wireless-dev.orig/net/d80211/ieee80211_scan.c 2006-12-05 18:09:35.000000000 +0100 +++ bu3sch-wireless-dev/net/d80211/ieee80211_scan.c 2006-12-13 19:40:05.000000000 +0100 @@ -24,49 +24,49 @@ #define SCAN_TXRX_THRESHOLD 75 static void get_channel_params(struct ieee80211_local *local, int channel, - struct ieee80211_hw_modes **mode, + struct ieee80211_hw_mode **mode, struct ieee80211_channel **chan) { - int m; + struct ieee80211_hw_mode *m; - for (m = 0; m < local->hw.num_modes; m++) { - *mode = &local->hw.modes[m]; - if ((*mode)->mode == local->hw.conf.phymode) + list_for_each_entry(m, &local->modes_list, list) { + *mode = m; + if (m->mode == local->hw.conf.phymode) break; } - local->scan.mode_idx = m; + local->scan.mode = m; local->scan.chan_idx = 0; do { - *chan = &(*mode)->channels[local->scan.chan_idx]; - if ((*chan)->chan == channel) { + *chan = &m->channels[local->scan.chan_idx]; + if ((*chan)->chan == channel) return; - } local->scan.chan_idx++; - } while (local->scan.chan_idx < (*mode)->num_channels); + } while (local->scan.chan_idx < m->num_channels); *chan = NULL; } static void next_chan_same_mode(struct ieee80211_local *local, - struct ieee80211_hw_modes **mode, + struct ieee80211_hw_mode **mode, struct ieee80211_channel **chan) { - int m, prev; + struct ieee80211_hw_mode *m; + int prev; - for (m = 0; m < local->hw.num_modes; m++) { - *mode = &local->hw.modes[m]; - if ((*mode)->mode == local->hw.conf.phymode) + list_for_each_entry(m, &local->modes_list, list) { + *mode = m; + if (m->mode == local->hw.conf.phymode) break; } - local->scan.mode_idx = m; + local->scan.mode = m; /* Select next channel - scan only channels marked with W_SCAN flag */ prev = local->scan.chan_idx; do { local->scan.chan_idx++; - if (local->scan.chan_idx >= (*mode)->num_channels) + if (local->scan.chan_idx >= m->num_channels) local->scan.chan_idx = 0; - *chan = &(*mode)->channels[local->scan.chan_idx]; + *chan = &m->channels[local->scan.chan_idx]; if ((*chan)->flag & IEEE80211_CHAN_W_SCAN) break; } while (local->scan.chan_idx != prev); @@ -74,43 +74,44 @@ static void next_chan_same_mode(struct i static void next_chan_all_modes(struct ieee80211_local *local, - struct ieee80211_hw_modes **mode, + struct ieee80211_hw_mode **mode, struct ieee80211_channel **chan) { - int prev, prev_m; - - if (local->scan.mode_idx >= local->hw.num_modes) { - local->scan.mode_idx = 0; - local->scan.chan_idx = 0; - } + struct ieee80211_hw_mode *prev_m; + int prev; /* Select next channel - scan only channels marked with W_SCAN flag */ prev = local->scan.chan_idx; - prev_m = local->scan.mode_idx; + prev_m = local->scan.mode; do { - *mode = &local->hw.modes[local->scan.mode_idx]; + *mode = local->scan.mode; local->scan.chan_idx++; if (local->scan.chan_idx >= (*mode)->num_channels) { + struct list_head *next; + local->scan.chan_idx = 0; - local->scan.mode_idx++; - if (local->scan.mode_idx >= local->hw.num_modes) - local->scan.mode_idx = 0; - *mode = &local->hw.modes[local->scan.mode_idx]; + next = (*mode)->list.next; + if (next == &local->modes_list) + next = next->next; + *mode = list_entry(next, + struct ieee80211_hw_mode, + list); + local->scan.mode = *mode; } *chan = &(*mode)->channels[local->scan.chan_idx]; if ((*chan)->flag & IEEE80211_CHAN_W_SCAN) break; } while (local->scan.chan_idx != prev || - local->scan.mode_idx != prev_m); + local->scan.mode != prev_m); } static void ieee80211_scan_start(struct ieee80211_local *local, struct ieee80211_scan_conf *conf) { - int old_mode_idx = local->scan.mode_idx; + struct ieee80211_hw_mode *old_mode = local->scan.mode; int old_chan_idx = local->scan.chan_idx; - struct ieee80211_hw_modes *mode = NULL; + struct ieee80211_hw_mode *mode = NULL; struct ieee80211_channel *chan = NULL; int ret; @@ -189,7 +190,7 @@ static void ieee80211_scan_start(struct if (ret == -EAGAIN) { local->scan.timer.expires = jiffies + (local->scan.interval * HZ / 100); - local->scan.mode_idx = old_mode_idx; + local->scan.mode = old_mode; local->scan.chan_idx = old_chan_idx; } else { printk(KERN_DEBUG "%s: Got unknown error from " @@ -207,23 +208,17 @@ static void ieee80211_scan_start(struct static void ieee80211_scan_stop(struct ieee80211_local *local, struct ieee80211_scan_conf *conf) { - struct ieee80211_hw_modes *mode; + struct ieee80211_hw_mode *mode; struct ieee80211_channel *chan; int wait; if (!local->ops->passive_scan) return; - if (local->scan.mode_idx >= local->hw.num_modes) { - local->scan.mode_idx = 0; - local->scan.chan_idx = 0; - } + mode = local->scan.mode; - mode = &local->hw.modes[local->scan.mode_idx]; - - if (local->scan.chan_idx >= mode->num_channels) { + if (local->scan.chan_idx >= mode->num_channels) local->scan.chan_idx = 0; - } chan = &mode->channels[local->scan.chan_idx]; Index: bu3sch-wireless-dev/net/d80211/ieee80211_sta.c =================================================================== --- bu3sch-wireless-dev.orig/net/d80211/ieee80211_sta.c 2006-12-05 18:09:35.000000000 +0100 +++ bu3sch-wireless-dev/net/d80211/ieee80211_sta.c 2006-12-13 19:40:05.000000000 +0100 @@ -1380,6 +1380,7 @@ static void ieee80211_rx_bss_info(struct if (sdata->type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && (sta = sta_info_get(local, mgmt->sa))) { + struct ieee80211_hw_mode *mode; struct ieee80211_rate *rates; size_t num_rates; u32 supp_rates, prev_rates; @@ -1389,8 +1390,7 @@ static void ieee80211_rx_bss_info(struct num_rates = local->num_curr_rates; oper_mode = local->sta_scanning ? local->scan_oper_phymode : local->hw.conf.phymode; - for (i = 0; i < local->hw.num_modes; i++) { - struct ieee80211_hw_modes *mode = &local->hw.modes[i]; + list_for_each_entry(mode, &local->modes_list, list) { if (oper_mode == mode->mode) { rates = mode->rates; num_rates = mode->num_rates; @@ -1924,10 +1924,10 @@ static void ieee80211_sta_new_auth(struc static int ieee80211_ibss_allowed(struct ieee80211_local *local) { - int m, c; + struct ieee80211_hw_mode *mode; + int c; - for (m = 0; m < local->hw.num_modes; m++) { - struct ieee80211_hw_modes *mode = &local->hw.modes[m]; + list_for_each_entry(mode, &local->modes_list, list) { if (mode->mode != local->hw.conf.phymode) continue; for (c = 0; c < mode->num_channels; c++) { @@ -2383,10 +2383,10 @@ static int ieee80211_sta_restore_oper_ch static int ieee80211_active_scan(struct ieee80211_local *local) { - int m, c; + struct ieee80211_hw_mode *mode; + int c; - for (m = 0; m < local->hw.num_modes; m++) { - struct ieee80211_hw_modes *mode = &local->hw.modes[m]; + list_for_each_entry(mode, &local->modes_list, list) { if (mode->mode != local->hw.conf.phymode) continue; for (c = 0; c < mode->num_channels; c++) { @@ -2433,7 +2433,7 @@ static void ieee80211_sta_scan_work(void struct net_device *dev = ptr; struct ieee80211_local *local = dev->ieee80211_ptr; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_hw_modes *mode; + struct ieee80211_hw_mode *mode; struct ieee80211_channel *chan; int skip; unsigned long next_delay = 0; @@ -2443,10 +2443,9 @@ static void ieee80211_sta_scan_work(void switch (local->scan_state) { case SCAN_SET_CHANNEL: - mode = &local->hw.modes[local->scan_hw_mode_idx]; - if (local->scan_hw_mode_idx >= local->hw.num_modes || - (local->scan_hw_mode_idx + 1 == local->hw.num_modes && - local->scan_channel_idx >= mode->num_channels)) { + mode = local->scan_hw_mode; + if (local->scan_hw_mode->list.next == &local->modes_list && + local->scan_channel_idx >= mode->num_channels) { if (ieee80211_sta_restore_oper_chan(dev)) { printk(KERN_DEBUG "%s: failed to restore " "operational channel after scan\n", @@ -2486,10 +2485,13 @@ static void ieee80211_sta_scan_work(void } local->scan_channel_idx++; - if (local->scan_channel_idx >= - local->hw.modes[local->scan_hw_mode_idx].num_channels) { - local->scan_hw_mode_idx++; - local->scan_channel_idx = 0; + if (local->scan_channel_idx >= local->scan_hw_mode->num_channels) { + if (local->scan_hw_mode->list.next != &local->modes_list) { + local->scan_hw_mode = list_entry(local->scan_hw_mode->list.next, + struct ieee80211_hw_mode, + list); + local->scan_channel_idx = 0; + } } if (skip) @@ -2575,7 +2577,9 @@ int ieee80211_sta_req_scan(struct net_de } else local->scan_ssid_len = 0; local->scan_state = SCAN_SET_CHANNEL; - local->scan_hw_mode_idx = 0; + local->scan_hw_mode = list_entry(local->modes_list.next, + struct ieee80211_hw_mode, + list); local->scan_channel_idx = 0; INIT_WORK(&local->scan_work, ieee80211_sta_scan_work, dev); schedule_work(&local->scan_work); Index: bu3sch-wireless-dev/net/d80211/ieee80211_sysfs.c =================================================================== --- bu3sch-wireless-dev.orig/net/d80211/ieee80211_sysfs.c 2006-12-05 18:09:35.000000000 +0100 +++ bu3sch-wireless-dev/net/d80211/ieee80211_sysfs.c 2006-12-13 19:40:05.000000000 +0100 @@ -189,15 +189,13 @@ __IEEE80211_LOCAL_SHOW(tx_power_reductio static ssize_t ieee80211_local_fmt_modes(struct ieee80211_local *local, char *buf) { - int i; - struct ieee80211_hw_modes *mode; + struct ieee80211_hw_mode *mode; char *p = buf; - /* FIXME: locking against ieee80211_update_hw? */ - for (i = 0; i < local->hw.num_modes; i++) { - mode = &local->hw.modes[i]; + /* FIXME: Locking? Could register a mode in the meantime. */ + list_for_each_entry(mode, &local->modes_list, list) p += sprintf(p, "%s\n", ieee80211_mode_str_short(mode->mode)); - } + return (p - buf); } __IEEE80211_LOCAL_SHOW(modes); - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html