[802.11] Clean up channel and rate handling
authorJoshua Oreman <oremanj@xenon.get-linux.org>
Tue, 16 Jun 2009 07:51:35 +0000 (00:51 -0700)
committerJoshua Oreman <oremanj@xenon.get-linux.org>
Tue, 16 Jun 2009 07:51:35 +0000 (00:51 -0700)
src/include/gpxe/net80211.h
src/net/net80211.c

index 5afcf14..250fdc0 100644 (file)
@@ -831,8 +831,9 @@ struct net80211_wlan
 
        /** The channel on which that access point communicates
         *
-        * This is an index into the channels array for the 802.11
-        * device that was used to run the probe.
+        * This is a raw channel number (net80211_channel::channel_nr),
+        * so that it will not be affected by reconfiguration of the
+        * device channels array.
         */
        int channel;
 
index 7736063..5d70dd7 100644 (file)
@@ -133,6 +133,7 @@ static void net80211_print_status ( struct net_device *netdev );
 static void net80211_step_associate ( struct process *proc );
 static void net80211_set_rtscts_rate ( struct net80211_device *dev );
 static void net80211_set_rate_intelligently ( struct net80211_device *dev );
+static int net80211_set_channel_nr ( struct net80211_device *dev, int channel );
 static void net80211_handle_auth ( struct net80211_device *dev,
                                   struct io_buffer *iob );
 static void net80211_handle_assoc_reply ( struct net80211_device *dev,
@@ -291,8 +292,8 @@ static u8 net80211_ll_broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 static inline int net80211_rate_is_erp ( u16 rate ) 
 {
        if ( rate == 10 || rate == 20 || rate == 55 || rate == 110 )
-               return 1;
-       return 0;
+               return 0;
+       return 1;
 }
 
 
@@ -907,7 +908,7 @@ static int net80211_process_ie ( struct net80211_device *dev,
                             dev->channels[dev->channel].channel_nr )
                                break;
                        ds_channel = ie->ds_param.current_channel;
-                       changed |= NET80211_CFG_CHANNEL;
+                       net80211_set_channel_nr ( dev, ds_channel );
                        break;
 
                case IEEE80211_IE_COUNTRY:
@@ -977,15 +978,6 @@ static int net80211_process_ie ( struct net80211_device *dev,
                        changed |= NET80211_CFG_RATE;
        }
 
-       if ( ds_channel ) {
-               for ( i = 0; i < dev->nr_channels; i++ ) {
-                       if ( dev->channels[i].channel_nr == ds_channel ) {
-                               dev->channel = i;
-                               break;
-                       }
-               }
-       }
-
        if ( dev->hw->flags & NET80211_HW_NO_SHORT_PREAMBLE )
                dev->phy_flags &= ~NET80211_PHY_USE_SHORT_PREAMBLE;
        if ( dev->hw->flags & NET80211_HW_NO_SHORT_SLOT )
@@ -1248,7 +1240,7 @@ struct net80211_wlan * net80211_probe ( struct net80211_device *dev,
                wlan->signal = signal;
                wlan->beacon = iob;
                wlan->security = 0; /* XXX implement */
-               wlan->channel = dev->channel;
+               wlan->channel = dev->channels[dev->channel].channel_nr;
                DBGC2 ( dev, "802.11 %p probe: beacon for %s (%s) with "
                        "new best signal %d\n", dev, wlan->essid,
                        eth_ntoa ( wlan->bssid ), wlan->signal );
@@ -1538,13 +1530,14 @@ static void net80211_set_rtscts_rate ( struct net80211_device *dev )
  */
 static void net80211_set_rate_intelligently ( struct net80211_device *dev )
 {
-       int i;
+       int i, oldrate = dev->rate;
 
        if ( dev->nr_rates == 0 ) {
                for ( i = 0; i < dev->hw->nr_supported_rates; i++ ) {
                        u16 rate = dev->hw->supported_rates[i];
                        dev->rates[dev->nr_rates++] = rate;
                }
+               oldrate = -1;   /* always reconfigure */
        }
 
        /* For now, stick with something safe: the last (probably
@@ -1560,6 +1553,35 @@ static void net80211_set_rate_intelligently ( struct net80211_device *dev )
 
        if ( dev->rate == dev->nr_rates ) /* no non-ERP rates */
                dev->rate = 0;  /* first ERP rate */
+
+       if ( dev->rate != oldrate )
+               dev->op->config ( dev, NET80211_CFG_RATE );
+}
+
+/**
+ * Configure 802.11 device to transmit on a certain channel
+ *
+ * @v dev      802.11 device
+ * @v channel  Channel number (1-11 for 2.4GHz) to transmit on
+ */
+int net80211_set_channel_nr ( struct net80211_device *dev, int channel )
+{
+       int i, oldchan = dev->channel;
+
+       for ( i = 0; i < dev->nr_channels; i++ ) {
+               if ( dev->channels[i].channel_nr == channel ) {
+                       dev->channel = i;
+                       break;
+               }
+       }
+
+       if ( i == dev->nr_channels )
+               return -ENOENT;
+
+       if ( i != oldchan )
+               return dev->op->config ( dev, NET80211_CFG_CHANNEL );
+
+       return 0;
 }
 
 /**
@@ -1601,11 +1623,11 @@ int net80211_prepare_default ( struct net80211_device *dev, int band,
        }
 
        dev->channel = 0;
-       dev->nr_rates = 0;
+       dev->op->config ( dev, NET80211_CFG_CHANNEL );
 
+       dev->nr_rates = 0;
        net80211_set_rate_intelligently ( dev );
 
-       dev->op->config ( dev, NET80211_CFG_CHANNEL | NET80211_CFG_RATE );
        return 0;
 }
 
@@ -1633,7 +1655,7 @@ int net80211_prepare ( struct net80211_device *dev,
        /* Barring an IE that tells us the channel outright, assume
           the channel we heard this AP best on is the channel it's
           communicating on. */
-       dev->channel = wlan->channel;
+       net80211_set_channel_nr ( dev, wlan->channel );
 
        rc = net80211_process_capab ( dev, beacon->capability );
        if ( rc )
@@ -2107,6 +2129,8 @@ void net80211_rx ( struct net80211_device *dev, struct io_buffer *iob,
                iob = niob;
        }
 
+       dev->last_signal = signal;
+
        /* Fragments go into the frag cache or get dropped. */
        if ( IEEE80211_FRAG ( hdr->seq ) != 0
             || ( hdr->fc & IEEE80211_FC_MORE_FRAG ) ) {