From 1c6b43df0a36ff2c6277b52b132f616c3e105f0f Mon Sep 17 00:00:00 2001 From: Andriy Voskoboinyk Date: Tue, 12 Jan 2016 00:24:40 +0000 Subject: [PATCH] wpi, iwn: implement ic_getradiocaps method This will allow to restore channel list after switching interface to more restrictive regdomain. Tested with Intel 3945BG (wpi) only. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D4863 --- sys/dev/iwn/if_iwn.c | 66 ++++++++++++++++++++++++++++++++++---------- sys/dev/wpi/if_wpi.c | 38 ++++++++++++++++++++----- 2 files changed, 83 insertions(+), 21 deletions(-) diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c index ab630e7f8660..c361fe36aeb7 100644 --- a/sys/dev/iwn/if_iwn.c +++ b/sys/dev/iwn/if_iwn.c @@ -177,11 +177,15 @@ static void iwn4965_print_power_group(struct iwn_softc *, int); #endif static void iwn5000_read_eeprom(struct iwn_softc *); static uint32_t iwn_eeprom_channel_flags(struct iwn_eeprom_chan *); -static void iwn_read_eeprom_band(struct iwn_softc *, int); -static void iwn_read_eeprom_ht40(struct iwn_softc *, int); +static void iwn_read_eeprom_band(struct iwn_softc *, int, int, int *, + struct ieee80211_channel[]); +static void iwn_read_eeprom_ht40(struct iwn_softc *, int, int, int *, + struct ieee80211_channel[]); static void iwn_read_eeprom_channels(struct iwn_softc *, int, uint32_t); static struct iwn_eeprom_chan *iwn_find_eeprom_channel(struct iwn_softc *, struct ieee80211_channel *); +static void iwn_getradiocaps(struct ieee80211com *, int, int *, + struct ieee80211_channel[]); static int iwn_setregdomain(struct ieee80211com *, struct ieee80211_regdomain *, int, struct ieee80211_channel[]); @@ -666,6 +670,7 @@ iwn_attach(device_t dev) ic->ic_set_channel = iwn_set_channel; ic->ic_scan_curchan = iwn_scan_curchan; ic->ic_scan_mindwell = iwn_scan_mindwell; + ic->ic_getradiocaps = iwn_getradiocaps; ic->ic_setregdomain = iwn_setregdomain; iwn_radiotap_attach(sc); @@ -2371,9 +2376,9 @@ iwn_eeprom_channel_flags(struct iwn_eeprom_chan *channel) } static void -iwn_read_eeprom_band(struct iwn_softc *sc, int n) +iwn_read_eeprom_band(struct iwn_softc *sc, int n, int maxchans, int *nchans, + struct ieee80211_channel chans[]) { - struct ieee80211com *ic = &sc->sc_ic; struct iwn_eeprom_chan *channels = sc->eeprom_channels[n]; const struct iwn_chan_band *band = &iwn_bands[n]; struct ieee80211_channel *c; @@ -2390,10 +2395,14 @@ iwn_read_eeprom_band(struct iwn_softc *sc, int n) channels[i].maxpwr); continue; } + + if (*nchans >= maxchans) + break; + chan = band->chan[i]; nflags = iwn_eeprom_channel_flags(&channels[i]); - c = &ic->ic_channels[ic->ic_nchans++]; + c = &chans[(*nchans)++]; c->ic_ieee = chan; c->ic_maxregpower = channels[i].maxpwr; c->ic_maxpower = 2*c->ic_maxregpower; @@ -2402,7 +2411,11 @@ iwn_read_eeprom_band(struct iwn_softc *sc, int n) c->ic_freq = ieee80211_ieee2mhz(chan, IEEE80211_CHAN_G); /* G =>'s B is supported */ c->ic_flags = IEEE80211_CHAN_B | nflags; - c = &ic->ic_channels[ic->ic_nchans++]; + + if (*nchans >= maxchans) + break; + + c = &chans[(*nchans)++]; c[0] = c[-1]; c->ic_flags = IEEE80211_CHAN_G | nflags; } else { /* 5GHz band */ @@ -2418,8 +2431,11 @@ iwn_read_eeprom_band(struct iwn_softc *sc, int n) channels[i].flags, channels[i].maxpwr); if (sc->sc_flags & IWN_FLAG_HAS_11N) { + if (*nchans >= maxchans) + break; + /* add HT20, HT40 added separately */ - c = &ic->ic_channels[ic->ic_nchans++]; + c = &chans[(*nchans)++]; c[0] = c[-1]; c->ic_flags |= IEEE80211_CHAN_HT20; } @@ -2430,7 +2446,8 @@ iwn_read_eeprom_band(struct iwn_softc *sc, int n) } static void -iwn_read_eeprom_ht40(struct iwn_softc *sc, int n) +iwn_read_eeprom_ht40(struct iwn_softc *sc, int n, int maxchans, int *nchans, + struct ieee80211_channel chans[]) { struct ieee80211com *ic = &sc->sc_ic; struct iwn_eeprom_chan *channels = sc->eeprom_channels[n]; @@ -2454,6 +2471,10 @@ iwn_read_eeprom_ht40(struct iwn_softc *sc, int n) channels[i].maxpwr); continue; } + + if (*nchans + 1 >= maxchans) + break; + chan = band->chan[i]; nflags = iwn_eeprom_channel_flags(&channels[i]); @@ -2481,12 +2502,12 @@ iwn_read_eeprom_ht40(struct iwn_softc *sc, int n) "add ht40 chan %d flags 0x%x maxpwr %d\n", chan, channels[i].flags, channels[i].maxpwr); - c = &ic->ic_channels[ic->ic_nchans++]; + c = &chans[(*nchans)++]; c[0] = cent[0]; c->ic_extieee = extc->ic_ieee; c->ic_flags &= ~IEEE80211_CHAN_HT; c->ic_flags |= IEEE80211_CHAN_HT40U | nflags; - c = &ic->ic_channels[ic->ic_nchans++]; + c = &chans[(*nchans)++]; c[0] = extc[0]; c->ic_extieee = cent->ic_ieee; c->ic_flags &= ~IEEE80211_CHAN_HT; @@ -2505,10 +2526,13 @@ iwn_read_eeprom_channels(struct iwn_softc *sc, int n, uint32_t addr) iwn_read_prom_data(sc, addr, &sc->eeprom_channels[n], iwn_bands[n].nchan * sizeof (struct iwn_eeprom_chan)); - if (n < 5) - iwn_read_eeprom_band(sc, n); - else - iwn_read_eeprom_ht40(sc, n); + if (n < 5) { + iwn_read_eeprom_band(sc, n, IEEE80211_CHAN_MAX, &ic->ic_nchans, + ic->ic_channels); + } else { + iwn_read_eeprom_ht40(sc, n, IEEE80211_CHAN_MAX, &ic->ic_nchans, + ic->ic_channels); + } ieee80211_sort_channels(ic->ic_channels, ic->ic_nchans); } @@ -2538,6 +2562,20 @@ iwn_find_eeprom_channel(struct iwn_softc *sc, struct ieee80211_channel *c) return NULL; } +static void +iwn_getradiocaps(struct ieee80211com *ic, + int maxchans, int *nchans, struct ieee80211_channel chans[]) +{ + struct iwn_softc *sc = ic->ic_softc; + int i; + + /* Parse the list of authorized channels. */ + for (i = 0; i < 5 && *nchans < maxchans; i++) + iwn_read_eeprom_band(sc, i, maxchans, nchans, chans); + for (i = 5; i < IWN_NBANDS - 1 && *nchans < maxchans; i++) + iwn_read_eeprom_ht40(sc, i, maxchans, nchans, chans); +} + /* * Enforce flags read from EEPROM. */ diff --git a/sys/dev/wpi/if_wpi.c b/sys/dev/wpi/if_wpi.c index b59d3e6ddf5b..824f75b17532 100644 --- a/sys/dev/wpi/if_wpi.c +++ b/sys/dev/wpi/if_wpi.c @@ -166,10 +166,13 @@ static void wpi_free_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); static int wpi_read_eeprom(struct wpi_softc *, uint8_t macaddr[IEEE80211_ADDR_LEN]); static uint32_t wpi_eeprom_channel_flags(struct wpi_eeprom_chan *); -static void wpi_read_eeprom_band(struct wpi_softc *, uint8_t); +static void wpi_read_eeprom_band(struct wpi_softc *, uint8_t, int, int *, + struct ieee80211_channel[]); static int wpi_read_eeprom_channels(struct wpi_softc *, uint8_t); static struct wpi_eeprom_chan *wpi_find_eeprom_channel(struct wpi_softc *, struct ieee80211_channel *); +static void wpi_getradiocaps(struct ieee80211com *, int, int *, + struct ieee80211_channel[]); static int wpi_setregdomain(struct ieee80211com *, struct ieee80211_regdomain *, int, struct ieee80211_channel[]); @@ -516,6 +519,7 @@ wpi_attach(device_t dev) ic->ic_set_channel = wpi_set_channel; ic->ic_scan_curchan = wpi_scan_curchan; ic->ic_scan_mindwell = wpi_scan_mindwell; + ic->ic_getradiocaps = wpi_getradiocaps; ic->ic_setregdomain = wpi_setregdomain; sc->sc_update_rx_ring = wpi_update_rx_ring; @@ -1417,9 +1421,9 @@ wpi_eeprom_channel_flags(struct wpi_eeprom_chan *channel) } static void -wpi_read_eeprom_band(struct wpi_softc *sc, uint8_t n) +wpi_read_eeprom_band(struct wpi_softc *sc, uint8_t n, int maxchans, + int *nchans, struct ieee80211_channel chans[]) { - struct ieee80211com *ic = &sc->sc_ic; struct wpi_eeprom_chan *channels = sc->eeprom_channels[n]; const struct wpi_chan_band *band = &wpi_bands[n]; struct ieee80211_channel *c; @@ -1434,10 +1438,13 @@ wpi_read_eeprom_band(struct wpi_softc *sc, uint8_t n) continue; } + if (*nchans >= maxchans) + break; + chan = band->chan[i]; nflags = wpi_eeprom_channel_flags(&channels[i]); - c = &ic->ic_channels[ic->ic_nchans++]; + c = &chans[(*nchans)++]; c->ic_ieee = chan; c->ic_maxregpower = channels[i].maxpwr; c->ic_maxpower = 2*c->ic_maxregpower; @@ -1448,7 +1455,11 @@ wpi_read_eeprom_band(struct wpi_softc *sc, uint8_t n) /* G =>'s B is supported */ c->ic_flags = IEEE80211_CHAN_B | nflags; - c = &ic->ic_channels[ic->ic_nchans++]; + + if (*nchans >= maxchans) + break; + + c = &chans[(*nchans)++]; c[0] = c[-1]; c->ic_flags = IEEE80211_CHAN_G | nflags; } else { /* 5GHz band */ @@ -1465,7 +1476,7 @@ wpi_read_eeprom_band(struct wpi_softc *sc, uint8_t n) "adding chan %d (%dMHz) flags=0x%x maxpwr=%d passive=%d," " offset %d\n", chan, c->ic_freq, channels[i].flags, sc->maxpwr[chan], - IEEE80211_IS_CHAN_PASSIVE(c), ic->ic_nchans); + IEEE80211_IS_CHAN_PASSIVE(c), *nchans); } } @@ -1489,7 +1500,8 @@ wpi_read_eeprom_channels(struct wpi_softc *sc, uint8_t n) return error; } - wpi_read_eeprom_band(sc, n); + wpi_read_eeprom_band(sc, n, IEEE80211_CHAN_MAX, &ic->ic_nchans, + ic->ic_channels); ieee80211_sort_channels(ic->ic_channels, ic->ic_nchans); @@ -1511,6 +1523,18 @@ wpi_find_eeprom_channel(struct wpi_softc *sc, struct ieee80211_channel *c) return NULL; } +static void +wpi_getradiocaps(struct ieee80211com *ic, + int maxchans, int *nchans, struct ieee80211_channel chans[]) +{ + struct wpi_softc *sc = ic->ic_softc; + int i; + + /* Parse the list of authorized channels. */ + for (i = 0; i < WPI_CHAN_BANDS_COUNT && *nchans < maxchans; i++) + wpi_read_eeprom_band(sc, i, maxchans, nchans, chans); +} + /* * Enforce flags read from EEPROM. */