hw_features.c

Go to the documentation of this file.
00001 
00017 #include "includes.h"
00018 
00019 #include "hostapd.h"
00020 #include "hw_features.h"
00021 #include "driver.h"
00022 #include "config.h"
00023 #include "ieee802_11.h"
00024 #include "eloop.h"
00025 
00026 
00027 void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
00028                               size_t num_hw_features)
00029 {
00030         size_t i;
00031 
00032         if (hw_features == NULL)
00033                 return;
00034 
00035         for (i = 0; i < num_hw_features; i++) {
00036                 free(hw_features[i].channels);
00037                 free(hw_features[i].rates);
00038         }
00039 
00040         free(hw_features);
00041 }
00042 
00043 
00044 int hostapd_get_hw_features(struct hostapd_iface *iface)
00045 {
00046         struct hostapd_data *hapd = iface->bss[0];
00047         int ret = 0, i, j;
00048         u16 num_modes, flags;
00049         struct hostapd_hw_modes *modes;
00050 
00051         modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
00052         if (modes == NULL) {
00053                 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
00054                                HOSTAPD_LEVEL_DEBUG,
00055                                "Fetching hardware channel/rate support not "
00056                                "supported.");
00057                 return -1;
00058         }
00059 
00060         iface->hw_flags = flags;
00061 
00062         hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
00063         iface->hw_features = modes;
00064         iface->num_hw_features = num_modes;
00065 
00066         for (i = 0; i < num_modes; i++) {
00067                 struct hostapd_hw_modes *feature = &modes[i];
00068                 /* set flag for channels we can use in current regulatory
00069                  * domain */
00070                 for (j = 0; j < feature->num_channels; j++) {
00071                         /* TODO: add regulatory domain lookup */
00072                         unsigned char power_level = 0;
00073                         unsigned char antenna_max = 0;
00074 
00075                         if ((feature->mode == HOSTAPD_MODE_IEEE80211G ||
00076                              feature->mode == HOSTAPD_MODE_IEEE80211B) &&
00077                             feature->channels[j].chan >= 1 &&
00078                             feature->channels[j].chan <= 11) {
00079                                 power_level = 20;
00080                                 feature->channels[j].flag |=
00081                                         HOSTAPD_CHAN_W_SCAN;
00082                         } else
00083                                 feature->channels[j].flag &=
00084                                         ~HOSTAPD_CHAN_W_SCAN;
00085 
00086                         hostapd_set_channel_flag(hapd, feature->mode,
00087                                                  feature->channels[j].chan,
00088                                                  feature->channels[j].flag,
00089                                                  power_level,
00090                                                  antenna_max);
00091                 }
00092         }
00093 
00094         return ret;
00095 }
00096 
00097 
00098 static int hostapd_prepare_rates(struct hostapd_data *hapd,
00099                                  struct hostapd_hw_modes *mode)
00100 {
00101         int i, num_basic_rates = 0;
00102         int basic_rates_a[] = { 60, 120, 240, -1 };
00103         int basic_rates_b[] = { 10, 20, -1 };
00104         int basic_rates_g[] = { 10, 20, 55, 110, -1 };
00105         int *basic_rates;
00106 
00107         if (hapd->iconf->basic_rates)
00108                 basic_rates = hapd->iconf->basic_rates;
00109         else switch (mode->mode) {
00110         case HOSTAPD_MODE_IEEE80211A:
00111                 basic_rates = basic_rates_a;
00112                 break;
00113         case HOSTAPD_MODE_IEEE80211B:
00114                 basic_rates = basic_rates_b;
00115                 break;
00116         case HOSTAPD_MODE_IEEE80211G:
00117                 basic_rates = basic_rates_g;
00118                 break;
00119         default:
00120                 return -1;
00121         }
00122 
00123         if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates,
00124                                   basic_rates, mode->mode)) {
00125                 printf("Failed to update rate sets in kernel module\n");
00126         }
00127 
00128         free(hapd->iface->current_rates);
00129         hapd->iface->num_rates = 0;
00130 
00131         hapd->iface->current_rates =
00132                 malloc(mode->num_rates * sizeof(struct hostapd_rate_data));
00133         if (!hapd->iface->current_rates) {
00134                 printf("Failed to allocate memory for rate table.\n");
00135                 return -1;
00136         }
00137 
00138         for (i = 0; i < mode->num_rates; i++) {
00139                 struct hostapd_rate_data *rate;
00140 
00141                 if (hapd->iconf->supported_rates &&
00142                     !hostapd_rate_found(hapd->iconf->supported_rates,
00143                                         mode->rates[i].rate))
00144                         continue;
00145 
00146                 rate = &hapd->iface->current_rates[hapd->iface->num_rates];
00147                 memcpy(rate, &mode->rates[i],
00148                        sizeof(struct hostapd_rate_data));
00149                 if (hostapd_rate_found(basic_rates, rate->rate)) {
00150                         rate->flags |= HOSTAPD_RATE_BASIC;
00151                         num_basic_rates++;
00152                 } else
00153                         rate->flags &= ~HOSTAPD_RATE_BASIC;
00154                 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
00155                               "RATE[%d] rate=%d flags=0x%x\n",
00156                               hapd->iface->num_rates, rate->rate, rate->flags);
00157                 hapd->iface->num_rates++;
00158         }
00159 
00160         if (hapd->iface->num_rates == 0 || num_basic_rates == 0) {
00161                 printf("No rates remaining in supported/basic rate sets "
00162                        "(%d,%d).\n", hapd->iface->num_rates, num_basic_rates);
00163                 return -1;
00164         }
00165 
00166         return 0;
00167 }
00168 
00169 
00170 static void select_hw_mode_start(void *eloop_data, void *user_ctx);
00171 static void select_hw_mode2_handler(void *eloop_data, void *user_ctx);
00172 
00180 static int select_hw_mode_finalize(struct hostapd_iface *iface, int status)
00181 {
00182         hostapd_iface_cb cb;
00183 
00184         if (!iface->hw_mode_sel_cb)
00185                 return -1;
00186 
00187         eloop_cancel_timeout(select_hw_mode_start, iface, NULL);
00188         eloop_cancel_timeout(select_hw_mode2_handler, iface, NULL);
00189 
00190         cb = iface->hw_mode_sel_cb;
00191 
00192         iface->hw_mode_sel_cb = NULL;
00193 
00194         cb(iface, status);
00195 
00196         return 0;
00197 }
00198 
00199 
00208 static void select_hw_mode2(struct hostapd_iface *iface, int status)
00209 {
00210         int ret = status;
00211         if (ret)
00212                 goto fail;
00213 
00214         if (iface->current_mode == NULL) {
00215                 hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
00216                                HOSTAPD_LEVEL_WARNING,
00217                                "Hardware does not support configured channel");
00218                 ret = -1;
00219                 goto fail;
00220         }
00221 
00222         if (hostapd_prepare_rates(iface->bss[0], iface->current_mode)) {
00223                 printf("Failed to prepare rates table.\n");
00224                 hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
00225                                            HOSTAPD_LEVEL_WARNING,
00226                                            "Failed to prepare rates table.");
00227                 ret = -1;
00228                 goto fail;
00229         }
00230 
00231         ret = hostapd_passive_scan(iface->bss[0], 0,
00232                                    iface->conf->passive_scan_mode,
00233                                    iface->conf->passive_scan_interval,
00234                                    iface->conf->passive_scan_listen,
00235                                    NULL, NULL);
00236         if (ret) {
00237                 printf("Could not set passive scanning: %s\n", strerror(ret));
00238                 ret = 0;
00239         }
00240 
00241 fail:
00242         select_hw_mode_finalize(iface, ret);
00243 }
00244 
00245 
00252 static void select_hw_mode2_handler(void *eloop_data, void *user_ctx)
00253 {
00254         struct hostapd_iface *iface = eloop_data;
00255 
00256         select_hw_mode2(iface, 0);
00257 }
00258 
00259 
00270 static int select_hw_mode1(struct hostapd_iface *iface)
00271 {
00272         int i, j, ok;
00273 
00274         if (iface->num_hw_features < 1)
00275                 return -1;
00276 
00277         iface->current_mode = NULL;
00278         for (i = 0; i < iface->num_hw_features; i++) {
00279                 struct hostapd_hw_modes *mode = &iface->hw_features[i];
00280                 if (mode->mode == (int) iface->conf->hw_mode) {
00281                         iface->current_mode = mode;
00282                         break;
00283                 }
00284         }
00285 
00286         if (iface->current_mode == NULL) {
00287                 printf("Hardware does not support configured mode\n");
00288                 hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
00289                                HOSTAPD_LEVEL_WARNING,
00290                                "Hardware does not support configured mode "
00291                                "(%d)", (int) iface->conf->hw_mode);
00292                 return -1;
00293         }
00294 
00295         ok = 0;
00296         for (j = 0; j < iface->current_mode->num_channels; j++) {
00297                 struct hostapd_channel_data *chan =
00298                         &iface->current_mode->channels[j];
00299                 if ((chan->flag & HOSTAPD_CHAN_W_SCAN) &&
00300                     (chan->chan == iface->conf->channel)) {
00301                         ok = 1;
00302                         break;
00303                 }
00304         }
00305         if (ok == 0 && iface->conf->channel != 0) {
00306                 hostapd_logger(iface->bss[0], NULL,
00307                                HOSTAPD_MODULE_IEEE80211,
00308                                HOSTAPD_LEVEL_WARNING,
00309                                "Configured channel (%d) not found from the "
00310                                "channel list of current mode (%d) %s",
00311                                iface->conf->channel,
00312                                iface->current_mode->mode,
00313                                hostapd_hw_mode_txt(iface->current_mode->mode));
00314                 iface->current_mode = NULL;
00315         }
00316 
00317         /*
00318          * Calls select_hw_mode2() via a handler, so that the function is
00319          * always executed from eloop.
00320          */
00321         eloop_register_timeout(0, 0, select_hw_mode2_handler, iface, NULL);
00322         return 0;
00323 }
00324 
00325 
00335 static void select_hw_mode_start(void *eloop_data, void *user_ctx)
00336 {
00337         struct hostapd_iface *iface = (struct hostapd_iface *)eloop_data;
00338 
00339         int ret;
00340 
00341         ret = select_hw_mode1(iface);
00342         if (ret)
00343                 select_hw_mode_finalize(iface, ret);
00344 }
00345 
00346 
00358 int hostapd_select_hw_mode_start(struct hostapd_iface *iface,
00359                                  hostapd_iface_cb cb)
00360 {
00361         if (iface->hw_mode_sel_cb) {
00362                 wpa_printf(MSG_DEBUG,
00363                            "%s: Hardware mode select already in progress.",
00364                            iface->bss[0]->conf->iface);
00365                 return -1;
00366         }
00367 
00368         iface->hw_mode_sel_cb = cb;
00369 
00370         eloop_register_timeout(0, 0, select_hw_mode_start, iface, NULL);
00371 
00372         return 0;
00373 }
00374 
00375 
00383 int hostapd_select_hw_mode_stop(struct hostapd_iface *iface)
00384 {
00385         return select_hw_mode_finalize(iface, -1);
00386 }
00387 
00388 
00389 const char * hostapd_hw_mode_txt(int mode)
00390 {
00391         switch (mode) {
00392         case HOSTAPD_MODE_IEEE80211A:
00393                 return "IEEE 802.11a";
00394         case HOSTAPD_MODE_IEEE80211B:
00395                 return "IEEE 802.11b";
00396         case HOSTAPD_MODE_IEEE80211G:
00397                 return "IEEE 802.11g";
00398         default:
00399                 return "UNKNOWN";
00400         }
00401 }
00402 
00403 
00404 int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
00405 {
00406         int i;
00407 
00408         if (!hapd->iface->current_mode)
00409                 return 0;
00410 
00411         for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
00412                 struct hostapd_channel_data *ch =
00413                         &hapd->iface->current_mode->channels[i];
00414                 if (ch->chan == chan)
00415                         return ch->freq;
00416         }
00417 
00418         return 0;
00419 }
00420 
00421 
00422 int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
00423 {
00424         int i;
00425 
00426         if (!hapd->iface->current_mode)
00427                 return 0;
00428 
00429         for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
00430                 struct hostapd_channel_data *ch =
00431                         &hapd->iface->current_mode->channels[i];
00432                 if (ch->freq == freq)
00433                         return ch->chan;
00434         }
00435 
00436         return 0;
00437 }
00438 

Generated on Sun Dec 31 13:43:27 2006 for hostapd by  doxygen 1.4.2