Main Page | Data Structures | Directories | File List | Data Fields | Globals

hostap_ioctl.c

Go to the documentation of this file.
00001 /* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */
00002 
00003 #ifdef WIRELESS_EXT
00004 
00005 #ifdef in_atomic
00006 /* Get kernel_locked() for in_atomic() */
00007 #include <linux/smp_lock.h>
00008 #endif
00009 
00010 
00011 static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev)
00012 {
00013         struct hostap_interface *iface = dev->priv;
00014         local_info_t *local = iface->local;
00015 
00016         local->wstats.status = 0;
00017         local->wstats.discard.code =
00018                 local->comm_tallies.rx_discards_wep_undecryptable;
00019         local->wstats.discard.misc =
00020                 local->comm_tallies.rx_fcs_errors +
00021                 local->comm_tallies.rx_discards_no_buffer +
00022                 local->comm_tallies.tx_discards_wrong_sa;
00023 
00024 #if WIRELESS_EXT > 11
00025         local->wstats.discard.retries =
00026                 local->comm_tallies.tx_retry_limit_exceeded;
00027         local->wstats.discard.fragment =
00028                 local->comm_tallies.rx_message_in_bad_msg_fragments;
00029 #endif /* WIRELESS_EXT > 11 */
00030 
00031         if (local->iw_mode != IW_MODE_MASTER &&
00032             local->iw_mode != IW_MODE_REPEAT) {
00033                 struct hfa384x_comms_quality sq;
00034 #ifdef in_atomic
00035                 /* FIX: get_rid() will sleep and it must not be called
00036                  * in interrupt context or while atomic. However, this
00037                  * function seems to be called while atomic (at least in Linux
00038                  * 2.5.59). Now, we just avoid illegal call, but in this case
00039                  * the signal quality values are not shown. Statistics could be
00040                  * collected before, if this really needs to be called while
00041                  * atomic. */
00042                 if (in_atomic()) {
00043                         printk(KERN_DEBUG "%s: hostap_get_wireless_stats() "
00044                                "called while atomic - skipping signal "
00045                                "quality query\n", dev->name);
00046                 } else
00047 #endif /* in_atomic */
00048                 if (local->func->get_rid(local->dev,
00049                                                 HFA384X_RID_COMMSQUALITY,
00050                                                 &sq, sizeof(sq), 1) >= 0) {
00051                         local->wstats.qual.qual = le16_to_cpu(sq.comm_qual);
00052                         local->wstats.qual.level = HFA384X_LEVEL_TO_dBm(
00053                                 le16_to_cpu(sq.signal_level));
00054                         local->wstats.qual.noise = HFA384X_LEVEL_TO_dBm(
00055                                 le16_to_cpu(sq.noise_level));
00056                         local->wstats.qual.updated = 7;
00057                 }
00058         }
00059 
00060         return &local->wstats;
00061 }
00062 
00063 
00064 static int prism2_get_datarates(struct net_device *dev, u8 *rates)
00065 {
00066         struct hostap_interface *iface = dev->priv;
00067         local_info_t *local = iface->local;
00068         u8 buf[12];
00069         int len;
00070         u16 val;
00071 
00072         len = local->func->get_rid(dev, HFA384X_RID_SUPPORTEDDATARATES, buf,
00073                                    sizeof(buf), 0);
00074         if (len < 2)
00075                 return 0;
00076 
00077         val = le16_to_cpu(*(u16 *) buf); /* string length */
00078 
00079         if (len - 2 < val || val > 10)
00080                 return 0;
00081 
00082         memcpy(rates, buf + 2, val);
00083         return val;
00084 }
00085 
00086 
00087 static int prism2_get_name(struct net_device *dev,
00088                            struct iw_request_info *info,
00089                            char *name, char *extra)
00090 {
00091         u8 rates[10];
00092         int len, i, over2 = 0;
00093 
00094         len = prism2_get_datarates(dev, rates);
00095 
00096         for (i = 0; i < len; i++) {
00097                 if (rates[i] == 0x0b || rates[i] == 0x16) {
00098                         over2 = 1;
00099                         break;
00100                 }
00101         }
00102 
00103         strcpy(name, over2 ? "IEEE 802.11b" : "IEEE 802.11-DS");
00104 
00105         return 0;
00106 }
00107 
00108 
00109 static void prism2_crypt_delayed_deinit(local_info_t *local,
00110                                         struct prism2_crypt_data **crypt)
00111 {
00112         struct prism2_crypt_data *tmp;
00113         unsigned long flags;
00114 
00115         tmp = *crypt;
00116         *crypt = NULL;
00117 
00118         if (tmp == NULL)
00119                 return;
00120 
00121         /* must not run ops->deinit() while there may be pending encrypt or
00122          * decrypt operations. Use a list of delayed deinits to avoid needing
00123          * locking. */
00124 
00125         spin_lock_irqsave(&local->lock, flags);
00126         list_add(&tmp->list, &local->crypt_deinit_list);
00127         if (!timer_pending(&local->crypt_deinit_timer)) {
00128                 local->crypt_deinit_timer.expires = jiffies + HZ;
00129                 add_timer(&local->crypt_deinit_timer);
00130         }
00131         spin_unlock_irqrestore(&local->lock, flags);
00132 }
00133 
00134 
00135 static int prism2_ioctl_siwencode(struct net_device *dev,
00136                                   struct iw_request_info *info,
00137                                   struct iw_point *erq, char *keybuf)
00138 {
00139         struct hostap_interface *iface = dev->priv;
00140         local_info_t *local = iface->local;
00141         int i;
00142         int first = 0;
00143 
00144         if (erq->flags & IW_ENCODE_DISABLED) {
00145                 prism2_crypt_delayed_deinit(local, &local->crypt);
00146                 goto done;
00147         }
00148 
00149         if (local->crypt != NULL && local->crypt->ops != NULL &&
00150             strcmp(local->crypt->ops->name, "WEP") != 0) {
00151                 /* changing to use WEP; deinit previously used algorithm */
00152                 prism2_crypt_delayed_deinit(local, &local->crypt);
00153         }
00154 
00155         if (local->crypt == NULL) {
00156                 struct prism2_crypt_data *new_crypt;
00157 
00158                 /* take WEP into use */
00159                 new_crypt = (struct prism2_crypt_data *)
00160                         kmalloc(sizeof(struct prism2_crypt_data), GFP_KERNEL);
00161                 if (new_crypt == NULL)
00162                         return -ENOMEM;
00163                 memset(new_crypt, 0, sizeof(struct prism2_crypt_data));
00164                 new_crypt->ops = hostap_get_crypto_ops("WEP");
00165                 if (!new_crypt->ops) {
00166                         request_module("hostap_crypt_wep");
00167                         new_crypt->ops = hostap_get_crypto_ops("WEP");
00168                 }
00169                 if (new_crypt->ops)
00170                         new_crypt->priv = new_crypt->ops->init();
00171                 if (!new_crypt->ops || !new_crypt->priv) {
00172                         kfree(new_crypt);
00173                         new_crypt = NULL;
00174 
00175                         printk(KERN_WARNING "%s: could not initialize WEP: "
00176                                "load module hostap_crypt_wep.o\n",
00177                                dev->name);
00178                         return -EOPNOTSUPP;
00179                 }
00180                 first = 1;
00181                 local->crypt = new_crypt;
00182         }
00183 
00184         i = erq->flags & IW_ENCODE_INDEX;
00185         if (i < 1 || i > 4)
00186                 i = local->crypt->ops->get_key_idx(local->crypt->priv);
00187         else
00188                 i--;
00189         if (i < 0 || i >= WEP_KEYS)
00190                 return -EINVAL;
00191 
00192         if (erq->length > 0) {
00193                 int len = erq->length <= 5 ? 5 : 13;
00194                 if (len > erq->length)
00195                         memset(keybuf + erq->length, 0, len - erq->length);
00196                 local->crypt->ops->set_key(i, keybuf, len, local->crypt->priv);
00197                 if (first)
00198                         local->crypt->ops->set_key_idx(i, local->crypt->priv);
00199         } else {
00200                 if (local->crypt->ops->set_key_idx(i, local->crypt->priv) < 0)
00201                         return -EINVAL; /* keyidx not valid */
00202         }
00203 
00204  done:
00205         local->open_wep = erq->flags & IW_ENCODE_OPEN;
00206 
00207         if (hostap_set_encryption(local)) {
00208                 printk(KERN_DEBUG "%s: set_encryption failed\n", dev->name);
00209                 return -EINVAL;
00210         }
00211 
00212         /* Do not reset port0 if card is in Managed mode since resetting will
00213          * generate new IEEE 802.11 authentication which may end up in looping
00214          * with IEEE 802.1X. Prism2 documentation seem to require port reset
00215          * after WEP configuration. However, keys are apparently changed at
00216          * least in Managed mode. */
00217         if (local->iw_mode != IW_MODE_INFRA && local->func->reset_port(dev)) {
00218                 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
00219                 return -EINVAL;
00220         }
00221 
00222         return 0;
00223 }
00224 
00225 
00226 static int prism2_ioctl_giwencode(struct net_device *dev,
00227                                   struct iw_request_info *info,
00228                                   struct iw_point *erq, char *key)
00229 {
00230         struct hostap_interface *iface = dev->priv;
00231         local_info_t *local = iface->local;
00232         int i, len;
00233         u16 val;
00234 
00235         if (local->crypt == NULL || local->crypt->ops == NULL) {
00236                 erq->length = 0;
00237                 erq->flags = IW_ENCODE_DISABLED;
00238                 return 0;
00239         }
00240 
00241         if (strcmp(local->crypt->ops->name, "WEP") != 0) {
00242                 /* only WEP is supported with wireless extensions, so just
00243                  * report that encryption is used */
00244                 erq->length = 0;
00245                 erq->flags = IW_ENCODE_ENABLED;
00246                 return 0;
00247         }
00248 
00249         i = erq->flags & IW_ENCODE_INDEX;
00250         if (i < 1 || i > 4)
00251                 i = local->crypt->ops->get_key_idx(local->crypt->priv);
00252         else
00253                 i--;
00254         if (i < 0 || i >= WEP_KEYS)
00255                 return -EINVAL;
00256 
00257         erq->flags = i + 1;
00258 
00259         /* Reads from HFA384X_RID_CNFDEFAULTKEY* return bogus values, so show
00260          * the keys from driver buffer */
00261         len = local->crypt->ops->get_key(i, key, WEP_KEY_LEN,
00262                                          local->crypt->priv);
00263         erq->length = (len >= 0 ? len : 0);
00264 
00265         if (local->func->get_rid(dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, 1) < 0)
00266         {
00267                 printk("CNFWEPFLAGS reading failed\n");
00268                 return -EOPNOTSUPP;
00269         }
00270         le16_to_cpus(&val);
00271         if (val & HFA384X_WEPFLAGS_PRIVACYINVOKED)
00272                 erq->flags |= IW_ENCODE_ENABLED;
00273         else
00274                 erq->flags |= IW_ENCODE_DISABLED;
00275         if (val & HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED)
00276                 erq->flags |= IW_ENCODE_RESTRICTED;
00277         else
00278                 erq->flags |= IW_ENCODE_OPEN;
00279 
00280         return 0;
00281 }
00282 
00283 
00284 #if WIRELESS_EXT <= 15
00285 static int prism2_ioctl_giwspy(struct net_device *dev,
00286                                struct iw_request_info *info,
00287                                struct iw_point *srq, char *extra)
00288 {
00289         struct hostap_interface *iface = dev->priv;
00290         local_info_t *local = iface->local;
00291         struct sockaddr addr[IW_MAX_SPY];
00292         struct iw_quality qual[IW_MAX_SPY];
00293 
00294         if (local->iw_mode != IW_MODE_MASTER) {
00295                 printk("SIOCGIWSPY is currently only supported in Host AP "
00296                        "mode\n");
00297                 srq->length = 0;
00298                 return -EOPNOTSUPP;
00299         }
00300 
00301         srq->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_SPY, 0);
00302 
00303         memcpy(extra, &addr, sizeof(addr[0]) * srq->length);
00304         memcpy(extra + sizeof(addr[0]) * srq->length, &qual,
00305                sizeof(qual[0]) * srq->length);
00306 
00307         return 0;
00308 }
00309 #endif /* WIRELESS_EXT <= 15 */
00310 
00311 
00312 static int hostap_set_rate(struct net_device *dev)
00313 {
00314         struct hostap_interface *iface = dev->priv;
00315         local_info_t *local = iface->local;
00316         int ret, basic_rates;
00317 
00318         basic_rates = local->basic_rates & local->tx_rate_control;
00319         if (!basic_rates || basic_rates != local->basic_rates) {
00320                 printk(KERN_INFO "%s: updating basic rate set automatically "
00321                        "to match with the new supported rate set\n",
00322                        dev->name);
00323                 if (!basic_rates)
00324                         basic_rates = local->tx_rate_control;
00325 
00326                 local->basic_rates = basic_rates;
00327                 if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
00328                                     basic_rates))
00329                         printk(KERN_WARNING "%s: failed to set "
00330                                "cnfBasicRates\n", dev->name);
00331         }
00332 
00333         ret = (hostap_set_word(dev, HFA384X_RID_TXRATECONTROL,
00334                                local->tx_rate_control) ||
00335                hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES,
00336                                local->tx_rate_control) ||
00337                local->func->reset_port(dev));
00338                 
00339         if (ret) {
00340                 printk(KERN_WARNING "%s: TXRateControl/cnfSupportedRates "
00341                        "setting to 0x%x failed\n",
00342                        dev->name, local->tx_rate_control);
00343         }
00344 
00345         /* Update TX rate configuration for all STAs based on new operational
00346          * rate set. */
00347         hostap_update_rates(local);
00348 
00349         return ret;
00350 }
00351 
00352 
00353 static int prism2_ioctl_siwrate(struct net_device *dev,
00354                                 struct iw_request_info *info,
00355                                 struct iw_param *rrq, char *extra)
00356 {
00357         struct hostap_interface *iface = dev->priv;
00358         local_info_t *local = iface->local;
00359 
00360         if (rrq->fixed) {
00361                 switch (rrq->value) {
00362                 case 11000000:
00363                         local->tx_rate_control = HFA384X_RATES_11MBPS;
00364                         break;
00365                 case 5500000:
00366                         local->tx_rate_control = HFA384X_RATES_5MBPS;
00367                         break;
00368                 case 2000000:
00369                         local->tx_rate_control = HFA384X_RATES_2MBPS;
00370                         break;
00371                 case 1000000:
00372                         local->tx_rate_control = HFA384X_RATES_1MBPS;
00373                         break;
00374                 default:
00375                         local->tx_rate_control = HFA384X_RATES_1MBPS |
00376                                 HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
00377                                 HFA384X_RATES_11MBPS;
00378                         break;
00379                 }
00380         } else {
00381                 switch (rrq->value) {
00382                 case 11000000:
00383                         local->tx_rate_control = HFA384X_RATES_1MBPS |
00384                                 HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
00385                                 HFA384X_RATES_11MBPS;
00386                         break;
00387                 case 5500000:
00388                         local->tx_rate_control = HFA384X_RATES_1MBPS |
00389                                 HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS;
00390                         break;
00391                 case 2000000:
00392                         local->tx_rate_control = HFA384X_RATES_1MBPS |
00393                                 HFA384X_RATES_2MBPS;
00394                         break;
00395                 case 1000000:
00396                         local->tx_rate_control = HFA384X_RATES_1MBPS;
00397                         break;
00398                 default:
00399                         local->tx_rate_control = HFA384X_RATES_1MBPS |
00400                                 HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
00401                                 HFA384X_RATES_11MBPS;
00402                         break;
00403                 }
00404         }
00405 
00406         return hostap_set_rate(dev);
00407 }
00408 
00409 
00410 static int prism2_ioctl_giwrate(struct net_device *dev,
00411                                 struct iw_request_info *info,
00412                                 struct iw_param *rrq, char *extra)
00413 {
00414         u16 val;
00415         struct hostap_interface *iface = dev->priv;
00416         local_info_t *local = iface->local;
00417         int ret = 0;
00418 
00419         if (local->func->get_rid(dev, HFA384X_RID_TXRATECONTROL, &val, 2, 1) <
00420             0)
00421                 return -EINVAL;
00422 
00423         if ((val & 0x1) && (val > 1))
00424                 rrq->fixed = 0;
00425         else
00426                 rrq->fixed = 1;
00427 
00428         if (local->iw_mode == IW_MODE_MASTER && local->ap != NULL &&
00429             !local->fw_tx_rate_control) {
00430                 /* HFA384X_RID_CURRENTTXRATE seems to always be 2 Mbps in
00431                  * Host AP mode, so use the recorded TX rate of the last sent
00432                  * frame */
00433                 rrq->value = local->ap->last_tx_rate > 0 ?
00434                         local->ap->last_tx_rate * 100000 : 11000000;
00435                 return 0;
00436         }
00437 
00438         if (local->func->get_rid(dev, HFA384X_RID_CURRENTTXRATE, &val, 2, 1) <
00439             0)
00440                 return -EINVAL;
00441 
00442         switch (val) {
00443         case HFA384X_RATES_1MBPS:
00444                 rrq->value = 1000000;
00445                 break;
00446         case HFA384X_RATES_2MBPS:
00447                 rrq->value = 2000000;
00448                 break;
00449         case HFA384X_RATES_5MBPS:
00450                 rrq->value = 5500000;
00451                 break;
00452         case HFA384X_RATES_11MBPS:
00453                 rrq->value = 11000000;
00454                 break;
00455         default:
00456                 /* should not happen */
00457                 rrq->value = 11000000;
00458                 ret = -EINVAL;
00459                 break;
00460         }
00461 
00462         return ret;
00463 }
00464 
00465 
00466 static int prism2_ioctl_siwsens(struct net_device *dev,
00467                                 struct iw_request_info *info,
00468                                 struct iw_param *sens, char *extra)
00469 {
00470         struct hostap_interface *iface = dev->priv;
00471         local_info_t *local = iface->local;
00472 
00473         /* Set the desired AP density */
00474         if (sens->value < 1 || sens->value > 3)
00475                 return -EINVAL;
00476 
00477         if (hostap_set_word(dev, HFA384X_RID_CNFSYSTEMSCALE, sens->value) ||
00478             local->func->reset_port(dev))
00479                 return -EINVAL;
00480 
00481         return 0;
00482 }
00483 
00484 static int prism2_ioctl_giwsens(struct net_device *dev,
00485                                 struct iw_request_info *info,
00486                                 struct iw_param *sens, char *extra)
00487 {
00488         struct hostap_interface *iface = dev->priv;
00489         local_info_t *local = iface->local;
00490         u16 val;
00491 
00492         /* Get the current AP density */
00493         if (local->func->get_rid(dev, HFA384X_RID_CNFSYSTEMSCALE, &val, 2, 1) <
00494             0)
00495                 return -EINVAL;
00496 
00497         sens->value = __le16_to_cpu(val);
00498         sens->fixed = 1;
00499 
00500         return 0;
00501 }
00502 
00503 
00504 /* Deprecated in new wireless extension API */
00505 static int prism2_ioctl_giwaplist(struct net_device *dev,
00506                                   struct iw_request_info *info,
00507                                   struct iw_point *data, char *extra)
00508 {
00509         struct hostap_interface *iface = dev->priv;
00510         local_info_t *local = iface->local;
00511         struct sockaddr addr[IW_MAX_AP];
00512         struct iw_quality qual[IW_MAX_AP];
00513 
00514         if (local->iw_mode != IW_MODE_MASTER) {
00515                 printk(KERN_DEBUG "SIOCGIWAPLIST is currently only supported "
00516                        "in Host AP mode\n");
00517                 data->length = 0;
00518                 return -EOPNOTSUPP;
00519         }
00520 
00521         data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1);
00522 
00523         memcpy(extra, &addr, sizeof(addr[0]) * data->length);
00524         data->flags = 1; /* has quality information */
00525         memcpy(extra + sizeof(addr[0]) * data->length, &qual,
00526                sizeof(qual[0]) * data->length);
00527 
00528         return 0;
00529 }
00530 
00531 
00532 static int prism2_ioctl_siwrts(struct net_device *dev,
00533                                struct iw_request_info *info,
00534                                struct iw_param *rts, char *extra)
00535 {
00536         struct hostap_interface *iface = dev->priv;
00537         local_info_t *local = iface->local;
00538         u16 val;
00539 
00540         if (rts->disabled)
00541                 val = __constant_cpu_to_le16(2347);
00542         else if (rts->value < 0 || rts->value > 2347)
00543                 return -EINVAL;
00544         else
00545                 val = __cpu_to_le16(rts->value);
00546 
00547         if (local->func->set_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2) ||
00548             local->func->reset_port(dev))
00549                 return -EINVAL;
00550 
00551         local->rts_threshold = rts->value;
00552 
00553         return 0;
00554 }
00555 
00556 static int prism2_ioctl_giwrts(struct net_device *dev,
00557                                struct iw_request_info *info,
00558                                struct iw_param *rts, char *extra)
00559 {
00560         struct hostap_interface *iface = dev->priv;
00561         local_info_t *local = iface->local;
00562         u16 val;
00563 
00564         if (local->func->get_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2, 1) <
00565             0)
00566                 return -EINVAL;
00567 
00568         rts->value = __le16_to_cpu(val);
00569         rts->disabled = (rts->value == 2347);
00570         rts->fixed = 1;
00571 
00572         return 0;
00573 }
00574 
00575 
00576 static int prism2_ioctl_siwfrag(struct net_device *dev,
00577                                 struct iw_request_info *info,
00578                                 struct iw_param *rts, char *extra)
00579 {
00580         struct hostap_interface *iface = dev->priv;
00581         local_info_t *local = iface->local;
00582         u16 val;
00583 
00584         if (rts->disabled)
00585                 val = __constant_cpu_to_le16(2346);
00586         else if (rts->value < 256 || rts->value > 2346)
00587                 return -EINVAL;
00588         else
00589                 val = __cpu_to_le16(rts->value & ~0x1); /* even numbers only */
00590 
00591         local->fragm_threshold = rts->value & ~0x1;
00592         if (local->func->set_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, &val,
00593                                  2)
00594             || local->func->reset_port(dev))
00595                 return -EINVAL;
00596 
00597         return 0;
00598 }
00599 
00600 static int prism2_ioctl_giwfrag(struct net_device *dev,
00601                                 struct iw_request_info *info,
00602                                 struct iw_param *rts, char *extra)
00603 {
00604         struct hostap_interface *iface = dev->priv;
00605         local_info_t *local = iface->local;
00606         u16 val;
00607 
00608         if (local->func->get_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
00609                                  &val, 2, 1) < 0)
00610                 return -EINVAL;
00611 
00612         rts->value = __le16_to_cpu(val);
00613         rts->disabled = (rts->value == 2346);
00614         rts->fixed = 1;
00615 
00616         return 0;
00617 }
00618 
00619 
00620 static int hostap_join_ap(struct net_device *dev)
00621 {
00622         struct hostap_interface *iface = dev->priv;
00623         local_info_t *local = iface->local;
00624         struct hfa384x_join_request req;
00625         unsigned long flags;
00626         int i;
00627         struct hfa384x_scan_result *entry;
00628 
00629         memcpy(req.bssid, local->preferred_ap, ETH_ALEN);
00630         req.channel = 0;
00631 
00632         spin_lock_irqsave(&local->lock, flags);
00633         for (i = 0; i < local->last_scan_results_count; i++) {
00634                 if (!local->last_scan_results)
00635                         break;
00636                 entry = &local->last_scan_results[i];
00637                 if (memcmp(local->preferred_ap, entry->bssid, ETH_ALEN) == 0) {
00638                         req.channel = entry->chid;
00639                         break;
00640                 }
00641         }
00642         spin_unlock_irqrestore(&local->lock, flags);
00643 
00644         if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
00645                                  sizeof(req))) {
00646                 printk(KERN_DEBUG "%s: JoinRequest " MACSTR
00647                        " failed\n",
00648                        dev->name, MAC2STR(local->preferred_ap));
00649                 return -1;
00650         }
00651 
00652         printk(KERN_DEBUG "%s: Trying to join BSSID " MACSTR "\n",
00653                dev->name, MAC2STR(local->preferred_ap));
00654 
00655         return 0;
00656 }
00657 
00658 
00659 static int prism2_ioctl_siwap(struct net_device *dev,
00660                               struct iw_request_info *info,
00661                               struct sockaddr *ap_addr, char *extra)
00662 {
00663 #ifdef PRISM2_NO_STATION_MODES
00664         return -EOPNOTSUPP;
00665 #else /* PRISM2_NO_STATION_MODES */
00666         struct hostap_interface *iface = dev->priv;
00667         local_info_t *local = iface->local;
00668 
00669         memcpy(local->preferred_ap, &ap_addr->sa_data, ETH_ALEN);
00670 
00671         if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) {
00672                 struct hfa384x_scan_request scan_req;
00673                 memset(&scan_req, 0, sizeof(scan_req));
00674                 scan_req.channel_list = __constant_cpu_to_le16(0x3fff);
00675                 scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS);
00676                 if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST,
00677                                          &scan_req, sizeof(scan_req))) {
00678                         printk(KERN_DEBUG "%s: ScanResults request failed - "
00679                                "preferred AP delayed to next unsolicited "
00680                                "scan\n", dev->name);
00681                 }
00682         } else if (local->host_roaming == 2 &&
00683                    local->iw_mode == IW_MODE_INFRA) {
00684                 if (hostap_join_ap(dev))
00685                         return -EINVAL;
00686         } else {
00687                 printk(KERN_DEBUG "%s: Preferred AP (SIOCSIWAP) is used only "
00688                        "in Managed mode when host_roaming is enabled\n",
00689                        dev->name);
00690         }
00691 
00692         return 0;
00693 #endif /* PRISM2_NO_STATION_MODES */
00694 }
00695 
00696 static int prism2_ioctl_giwap(struct net_device *dev,
00697                               struct iw_request_info *info,
00698                               struct sockaddr *ap_addr, char *extra)
00699 {
00700         struct hostap_interface *iface = dev->priv;
00701         local_info_t *local = iface->local;
00702 
00703         if (dev == local->stadev) {
00704                 memcpy(&ap_addr->sa_data, local->assoc_ap_addr, ETH_ALEN);
00705                 ap_addr->sa_family = ARPHRD_ETHER;
00706                 return 0;
00707         }
00708 
00709         if (local->func->get_rid(dev, HFA384X_RID_CURRENTBSSID,
00710                                  &ap_addr->sa_data, ETH_ALEN, 1) < 0)
00711                 return -EOPNOTSUPP;
00712 
00713         /* local->bssid is also updated in LinkStatus handler when in station
00714          * mode */
00715         memcpy(local->bssid, &ap_addr->sa_data, ETH_ALEN);
00716         ap_addr->sa_family = ARPHRD_ETHER;
00717 
00718         return 0;
00719 }
00720 
00721 
00722 static int prism2_ioctl_siwnickn(struct net_device *dev,
00723                                  struct iw_request_info *info,
00724                                  struct iw_point *data, char *nickname)
00725 {
00726         struct hostap_interface *iface = dev->priv;
00727         local_info_t *local = iface->local;
00728 
00729         memset(local->name, 0, sizeof(local->name));
00730         memcpy(local->name, nickname, data->length);
00731         local->name_set = 1;
00732 
00733         if (hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, local->name) ||
00734             local->func->reset_port(dev))
00735                 return -EINVAL;
00736 
00737         return 0;
00738 }
00739 
00740 static int prism2_ioctl_giwnickn(struct net_device *dev,
00741                                  struct iw_request_info *info,
00742                                  struct iw_point *data, char *nickname)
00743 {
00744         struct hostap_interface *iface = dev->priv;
00745         local_info_t *local = iface->local;
00746         int len;
00747         char name[MAX_NAME_LEN + 3];
00748         u16 val;
00749 
00750         len = local->func->get_rid(dev, HFA384X_RID_CNFOWNNAME,
00751                                    &name, MAX_NAME_LEN + 2, 0);
00752         val = __le16_to_cpu(*(u16 *) name);
00753         if (len > MAX_NAME_LEN + 2 || len < 0 || val > MAX_NAME_LEN)
00754                 return -EOPNOTSUPP;
00755 
00756         name[val + 2] = '\0';
00757         data->length = val + 1;
00758         memcpy(nickname, name + 2, val + 1);
00759 
00760         return 0;
00761 }
00762 
00763 
00764 static int prism2_ioctl_siwfreq(struct net_device *dev,
00765                                 struct iw_request_info *info,
00766                                 struct iw_freq *freq, char *extra)
00767 {
00768         struct hostap_interface *iface = dev->priv;
00769         local_info_t *local = iface->local;
00770 
00771         /* freq => chan. */
00772         if (freq->e == 1 &&
00773             freq->m / 100000 >= freq_list[0] &&
00774             freq->m / 100000 <= freq_list[FREQ_COUNT - 1]) {
00775                 int ch;
00776                 int fr = freq->m / 100000;
00777                 for (ch = 0; ch < FREQ_COUNT; ch++) {
00778                         if (fr == freq_list[ch]) {
00779                                 freq->e = 0;
00780                                 freq->m = ch + 1;
00781                                 break;
00782                         }
00783                 }
00784         }
00785 
00786         if (freq->e != 0 || freq->m < 1 || freq->m > FREQ_COUNT ||
00787             !(local->channel_mask & (1 << (freq->m - 1))))
00788                 return -EINVAL;
00789 
00790         local->channel = freq->m; /* channel is used in prism2_setup_rids() */
00791         if (hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel) ||
00792             local->func->reset_port(dev))
00793                 return -EINVAL;
00794 
00795         return 0;
00796 }
00797 
00798 static int prism2_ioctl_giwfreq(struct net_device *dev,
00799                                 struct iw_request_info *info,
00800                                 struct iw_freq *freq, char *extra)
00801 {
00802         struct hostap_interface *iface = dev->priv;
00803         local_info_t *local = iface->local;
00804         u16 val;
00805 
00806         if (local->func->get_rid(dev, HFA384X_RID_CURRENTCHANNEL, &val, 2, 1) <
00807             0)
00808                 return -EINVAL;
00809 
00810         le16_to_cpus(&val);
00811         if (val < 1 || val > FREQ_COUNT)
00812                 return -EINVAL;
00813 
00814         freq->m = freq_list[val - 1] * 100000;
00815         freq->e = 1;
00816 
00817         return 0;
00818 }
00819 
00820 #ifndef ARPHRD_IEEE80211_RADIOTAP
00821 #define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */
00822 #endif /* ARPHRD_IEEE80211_RADIOTAP */
00823 
00824 
00825 static void hostap_monitor_set_type(local_info_t *local)
00826 {
00827         struct net_device *dev = local->dev;
00828 
00829         if (local->monitor_type == PRISM2_MONITOR_PRISM ||
00830             local->monitor_type == PRISM2_MONITOR_CAPHDR) {
00831                 dev->type = ARPHRD_IEEE80211_RADIOTAP;
00832                 dev->hard_header_parse =
00833                         hostap_80211_prism_header_parse;
00834         } else {
00835                 dev->type = ARPHRD_IEEE80211;
00836                 dev->hard_header_parse = hostap_80211_header_parse;
00837         }
00838 }
00839 
00840 
00841 static int prism2_ioctl_siwessid(struct net_device *dev,
00842                                  struct iw_request_info *info,
00843                                  struct iw_point *data, char *ssid)
00844 {
00845         struct hostap_interface *iface = dev->priv;
00846         local_info_t *local = iface->local;
00847 
00848         if (data->flags == 0)
00849                 ssid[0] = '\0'; /* ANY */
00850 
00851         if (local->iw_mode == IW_MODE_MASTER && ssid[0] == '\0') {
00852                 /* Setting SSID to empty string seems to kill the card in
00853                  * Host AP mode */
00854                 printk(KERN_DEBUG "%s: Host AP mode does not support "
00855                        "'Any' essid\n", dev->name);
00856                 return -EINVAL;
00857         }
00858 
00859         memcpy(local->essid, ssid, data->length);
00860         local->essid[data->length] = '\0';
00861 
00862         if ((!local->fw_ap &&
00863              hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, local->essid))
00864             || hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, local->essid) ||
00865             local->func->reset_port(dev))
00866                 return -EINVAL;
00867 
00868         return 0;
00869 }
00870 
00871 static int prism2_ioctl_giwessid(struct net_device *dev,
00872                                  struct iw_request_info *info,
00873                                  struct iw_point *data, char *essid)
00874 {
00875         struct hostap_interface *iface = dev->priv;
00876         local_info_t *local = iface->local;
00877         u16 val;
00878 
00879         data->flags = 1; /* active */
00880         if (local->iw_mode == IW_MODE_MASTER) {
00881                 data->length = strlen(local->essid);
00882                 memcpy(essid, local->essid, IW_ESSID_MAX_SIZE);
00883         } else {
00884                 int len;
00885                 char ssid[MAX_SSID_LEN + 2];
00886                 memset(ssid, 0, sizeof(ssid));
00887                 len = local->func->get_rid(dev, HFA384X_RID_CURRENTSSID,
00888                                            &ssid, MAX_SSID_LEN + 2, 0);
00889                 val = __le16_to_cpu(*(u16 *) ssid);
00890                 if (len > MAX_SSID_LEN + 2 || len < 0 || val > MAX_SSID_LEN) {
00891                         return -EOPNOTSUPP;
00892                 }
00893                 data->length = val;
00894                 memcpy(essid, ssid + 2, IW_ESSID_MAX_SIZE);
00895         }
00896 
00897         return 0;
00898 }
00899 
00900 
00901 static int prism2_ioctl_giwrange(struct net_device *dev,
00902                                  struct iw_request_info *info,
00903                                  struct iw_point *data, char *extra)
00904 {
00905         struct hostap_interface *iface = dev->priv;
00906         local_info_t *local = iface->local;
00907         struct iw_range *range = (struct iw_range *) extra;
00908         u8 rates[10];
00909         u16 val;
00910         int i, len, over2;
00911 
00912         data->length = sizeof(struct iw_range);
00913         memset(range, 0, sizeof(struct iw_range));
00914 
00915 #if WIRELESS_EXT > 9
00916         /* TODO: could fill num_txpower and txpower array with
00917          * something; however, there are 128 different values.. */
00918 
00919         range->txpower_capa = IW_TXPOW_DBM;
00920 
00921         if (local->iw_mode == IW_MODE_INFRA || local->iw_mode == IW_MODE_ADHOC)
00922         {
00923                 range->min_pmp = 1 * 1024;
00924                 range->max_pmp = 65535 * 1024;
00925                 range->min_pmt = 1 * 1024;
00926                 range->max_pmt = 1000 * 1024;
00927                 range->pmp_flags = IW_POWER_PERIOD;
00928                 range->pmt_flags = IW_POWER_TIMEOUT;
00929                 range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT |
00930                         IW_POWER_UNICAST_R | IW_POWER_ALL_R;
00931         }
00932 #endif /* WIRELESS_EXT > 9 */
00933 
00934 #if WIRELESS_EXT > 10
00935         range->we_version_compiled = WIRELESS_EXT;
00936         range->we_version_source = 13;
00937 
00938         range->retry_capa = IW_RETRY_LIMIT;
00939         range->retry_flags = IW_RETRY_LIMIT;
00940         range->min_retry = 0;
00941         range->max_retry = 255;
00942 #endif /* WIRELESS_EXT > 10 */
00943 
00944         range->num_channels = FREQ_COUNT;
00945 
00946         val = 0;
00947         for (i = 0; i < FREQ_COUNT; i++) {
00948                 if (local->channel_mask & (1 << i)) {
00949                         range->freq[val].i = i + 1;
00950                         range->freq[val].m = freq_list[i] * 100000;
00951                         range->freq[val].e = 1;
00952                         val++;
00953                 }
00954                 if (val == IW_MAX_FREQUENCIES)
00955                         break;
00956         }
00957         range->num_frequency = val;
00958 
00959         range->max_qual.qual = 92; /* 0 .. 92 */
00960         range->max_qual.level = 154; /* 27 .. 154 */
00961         range->max_qual.noise = 154; /* 27 .. 154 */
00962         range->sensitivity = 3;
00963 
00964         range->max_encoding_tokens = WEP_KEYS;
00965         range->num_encoding_sizes = 2;
00966         range->encoding_size[0] = 5;
00967         range->encoding_size[1] = 13;
00968 
00969         over2 = 0;
00970         len = prism2_get_datarates(dev, rates);
00971         range->num_bitrates = 0;
00972         for (i = 0; i < len; i++) {
00973                 if (range->num_bitrates < IW_MAX_BITRATES) {
00974                         range->bitrate[range->num_bitrates] =
00975                                 rates[i] * 500000;
00976                         range->num_bitrates++;
00977                 }
00978                 if (rates[i] == 0x0b || rates[i] == 0x16)
00979                         over2 = 1;
00980         }
00981         /* estimated maximum TCP throughput values (bps) */
00982         range->throughput = over2 ? 5500000 : 1500000;
00983 
00984         range->min_rts = 0;
00985         range->max_rts = 2347;
00986         range->min_frag = 256;
00987         range->max_frag = 2346;
00988 
00989         return 0;
00990 }
00991 
00992 
00993 static int hostap_monitor_mode_enable(local_info_t *local)
00994 {
00995         struct net_device *dev = local->dev;
00996 
00997         printk(KERN_DEBUG "Enabling monitor mode\n");
00998         hostap_monitor_set_type(local);
00999 
01000         if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
01001                             HFA384X_PORTTYPE_PSEUDO_IBSS)) {
01002                 printk(KERN_DEBUG "Port type setting for monitor mode "
01003                        "failed\n");
01004                 return -EOPNOTSUPP;
01005         }
01006 
01007         /* Host decrypt is needed to get the IV and ICV fields;
01008          * however, monitor mode seems to remove WEP flag from frame
01009          * control field */
01010         if (hostap_set_word(dev, HFA384X_RID_CNFWEPFLAGS,
01011                             HFA384X_WEPFLAGS_HOSTENCRYPT |
01012                             HFA384X_WEPFLAGS_HOSTDECRYPT)) {
01013                 printk(KERN_DEBUG "WEP flags setting failed\n");
01014                 return -EOPNOTSUPP;
01015         }
01016 
01017         if (local->func->reset_port(dev) ||
01018             local->func->cmd(dev, HFA384X_CMDCODE_TEST |
01019                              (HFA384X_TEST_MONITOR << 8),
01020                              0, NULL, NULL)) {
01021                 printk(KERN_DEBUG "Setting monitor mode failed\n");
01022                 return -EOPNOTSUPP;
01023         }
01024 
01025         return 0;
01026 }
01027 
01028 
01029 static int hostap_monitor_mode_disable(local_info_t *local)
01030 {
01031         struct net_device *dev = local->dev;
01032 
01033         printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name);
01034         dev->type = ARPHRD_IEEE80211_RADIOTAP;
01035         dev->hard_header_parse = local->saved_eth_header_parse;
01036         if (local->func->cmd(dev, HFA384X_CMDCODE_TEST |
01037                              (HFA384X_TEST_STOP << 8),
01038                              0, NULL, NULL))
01039                 return -1;
01040         return hostap_set_encryption(local);
01041 }
01042 
01043 
01044 static int hostap_dssstest_mode_enable(local_info_t *local)
01045 {
01046   struct net_device *dev = local->dev;               
01047   
01048   if (!local->dev_enabled) {
01049     printk(KERN_DEBUG "%s: Device must be up for DSSS test mode\n",
01050            dev->name);
01051                         return -ENETDOWN;
01052   }
01053 
01054   printk(KERN_DEBUG "%s: Enabling DSSS test mode\n", dev->name);
01055   /* Send a nice 101010.... pattern */
01056   if (local->func->cmd(dev, HFA384X_CMDCODE_TEST |
01057                        (HFA384X_TEST_XMIT << 8),
01058                        0xAAAA, NULL, NULL)) {
01059     printk(KERN_DEBUG "%s: Setting DSSS-test mode failed\n",
01060            dev->name);
01061     return -EOPNOTSUPP;
01062   }
01063   
01064   return 0;
01065 }
01066 
01067 
01068 static int hostap_dssstest_mode_disable(local_info_t *local)
01069 {
01070   struct net_device *dev = local->dev;
01071   
01072   if (dev == NULL)
01073     return -1;
01074   
01075   printk(KERN_DEBUG "%s: Disabling DSSS test mode.\n", dev->name);
01076   
01077   
01078   if (local->func->cmd(dev, HFA384X_CMDCODE_TEST |
01079                        (HFA384X_TEST_STOP << 8),
01080                        0, NULL, NULL)) {
01081     printk(KERN_DEBUG "%s: Disable DSSS-test mode failed.\n",
01082            dev->name);
01083     return -1;
01084   }
01085   
01086   return 0;
01087 }
01088 
01089 
01090 static int prism2_ioctl_siwmode(struct net_device *dev,
01091                                 struct iw_request_info *info,
01092                                 __u32 *mode, char *extra)
01093 {
01094         struct hostap_interface *iface = dev->priv;
01095         local_info_t *local = iface->local;
01096         int double_reset = 0;
01097 
01098         if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA &&
01099             *mode != IW_MODE_MASTER && *mode != IW_MODE_REPEAT &&
01100             *mode != IW_MODE_MONITOR)
01101                 return -EOPNOTSUPP;
01102 
01103 #ifdef PRISM2_NO_STATION_MODES
01104         if (*mode == IW_MODE_ADHOC || *mode == IW_MODE_INFRA)
01105                 return -EOPNOTSUPP;
01106 #endif /* PRISM2_NO_STATION_MODES */
01107 
01108         if (*mode == local->iw_mode)
01109                 return 0;
01110 
01111         if (*mode == IW_MODE_MASTER && local->essid[0] == '\0') {
01112                 printk(KERN_WARNING "%s: empty SSID not allowed in Master "
01113                        "mode\n", dev->name);
01114                 return -EINVAL;
01115         }
01116 
01117         if (local->iw_mode == IW_MODE_MONITOR)
01118                 hostap_monitor_mode_disable(local);
01119 
01120         if (local->iw_mode == IW_MODE_ADHOC && *mode == IW_MODE_MASTER) {
01121                 /* There seems to be a firmware bug in at least STA f/w v1.5.6
01122                  * that leaves beacon frames to use IBSS type when moving from
01123                  * IBSS to Host AP mode. Doing double Port0 reset seems to be
01124                  * enough to workaround this. */
01125                 double_reset = 1;
01126         }
01127 
01128         printk(KERN_DEBUG "prism2: %s: operating mode changed "
01129                "%d -> %d\n", dev->name, local->iw_mode, *mode);
01130         local->iw_mode = *mode;
01131 
01132         if (local->iw_mode == IW_MODE_MONITOR)
01133                 hostap_monitor_mode_enable(local);
01134         else if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt &&
01135                  !local->fw_encrypt_ok) {
01136                 printk(KERN_DEBUG "%s: defaulting to host-based encryption as "
01137                        "a workaround for firmware bug in Host AP mode WEP\n",
01138                        dev->name);
01139                 local->host_encrypt = 1;
01140         }
01141 
01142         if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
01143                             hostap_get_porttype(local)))
01144                 return -EOPNOTSUPP;
01145 
01146         if (local->func->reset_port(dev))
01147                 return -EINVAL;
01148         if (double_reset && local->func->reset_port(dev))
01149                 return -EINVAL;
01150 
01151         return 0;
01152 }
01153 
01154 
01155 static int prism2_ioctl_giwmode(struct net_device *dev,
01156                                 struct iw_request_info *info,
01157                                 __u32 *mode, char *extra)
01158 {
01159         struct hostap_interface *iface = dev->priv;
01160         local_info_t *local = iface->local;
01161 
01162         if (dev == local->stadev) {
01163                 *mode = IW_MODE_INFRA;
01164                 return 0;
01165         }
01166 
01167         *mode = local->iw_mode;
01168         return 0;
01169 }
01170 
01171 
01172 static int prism2_ioctl_siwpower(struct net_device *dev,
01173                                  struct iw_request_info *info,
01174                                  struct iw_param *wrq, char *extra)
01175 {
01176 #ifdef PRISM2_NO_STATION_MODES
01177         return -EOPNOTSUPP;
01178 #else /* PRISM2_NO_STATION_MODES */
01179         int ret = 0;
01180 
01181         if (wrq->disabled)
01182                 return hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 0);
01183 
01184         switch (wrq->flags & IW_POWER_MODE) {
01185         case IW_POWER_UNICAST_R:
01186                 ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 0);
01187                 if (ret)
01188                         return ret;
01189                 ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
01190                 if (ret)
01191                         return ret;
01192                 break;
01193         case IW_POWER_ALL_R:
01194                 ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 1);
01195                 if (ret)
01196                         return ret;
01197                 ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
01198                 if (ret)
01199                         return ret;
01200                 break;
01201         case IW_POWER_ON:
01202                 break;
01203         default:
01204                 return -EINVAL;
01205         }
01206 
01207         if (wrq->flags & IW_POWER_TIMEOUT) {
01208                 ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
01209                 if (ret)
01210                         return ret;
01211                 ret = hostap_set_word(dev, HFA384X_RID_CNFPMHOLDOVERDURATION,
01212                                       wrq->value / 1024);
01213                 if (ret)
01214                         return ret;
01215         }
01216         if (wrq->flags & IW_POWER_PERIOD) {
01217                 ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
01218                 if (ret)
01219                         return ret;
01220                 ret = hostap_set_word(dev, HFA384X_RID_CNFMAXSLEEPDURATION,
01221                                       wrq->value / 1024);
01222                 if (ret)
01223                         return ret;
01224         }
01225 
01226         return ret;
01227 #endif /* PRISM2_NO_STATION_MODES */
01228 }
01229 
01230 
01231 static int prism2_ioctl_giwpower(struct net_device *dev,
01232                                  struct iw_request_info *info,
01233                                  struct iw_param *rrq, char *extra)
01234 {
01235 #ifdef PRISM2_NO_STATION_MODES
01236         return -EOPNOTSUPP;
01237 #else /* PRISM2_NO_STATION_MODES */
01238         struct hostap_interface *iface = dev->priv;
01239         local_info_t *local = iface->local;
01240         u16 enable, mcast;
01241 
01242         if (local->func->get_rid(dev, HFA384X_RID_CNFPMENABLED, &enable, 2, 1)
01243             < 0)
01244                 return -EINVAL;
01245 
01246         if (!__le16_to_cpu(enable)) {
01247                 rrq->disabled = 1;
01248                 return 0;
01249         }
01250 
01251         rrq->disabled = 0;
01252 
01253         if ((rrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
01254                 u16 timeout;
01255                 if (local->func->get_rid(dev,
01256                                          HFA384X_RID_CNFPMHOLDOVERDURATION,
01257                                          &timeout, 2, 1) < 0)
01258                         return -EINVAL;
01259 
01260                 rrq->flags = IW_POWER_TIMEOUT;
01261                 rrq->value = __le16_to_cpu(timeout) * 1024;
01262         } else {
01263                 u16 period;
01264                 if (local->func->get_rid(dev, HFA384X_RID_CNFMAXSLEEPDURATION,
01265                                          &period, 2, 1) < 0)
01266                         return -EINVAL;
01267 
01268                 rrq->flags = IW_POWER_PERIOD;
01269                 rrq->value = __le16_to_cpu(period) * 1024;
01270         }
01271 
01272         if (local->func->get_rid(dev, HFA384X_RID_CNFMULTICASTRECEIVE, &mcast,
01273                                  2, 1) < 0)
01274                 return -EINVAL;
01275 
01276         if (__le16_to_cpu(mcast))
01277                 rrq->flags |= IW_POWER_ALL_R;
01278         else
01279                 rrq->flags |= IW_POWER_UNICAST_R;
01280 
01281         return 0;
01282 #endif /* PRISM2_NO_STATION_MODES */
01283 }
01284 
01285 
01286 #if WIRELESS_EXT > 10
01287 static int prism2_ioctl_siwretry(struct net_device *dev,
01288                                  struct iw_request_info *info,
01289                                  struct iw_param *rrq, char *extra)
01290 {
01291         struct hostap_interface *iface = dev->priv;
01292         local_info_t *local = iface->local;
01293 
01294         if (rrq->disabled)
01295                 return -EINVAL;
01296 
01297         /* setting retry limits is not supported with the current station
01298          * firmware code; simulate this with alternative retry count for now */
01299         if (rrq->flags == IW_RETRY_LIMIT) {
01300                 if (rrq->value < 0) {
01301                         /* disable manual retry count setting and use firmware
01302                          * defaults */
01303                         local->manual_retry_count = -1;
01304                         local->tx_control &= ~HFA384X_TX_CTRL_ALT_RTRY;
01305                 } else {
01306                         if (hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT,
01307                                             rrq->value)) {
01308                                 printk(KERN_DEBUG "%s: Alternate retry count "
01309                                        "setting to %d failed\n",
01310                                        dev->name, rrq->value);
01311                                 return -EOPNOTSUPP;
01312                         }
01313 
01314                         local->manual_retry_count = rrq->value;
01315                         local->tx_control |= HFA384X_TX_CTRL_ALT_RTRY;
01316                 }
01317                 return 0;
01318         }
01319 
01320         return -EOPNOTSUPP;
01321 
01322 #if 0
01323         /* what could be done, if firmware would support this.. */
01324 
01325         if (rrq->flags & IW_RETRY_LIMIT) {
01326                 if (rrq->flags & IW_RETRY_MAX)
01327                         HFA384X_RID_LONGRETRYLIMIT = rrq->value;
01328                 else if (rrq->flags & IW_RETRY_MIN)
01329                         HFA384X_RID_SHORTRETRYLIMIT = rrq->value;
01330                 else {
01331                         HFA384X_RID_LONGRETRYLIMIT = rrq->value;
01332                         HFA384X_RID_SHORTRETRYLIMIT = rrq->value;
01333                 }
01334 
01335         }
01336 
01337         if (rrq->flags & IW_RETRY_LIFETIME) {
01338                 HFA384X_RID_MAXTRANSMITLIFETIME = rrq->value / 1024;
01339         }
01340 
01341         return 0;
01342 #endif /* 0 */
01343 }
01344 
01345 static int prism2_ioctl_giwretry(struct net_device *dev,
01346                                  struct iw_request_info *info,
01347                                  struct iw_param *rrq, char *extra)
01348 {
01349         struct hostap_interface *iface = dev->priv;
01350         local_info_t *local = iface->local;
01351         u16 shortretry, longretry, lifetime, altretry;
01352 
01353         if (local->func->get_rid(dev, HFA384X_RID_SHORTRETRYLIMIT, &shortretry,
01354                                  2, 1) < 0 ||
01355             local->func->get_rid(dev, HFA384X_RID_LONGRETRYLIMIT, &longretry,
01356                                  2, 1) < 0 ||
01357             local->func->get_rid(dev, HFA384X_RID_MAXTRANSMITLIFETIME,
01358                                  &lifetime, 2, 1) < 0)
01359                 return -EINVAL;
01360 
01361         le16_to_cpus(&shortretry);
01362         le16_to_cpus(&longretry);
01363         le16_to_cpus(&lifetime);
01364 
01365         rrq->disabled = 0;
01366 
01367         if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
01368                 rrq->flags = IW_RETRY_LIFETIME;
01369                 rrq->value = lifetime * 1024;
01370         } else {
01371                 if (local->manual_retry_count >= 0) {
01372                         rrq->flags = IW_RETRY_LIMIT;
01373                         if (local->func->get_rid(dev,
01374                                                  HFA384X_RID_CNFALTRETRYCOUNT,
01375                                                  &altretry, 2, 1) >= 0)
01376                                 rrq->value = le16_to_cpu(altretry);
01377                         else
01378                                 rrq->value = local->manual_retry_count;
01379                 } else if ((rrq->flags & IW_RETRY_MAX)) {
01380                         rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
01381                         rrq->value = longretry;
01382                 } else {
01383                         rrq->flags = IW_RETRY_LIMIT;
01384                         rrq->value = shortretry;
01385                         if (shortretry != longretry)
01386                                 rrq->flags |= IW_RETRY_MIN;
01387                 }
01388         }
01389         return 0;
01390 }
01391 #endif /* WIRELESS_EXT > 10 */
01392 
01393 
01394 #if WIRELESS_EXT > 9
01395 
01396 /* Note! This TX power controlling is experimental and should not be used in
01397  * production use. It just sets raw power register and does not use any kind of
01398  * feedback information from the measured TX power (CR58). This is now
01399  * commented out to make sure that it is not used by accident. TX power
01400  * configuration will be enabled again after proper algorithm using feedback
01401  * has been implemented. */
01402 
01403 #ifdef RAW_TXPOWER_SETTING
01404 /* Map HFA386x's CR31 to and from dBm with some sort of ad hoc mapping..
01405  * This version assumes following mapping:
01406  * CR31 is 7-bit value with -64 to +63 range.
01407  * -64 is mapped into +20dBm and +63 into -43dBm.
01408  * This is certainly not an exact mapping for every card, but at least
01409  * increasing dBm value should correspond to increasing TX power.
01410  */
01411 
01412 static int prism2_txpower_hfa386x_to_dBm(u16 val)
01413 {
01414         signed char tmp;
01415 
01416         if (val > 255)
01417                 val = 255;
01418 
01419         tmp = val;
01420         tmp >>= 2;
01421 
01422         return -12 - tmp;
01423 }
01424 
01425 static u16 prism2_txpower_dBm_to_hfa386x(int val)
01426 {
01427         signed char tmp;
01428 
01429         if (val > 20)
01430                 return 128;
01431         else if (val < -43)
01432                 return 127;
01433 
01434         tmp = val;
01435         tmp = -12 - tmp;
01436         tmp <<= 2;
01437 
01438         return (unsigned char) tmp;
01439 }
01440 #endif /* RAW_TXPOWER_SETTING */
01441 
01442 
01443 static int prism2_ioctl_siwtxpow(struct net_device *dev,
01444                                  struct iw_request_info *info,
01445                                  struct iw_param *rrq, char *extra)
01446 {
01447         struct hostap_interface *iface = dev->priv;
01448         local_info_t *local = iface->local;
01449 #ifdef RAW_TXPOWER_SETTING
01450         char *tmp;
01451 #endif
01452         u16 val;
01453         int ret = 0;
01454 
01455         if (rrq->disabled) {
01456                 if (local->txpower_type != PRISM2_TXPOWER_OFF) {
01457                         val = 0xff; /* use all standby and sleep modes */
01458                         ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
01459                                                HFA386X_CR_A_D_TEST_MODES2,
01460                                                &val, NULL);
01461                         printk(KERN_DEBUG "%s: Turning radio off: %s\n",
01462                                dev->name, ret ? "failed" : "OK");
01463                         local->txpower_type = PRISM2_TXPOWER_OFF;
01464                 }
01465                 return (ret ? -EOPNOTSUPP : 0);
01466         }
01467 
01468         if (local->txpower_type == PRISM2_TXPOWER_OFF) {
01469                 val = 0; /* disable all standby and sleep modes */
01470                 ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
01471                                        HFA386X_CR_A_D_TEST_MODES2, &val, NULL);
01472                 printk(KERN_DEBUG "%s: Turning radio on: %s\n",
01473                        dev->name, ret ? "failed" : "OK");
01474                 local->txpower_type = PRISM2_TXPOWER_UNKNOWN;
01475         }
01476 
01477 #ifdef RAW_TXPOWER_SETTING
01478         if (!rrq->fixed && local->txpower_type != PRISM2_TXPOWER_AUTO) {
01479                 printk(KERN_DEBUG "Setting ALC on\n");
01480                 val = HFA384X_TEST_CFG_BIT_ALC;
01481                 local->func->cmd(dev, HFA384X_CMDCODE_TEST |
01482                                  (HFA384X_TEST_CFG_BITS << 8), 1, &val, NULL);
01483                 local->txpower_type = PRISM2_TXPOWER_AUTO;
01484                 return 0;
01485         }
01486 
01487         if (local->txpower_type != PRISM2_TXPOWER_FIXED) {
01488                 printk(KERN_DEBUG "Setting ALC off\n");
01489                 val = HFA384X_TEST_CFG_BIT_ALC;
01490                 local->func->cmd(dev, HFA384X_CMDCODE_TEST |
01491                                  (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL);
01492                         local->txpower_type = PRISM2_TXPOWER_FIXED;
01493         }
01494 
01495         if (rrq->flags == IW_TXPOW_DBM)
01496                 tmp = "dBm";
01497         else if (rrq->flags == IW_TXPOW_MWATT)
01498                 tmp = "mW";
01499         else
01500                 tmp = "UNKNOWN";
01501         printk(KERN_DEBUG "Setting TX power to %d %s\n", rrq->value, tmp);
01502 
01503         if (rrq->flags != IW_TXPOW_DBM) {
01504                 printk("SIOCSIWTXPOW with mW is not supported; use dBm\n");
01505                 return -EOPNOTSUPP;
01506         }
01507 
01508         local->txpower = rrq->value;
01509         val = prism2_txpower_dBm_to_hfa386x(local->txpower);
01510         if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
01511                              HFA386X_CR_MANUAL_TX_POWER, &val, NULL))
01512                 ret = -EOPNOTSUPP;
01513 #else /* RAW_TXPOWER_SETTING */
01514         if (rrq->fixed)
01515                 ret = -EOPNOTSUPP;
01516 #endif /* RAW_TXPOWER_SETTING */
01517 
01518         return ret;
01519 }
01520 
01521 static int prism2_ioctl_giwtxpow(struct net_device *dev,
01522                                  struct iw_request_info *info,
01523                                  struct iw_param *rrq, char *extra)
01524 {
01525 #ifdef RAW_TXPOWER_SETTING
01526         struct hostap_interface *iface = dev->priv;
01527         local_info_t *local = iface->local;
01528         u16 resp0;
01529 
01530         rrq->flags = IW_TXPOW_DBM;
01531         rrq->disabled = 0;
01532         rrq->fixed = 0;
01533 
01534         if (local->txpower_type == PRISM2_TXPOWER_AUTO) {
01535                 if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF,
01536                                      HFA386X_CR_MANUAL_TX_POWER,
01537                                      NULL, &resp0) == 0) {
01538                         rrq->value = prism2_txpower_hfa386x_to_dBm(resp0);
01539                 } else {
01540                         /* Could not get real txpower; guess 15 dBm */
01541                         rrq->value = 15;
01542                 }
01543         } else if (local->txpower_type == PRISM2_TXPOWER_OFF) {
01544                 rrq->value = 0;
01545                 rrq->disabled = 1;
01546         } else if (local->txpower_type == PRISM2_TXPOWER_FIXED) {
01547                 rrq->value = local->txpower;
01548                 rrq->fixed = 1;
01549         } else {
01550                 printk("SIOCGIWTXPOW - unknown txpower_type=%d\n",
01551                        local->txpower_type);
01552         }
01553         return 0;
01554 #else /* RAW_TXPOWER_SETTING */
01555         return -EOPNOTSUPP;
01556 #endif /* RAW_TXPOWER_SETTING */
01557 }
01558 #endif /* WIRELESS_EXT > 9 */
01559 
01560 
01561 #if WIRELESS_EXT > 13
01562 
01563 #ifndef PRISM2_NO_STATION_MODES
01564 
01565 /* HostScan request works with and without host_roaming mode. In addition, it
01566  * does not break current association. However, it requires newer station
01567  * firmware version (>= 1.3.1) than scan request. */
01568 static int prism2_request_hostscan(struct net_device *dev)
01569 {
01570         struct hostap_interface *iface = dev->priv;
01571         local_info_t *local = iface->local;
01572         struct hfa384x_hostscan_request scan_req;
01573 
01574         memset(&scan_req, 0, sizeof(scan_req));
01575         scan_req.channel_list = __constant_cpu_to_le16(local->channel_mask);
01576         scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS);
01577         /* leave target_ssid empty so that all SSIDs are accepted */
01578 
01579         if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req,
01580                                  sizeof(scan_req))) {
01581                 printk(KERN_DEBUG "%s: HOSTSCAN failed\n", dev->name);
01582                 return -EINVAL;
01583         }
01584         return 0;
01585 }
01586 
01587 
01588 static int prism2_request_scan(struct net_device *dev)
01589 {
01590         struct hostap_interface *iface = dev->priv;
01591         local_info_t *local = iface->local;
01592         struct hfa384x_scan_request scan_req;
01593         int ret = 0;
01594 
01595         memset(&scan_req, 0, sizeof(scan_req));
01596         scan_req.channel_list = __constant_cpu_to_le16(local->channel_mask);
01597         scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS);
01598 
01599         /* FIX:
01600          * It seems to be enough to set roaming mode for a short moment to
01601          * host-based and then setup scanrequest data and return the mode to
01602          * firmware-based.
01603          *
01604          * Master mode would need to drop to Managed mode for a short while
01605          * to make scanning work.. Or sweep through the different channels and
01606          * use passive scan based on beacons. */
01607 
01608         if (!local->host_roaming)
01609                 hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE,
01610                                 HFA384X_ROAMING_HOST);
01611 
01612         if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, &scan_req,
01613                                  sizeof(scan_req))) {
01614                 printk(KERN_DEBUG "SCANREQUEST failed\n");
01615                 ret = -EINVAL;
01616         }
01617 
01618         if (!local->host_roaming)
01619                 hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE,
01620                                 HFA384X_ROAMING_FIRMWARE);
01621 
01622         return 0;
01623 }
01624 
01625 #else /* !PRISM2_NO_STATION_MODES */
01626 
01627 static inline int prism2_request_hostscan(struct net_device *dev)
01628 {
01629         return -EOPNOTSUPP;
01630 }
01631 
01632 
01633 static inline int prism2_request_scan(struct net_device *dev)
01634 {
01635         return -EOPNOTSUPP;
01636 }
01637 
01638 #endif /* !PRISM2_NO_STATION_MODES */
01639 
01640 
01641 static int prism2_ioctl_siwscan(struct net_device *dev,
01642                                 struct iw_request_info *info,
01643                                 struct iw_point *data, char *extra)
01644 {
01645         struct hostap_interface *iface = dev->priv;
01646         local_info_t *local = iface->local;
01647         int ret;
01648 
01649         if (local->iw_mode == IW_MODE_MASTER) {
01650                 /* In master mode, we just return the results of our local
01651                  * tables, so we don't need to start anything...
01652                  * Jean II */
01653                 data->length = 0;
01654                 return 0;
01655         }
01656 
01657         if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1))
01658                 ret = prism2_request_hostscan(dev);
01659         else
01660                 ret = prism2_request_scan(dev);
01661 
01662         if (ret == 0)
01663                 local->scan_timestamp = jiffies;
01664 
01665         /* Could inquire F101, F103 or wait for SIOCGIWSCAN and read RID */
01666 
01667         return ret;
01668 }
01669 
01670 
01671 #ifndef PRISM2_NO_STATION_MODES
01672 /* Translate scan data returned from the card to a card independant
01673  * format that the Wireless Tools will understand - Jean II */
01674 static inline int prism2_translate_scan(local_info_t *local, char *buffer)
01675 {
01676         struct hfa384x_scan_result *scan;
01677         struct hfa384x_hostscan_result *hscan;
01678         int i, entries, entry, hostscan;
01679         struct iw_event iwe;
01680         char *current_ev = buffer;
01681         char *end_buf = buffer + IW_SCAN_MAX_DATA;
01682         char *current_val;
01683         u16 capabilities;
01684         u8 *pos;
01685 
01686         spin_lock_bh(&local->lock);
01687 
01688         hostscan = local->last_scan_type == PRISM2_HOSTSCAN;
01689         entries = hostscan ? local->last_hostscan_results_count :
01690                 local->last_scan_results_count;
01691         for (entry = 0; entry < entries; entry++) {
01692                 scan = &local->last_scan_results[entry];
01693                 hscan = &local->last_hostscan_results[entry];
01694 
01695                 /* First entry *MUST* be the AP MAC address */
01696                 memset(&iwe, 0, sizeof(iwe));
01697                 iwe.cmd = SIOCGIWAP;
01698                 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
01699                 memcpy(iwe.u.ap_addr.sa_data,
01700                        hostscan ? hscan->bssid : scan->bssid, ETH_ALEN);
01701                 /* FIX:
01702                  * I do not know how this is possible, but iwe_stream_add_event
01703                  * seems to re-order memcpy execution so that len is set only
01704                  * after copying.. Pre-setting len here "fixes" this, but real
01705                  * problems should be solved (after which these iwe.len
01706                  * settings could be removed from this function). */
01707                 iwe.len = IW_EV_ADDR_LEN;
01708                 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
01709                                                   IW_EV_ADDR_LEN);
01710 
01711                 /* Other entries will be displayed in the order we give them */
01712 
01713                 memset(&iwe, 0, sizeof(iwe));
01714                 iwe.cmd = SIOCGIWESSID;
01715                 iwe.u.data.length = le16_to_cpu(hostscan ? hscan->ssid_len :
01716                                                 scan->ssid_len);
01717                 if (iwe.u.data.length > 32)
01718                         iwe.u.data.length = 32;
01719                 iwe.u.data.flags = 1;
01720                 iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
01721                 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
01722                                                   hostscan ? hscan->ssid :
01723                                                   scan->ssid);
01724 
01725                 memset(&iwe, 0, sizeof(iwe));
01726                 iwe.cmd = SIOCGIWMODE;
01727                 capabilities = le16_to_cpu(hostscan ? hscan->capability :
01728                                            scan->capability);
01729                 if (capabilities & (WLAN_CAPABILITY_ESS |
01730                                     WLAN_CAPABILITY_IBSS)) {
01731                         if (capabilities & WLAN_CAPABILITY_ESS)
01732                                 iwe.u.mode = IW_MODE_MASTER;
01733                         else
01734                                 iwe.u.mode = IW_MODE_ADHOC;
01735                         iwe.len = IW_EV_UINT_LEN;
01736                         current_ev = iwe_stream_add_event(current_ev, end_buf,
01737                                                           &iwe,
01738                                                           IW_EV_UINT_LEN);
01739                 }
01740 
01741                 memset(&iwe, 0, sizeof(iwe));
01742                 iwe.cmd = SIOCGIWFREQ;
01743                 iwe.u.freq.m = freq_list[le16_to_cpu(hostscan ? hscan->chid :
01744                                                      scan->chid) - 1] * 100000;
01745                 iwe.u.freq.e = 1;
01746                 iwe.len = IW_EV_FREQ_LEN;
01747                 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
01748                                                   IW_EV_FREQ_LEN);
01749 
01750                 memset(&iwe, 0, sizeof(iwe));
01751                 iwe.cmd = IWEVQUAL;
01752                 if (hostscan) {
01753                         iwe.u.qual.level = le16_to_cpu(hscan->sl);
01754                         iwe.u.qual.noise = le16_to_cpu(hscan->anl);
01755                 } else {
01756                         iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(
01757                                 le16_to_cpu(scan->sl));
01758                         iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(
01759                                 le16_to_cpu(scan->anl));
01760                 }
01761                 iwe.len = IW_EV_QUAL_LEN;
01762                 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
01763                                                   IW_EV_QUAL_LEN);
01764 
01765                 memset(&iwe, 0, sizeof(iwe));
01766                 iwe.cmd = SIOCGIWENCODE;
01767                 if (capabilities & WLAN_CAPABILITY_PRIVACY)
01768                         iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
01769                 else
01770                         iwe.u.data.flags = IW_ENCODE_DISABLED;
01771                 iwe.u.data.length = 0;
01772                 iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
01773                 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
01774                                                   "");
01775 
01776                 memset(&iwe, 0, sizeof(iwe));
01777                 iwe.cmd = SIOCGIWRATE;
01778                 current_val = current_ev + IW_EV_LCP_LEN;
01779                 pos = hostscan ? hscan->sup_rates : scan->sup_rates;
01780                 for (i = 0; i < sizeof(scan->sup_rates); i++) {
01781                         if (pos[i] == 0)
01782                                 break;
01783                         /* Bit rate given in 500 kb/s units (+ 0x80) */
01784                         iwe.u.bitrate.value =
01785                                 ((pos[i] & 0x7f) * 500000);
01786                         current_val = iwe_stream_add_value(
01787                                 current_ev, current_val, end_buf, &iwe,
01788                                 IW_EV_PARAM_LEN);
01789                 }
01790                 /* Check if we added any event */
01791                 if ((current_val - current_ev) > IW_EV_LCP_LEN)
01792                         current_ev = current_val;
01793 
01794 #if WIRELESS_EXT > 14
01795                 {
01796                         char buf[20];
01797                         memset(&iwe, 0, sizeof(iwe));
01798                         iwe.cmd = IWEVCUSTOM;
01799                         sprintf(buf, "bcn_int=%d",
01800                                 le16_to_cpu(hostscan ? hscan->beacon_interval :
01801                                             scan->beacon_interval));
01802                         iwe.u.data.length = strlen(buf);
01803                         current_ev = iwe_stream_add_point(current_ev, end_buf,
01804                                                           &iwe, buf);
01805 
01806                         memset(&iwe, 0, sizeof(iwe));
01807                         iwe.cmd = IWEVCUSTOM;
01808                         sprintf(buf, "resp_rate=%d",
01809                                 le16_to_cpu(hostscan ? hscan->rate :
01810                                             scan->rate));
01811                         iwe.u.data.length = strlen(buf);
01812                         current_ev = iwe_stream_add_point(current_ev, end_buf,
01813                                                           &iwe, buf);
01814 
01815                         if (hostscan && (capabilities & WLAN_CAPABILITY_IBSS))
01816                         {
01817                                 memset(&iwe, 0, sizeof(iwe));
01818                                 iwe.cmd = IWEVCUSTOM;
01819                                 sprintf(buf, "atim=%d",
01820                                         le16_to_cpu(hscan->atim));
01821                                 iwe.u.data.length = strlen(buf);
01822                                 current_ev = iwe_stream_add_point(
01823                                         current_ev, end_buf, &iwe, buf);
01824                         }
01825                 }
01826 #endif /* WIRELESS_EXT > 14 */
01827 
01828 
01829                 /* Could add beacon_interval and rate (of the received
01830                  * ProbeResp) to scan results. With hostscan, could also add
01831                  * ATIM. */
01832         }
01833 
01834         spin_unlock_bh(&local->lock);
01835 
01836         return current_ev - buffer;
01837 }
01838 #endif /* PRISM2_NO_STATION_MODES */
01839 
01840 
01841 static inline int prism2_ioctl_giwscan_sta(struct net_device *dev,
01842                                            struct iw_request_info *info,
01843                                            struct iw_point *data, char *extra)
01844 {
01845 #ifdef PRISM2_NO_STATION_MODES
01846         return -EOPNOTSUPP;
01847 #else /* PRISM2_NO_STATION_MODES */
01848         struct hostap_interface *iface = dev->priv;
01849         local_info_t *local = iface->local;
01850         int res;
01851 
01852         /* Wait until the scan is finished. We can probably do better
01853          * than that - Jean II */
01854         if (local->scan_timestamp &&
01855             time_before(jiffies, local->scan_timestamp + 3 * HZ)) {
01856                 /* Important note : we don't want to block the caller
01857                  * until results are ready for various reasons.
01858                  * First, managing wait queues is complex and racy
01859                  * (there may be multiple simultaneous callers).
01860                  * Second, we grab some rtnetlink lock before comming
01861                  * here (in dev_ioctl()).
01862                  * Third, the caller can wait on the Wireless Event
01863                  * - Jean II */
01864                 return -EAGAIN;
01865         }
01866         local->scan_timestamp = 0;
01867 
01868         res = prism2_translate_scan(local, extra);
01869 
01870         if (res >= 0) {
01871                 data->length = res;
01872                 return 0;
01873         } else {
01874                 data->length = 0;
01875                 return res;
01876         }
01877 #endif /* PRISM2_NO_STATION_MODES */
01878 }
01879 
01880 
01881 static int prism2_ioctl_giwscan(struct net_device *dev,
01882                                 struct iw_request_info *info,
01883                                 struct iw_point *data, char *extra)
01884 {
01885         struct hostap_interface *iface = dev->priv;
01886         local_info_t *local = iface->local;
01887         int res;
01888 
01889         if (local->iw_mode == IW_MODE_MASTER) {
01890                 /* In MASTER mode, it doesn't make sense to go around
01891                  * scanning the frequencies and make the stations we serve
01892                  * wait when what the user is really interested about is the
01893                  * list of stations and access points we are talking to.
01894                  * So, just extract results from our cache...
01895                  * Jean II */
01896 
01897                 /* Translate to WE format */
01898                 res = prism2_ap_translate_scan(dev, extra);
01899                 if (res >= 0) {
01900                         printk(KERN_DEBUG "Scan result translation succeeded "
01901                                "(length=%d)\n", res);
01902                         data->length = res;
01903                         return 0;
01904                 } else {
01905                         printk(KERN_DEBUG
01906                                "Scan result translation failed (res=%d)\n",
01907                                res);
01908                         data->length = 0;
01909                         return res;
01910                 }
01911         } else {
01912                 /* Station mode */
01913                 return prism2_ioctl_giwscan_sta(dev, info, data, extra);
01914         }
01915 }
01916 #endif /* WIRELESS_EXT > 13 */
01917 
01918 
01919 static const struct iw_priv_args prism2_priv[] = {
01920         { PRISM2_IOCTL_MONITOR,
01921           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor" },
01922         { PRISM2_IOCTL_DSSSTEST,
01923           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dssstest" },
01924         { PRISM2_IOCTL_READMIF,
01925           IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
01926           IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "readmif" },
01927         { PRISM2_IOCTL_WRITEMIF,
01928           IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2, 0, "writemif" },
01929         { PRISM2_IOCTL_RESET,
01930           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "reset" },
01931         { PRISM2_IOCTL_INQUIRE,
01932           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "inquire" },
01933         { PRISM2_IOCTL_SET_RID_WORD,
01934           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_rid_word" },
01935         { PRISM2_IOCTL_MACCMD,
01936           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maccmd" },
01937 #ifdef PRISM2_USE_WE_TYPE_ADDR
01938         { PRISM2_IOCTL_WDS_ADD,
01939           IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_add" },
01940         { PRISM2_IOCTL_WDS_DEL,
01941           IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_del" },
01942         { PRISM2_IOCTL_ADDMAC,
01943           IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addmac" },
01944         { PRISM2_IOCTL_DELMAC,
01945           IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "delmac" },
01946         { PRISM2_IOCTL_KICKMAC,
01947           IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac" },
01948 #else /* PRISM2_USE_WE_TYPE_ADDR */
01949         { PRISM2_IOCTL_WDS_ADD,
01950           IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 18, 0, "wds_add" },
01951         { PRISM2_IOCTL_WDS_DEL,
01952           IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 18, 0, "wds_del" },
01953         { PRISM2_IOCTL_ADDMAC,
01954           IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 18, 0, "addmac" },
01955         { PRISM2_IOCTL_DELMAC,
01956           IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 18, 0, "delmac" },
01957         { PRISM2_IOCTL_KICKMAC,
01958           IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 18, 0, "kickmac" },
01959 #endif /* PRISM2_USE_WE_TYPE_ADDR */
01960         /* --- raw access to sub-ioctls --- */
01961         { PRISM2_IOCTL_PRISM2_PARAM,
01962           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "prism2_param" },
01963 #if WIRELESS_EXT >= 12
01964         { PRISM2_IOCTL_GET_PRISM2_PARAM,
01965           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
01966           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprism2_param" },
01967 #ifdef PRISM2_USE_WE_SUB_IOCTLS
01968         /* --- sub-ioctls handlers --- */
01969         { PRISM2_IOCTL_PRISM2_PARAM,
01970           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" },
01971         { PRISM2_IOCTL_GET_PRISM2_PARAM,
01972           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" },
01973         /* --- sub-ioctls definitions --- */
01974         { PRISM2_PARAM_PTYPE,
01975           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ptype" },
01976         { PRISM2_PARAM_PTYPE,
01977           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getptype" },
01978         { PRISM2_PARAM_TXRATECTRL,
01979           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "txratectrl" },
01980         { PRISM2_PARAM_TXRATECTRL,
01981           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettxratectrl" },
01982         { PRISM2_PARAM_BEACON_INT,
01983           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beacon_int" },
01984         { PRISM2_PARAM_BEACON_INT,
01985           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbeacon_int" },
01986 #ifndef PRISM2_NO_STATION_MODES
01987         { PRISM2_PARAM_PSEUDO_IBSS,
01988           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "pseudo_ibss" },
01989         { PRISM2_PARAM_PSEUDO_IBSS,
01990           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpseudo_ibss" },
01991 #endif /* PRISM2_NO_STATION_MODES */
01992         { PRISM2_PARAM_ALC,
01993           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "alc" },
01994         { PRISM2_PARAM_ALC,
01995           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getalc" },
01996         { PRISM2_PARAM_TXPOWER,
01997           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "txpower" },
01998         { PRISM2_PARAM_TXPOWER,
01999           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getxpower" },
02000         { PRISM2_PARAM_DUMP,
02001           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dump" },
02002         { PRISM2_PARAM_DUMP,
02003           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdump" },
02004         { PRISM2_PARAM_OTHER_AP_POLICY,
02005           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "other_ap_policy" },
02006         { PRISM2_PARAM_OTHER_AP_POLICY,
02007           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getother_ap_pol" },
02008         { PRISM2_PARAM_AP_MAX_INACTIVITY,
02009           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_inactivity" },
02010         { PRISM2_PARAM_AP_MAX_INACTIVITY,
02011           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_inactivi" },
02012         { PRISM2_PARAM_AP_BRIDGE_PACKETS,
02013           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bridge_packets" },
02014         { PRISM2_PARAM_AP_BRIDGE_PACKETS,
02015           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbridge_packe" },
02016         { PRISM2_PARAM_DTIM_PERIOD,
02017           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dtim_period" },
02018         { PRISM2_PARAM_DTIM_PERIOD,
02019           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdtim_period" },
02020         { PRISM2_PARAM_AP_NULLFUNC_ACK,
02021           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "nullfunc_ack" },
02022         { PRISM2_PARAM_AP_NULLFUNC_ACK,
02023           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getnullfunc_ack" },
02024         { PRISM2_PARAM_MAX_WDS,
02025           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_wds" },
02026         { PRISM2_PARAM_MAX_WDS,
02027           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_wds" },
02028         { PRISM2_PARAM_AP_AUTOM_AP_WDS,
02029           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "autom_ap_wds" },
02030         { PRISM2_PARAM_AP_AUTOM_AP_WDS,
02031           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getautom_ap_wds" },
02032         { PRISM2_PARAM_AP_AUTH_ALGS,
02033           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_auth_algs" },
02034         { PRISM2_PARAM_AP_AUTH_ALGS,
02035           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_auth_algs" },
02036         { PRISM2_PARAM_MONITOR_ALLOW_FCSERR,
02037           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "allow_fcserr" },
02038         { PRISM2_PARAM_MONITOR_ALLOW_FCSERR,
02039           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getallow_fcserr" },
02040         { PRISM2_PARAM_HOST_ENCRYPT,
02041           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_encrypt" },
02042         { PRISM2_PARAM_HOST_ENCRYPT,
02043           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_encrypt" },
02044         { PRISM2_PARAM_HOST_DECRYPT,
02045           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_decrypt" },
02046         { PRISM2_PARAM_HOST_DECRYPT,
02047           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_decrypt" },
02048         { PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX,
02049           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "busmaster_rx" },
02050         { PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX,
02051           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbusmaster_rx" },
02052         { PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX,
02053           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "busmaster_tx" },
02054         { PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX,
02055           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbusmaster_tx" },
02056 #ifndef PRISM2_NO_STATION_MODES
02057         { PRISM2_PARAM_HOST_ROAMING,
02058           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_roaming" },
02059         { PRISM2_PARAM_HOST_ROAMING,
02060           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_roaming" },
02061 #endif /* PRISM2_NO_STATION_MODES */
02062         { PRISM2_PARAM_BCRX_STA_KEY,
02063           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bcrx_sta_key" },
02064         { PRISM2_PARAM_BCRX_STA_KEY,
02065           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbcrx_sta_key" },
02066         { PRISM2_PARAM_IEEE_802_1X,
02067           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ieee_802_1x" },
02068         { PRISM2_PARAM_IEEE_802_1X,
02069           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getieee_802_1x" },
02070         { PRISM2_PARAM_ANTSEL_TX,
02071           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_tx" },
02072         { PRISM2_PARAM_ANTSEL_TX,
02073           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_tx" },
02074         { PRISM2_PARAM_ANTSEL_RX,
02075           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_rx" },
02076         { PRISM2_PARAM_ANTSEL_RX,
02077           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_rx" },
02078         { PRISM2_PARAM_MONITOR_TYPE,
02079           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor_type" },
02080         { PRISM2_PARAM_MONITOR_TYPE,
02081           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmonitor_type" },
02082         { PRISM2_PARAM_WDS_TYPE,
02083           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wds_type" },
02084         { PRISM2_PARAM_WDS_TYPE,
02085           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwds_type" },
02086         { PRISM2_PARAM_HOSTSCAN,
02087           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostscan" },
02088         { PRISM2_PARAM_HOSTSCAN,
02089           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostscan" },
02090         { PRISM2_PARAM_AP_SCAN,
02091           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_scan" },
02092         { PRISM2_PARAM_AP_SCAN,
02093           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_scan" },
02094         { PRISM2_PARAM_ENH_SEC,
02095           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "enh_sec" },
02096         { PRISM2_PARAM_ENH_SEC,
02097           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getenh_sec" },
02098 #ifdef PRISM2_IO_DEBUG
02099         { PRISM2_PARAM_IO_DEBUG,
02100           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "io_debug" },
02101         { PRISM2_PARAM_IO_DEBUG,
02102           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getio_debug" },
02103 #endif /* PRISM2_IO_DEBUG */
02104         { PRISM2_PARAM_BASIC_RATES,
02105           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "basic_rates" },
02106         { PRISM2_PARAM_BASIC_RATES,
02107           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbasic_rates" },
02108         { PRISM2_PARAM_OPER_RATES,
02109           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oper_rates" },
02110         { PRISM2_PARAM_OPER_RATES,
02111           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getoper_rates" },
02112         { PRISM2_PARAM_HOSTAPD,
02113           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd" },
02114         { PRISM2_PARAM_HOSTAPD,
02115           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd" },
02116         { PRISM2_PARAM_TX_OK,
02117           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "tx_ok" },
02118         { PRISM2_PARAM_TX_OK,
02119           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettx_ok" },
02120         { PRISM2_PARAM_TX_EX,
02121           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "tx_ex" },
02122         { PRISM2_PARAM_TX_EX,
02123           0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettx_ex" },
02124 
02125 
02126 #endif /* PRISM2_USE_WE_SUB_IOCTLS */
02127 #endif /* WIRELESS_EXT >= 12 */
02128 };
02129 
02130 
02131 #if WIRELESS_EXT <= 12
02132 static int prism2_ioctl_giwpriv(struct net_device *dev, struct iw_point *data)
02133 {
02134 
02135         if (!data->pointer ||
02136             verify_area(VERIFY_WRITE, data->pointer, sizeof(prism2_priv)))
02137                 return -EINVAL;
02138 
02139         data->length = sizeof(prism2_priv) / sizeof(prism2_priv[0]);
02140         if (copy_to_user(data->pointer, prism2_priv, sizeof(prism2_priv)))
02141                 return -EINVAL;
02142         return 0;
02143 }
02144 #endif /* WIRELESS_EXT <= 12 */
02145 
02146 
02147 static int prism2_ioctl_priv_inquire(struct net_device *dev, int *i)
02148 {
02149         struct hostap_interface *iface = dev->priv;
02150         local_info_t *local = iface->local;
02151 
02152         if (local->func->cmd(dev, HFA384X_CMDCODE_INQUIRE, *i, NULL, NULL))
02153                 return -EOPNOTSUPP;
02154 
02155         return 0;
02156 }
02157 
02158 
02159 static int prism2_ioctl_priv_prism2_param(struct net_device *dev,
02160                                           struct iw_request_info *info,
02161                                           void *wrqu, char *extra)
02162 {
02163         struct hostap_interface *iface = dev->priv;
02164         local_info_t *local = iface->local;
02165         int *i = (int *) extra;
02166         int param = *i;
02167         int value = *(i + 1);
02168         int ret = 0;
02169         u16 val;
02170 
02171         switch (param) {
02172         case PRISM2_PARAM_PTYPE:
02173                 if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, value)) {
02174                         ret = -EOPNOTSUPP;
02175                         break;
02176                 }
02177 
02178                 if (local->func->reset_port(dev))
02179                         ret = -EINVAL;
02180                 break;
02181 
02182         case PRISM2_PARAM_TXRATECTRL:
02183                 local->fw_tx_rate_control = value;
02184                 break;
02185 
02186         case PRISM2_PARAM_BEACON_INT:
02187                 if (hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, value) ||
02188                     local->func->reset_port(dev))
02189                         ret = -EINVAL;
02190                 else
02191                         local->beacon_int = value;
02192                 break;
02193 
02194 #ifndef PRISM2_NO_STATION_MODES
02195         case PRISM2_PARAM_PSEUDO_IBSS:
02196                 if (value == local->pseudo_adhoc)
02197                         break;
02198 
02199                 if (value != 0 && value != 1) {
02200                         ret = -EINVAL;
02201                         break;
02202                 }
02203 
02204                 printk(KERN_DEBUG "prism2: %s: pseudo IBSS change %d -> %d\n",
02205                        dev->name, local->pseudo_adhoc, value);
02206                 local->pseudo_adhoc = value;
02207                 if (local->iw_mode != IW_MODE_ADHOC)
02208                         break;
02209 
02210                 if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
02211                                     hostap_get_porttype(local))) {
02212                         ret = -EOPNOTSUPP;
02213                         break;
02214                 }
02215 
02216                 if (local->func->reset_port(dev))
02217                         ret = -EINVAL;
02218                 break;
02219 #endif /* PRISM2_NO_STATION_MODES */
02220 
02221         case PRISM2_PARAM_ALC:
02222                 printk(KERN_DEBUG "%s: %s ALC\n", dev->name,
02223                        value == 0 ? "Disabling" : "Enabling");
02224                 val = HFA384X_TEST_CFG_BIT_ALC;
02225                 local->func->cmd(dev, HFA384X_CMDCODE_TEST |
02226                                  (HFA384X_TEST_CFG_BITS << 8),
02227                                  value == 0 ? 0 : 1, &val, NULL);
02228                 break;
02229 
02230         case PRISM2_PARAM_TXPOWER:
02231                 val = value;
02232                 if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
02233                                      HFA386X_CR_MANUAL_TX_POWER, &val, NULL))
02234                         ret = -EOPNOTSUPP;
02235                 break;
02236 
02237         case PRISM2_PARAM_DUMP:
02238                 local->frame_dump = value;
02239                 break;
02240 
02241         case PRISM2_PARAM_OTHER_AP_POLICY:
02242                 if (value < 0 || value > 3) {
02243                         ret = -EINVAL;
02244                         break;
02245                 }
02246                 if (local->ap != NULL)
02247                         local->ap->ap_policy = value;
02248                 break;
02249 
02250         case PRISM2_PARAM_AP_MAX_INACTIVITY:
02251                 if (value < 0 || value > 7 * 24 * 60 * 60) {
02252                         ret = -EINVAL;
02253                         break;
02254                 }
02255                 if (local->ap != NULL)
02256                         local->ap->max_inactivity = value * HZ;
02257                 break;
02258 
02259         case PRISM2_PARAM_AP_BRIDGE_PACKETS:
02260                 if (local->ap != NULL)
02261                         local->ap->bridge_packets = value;
02262                 break;
02263 
02264         case PRISM2_PARAM_DTIM_PERIOD:
02265                 if (value < 0 || value > 65535) {
02266                         ret = -EINVAL;
02267                         break;
02268                 }
02269                 if (hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, value)
02270                     || local->func->reset_port(dev))
02271                         ret = -EINVAL;
02272                 else
02273                         local->dtim_period = value;
02274                 break;
02275 
02276         case PRISM2_PARAM_AP_NULLFUNC_ACK:
02277                 if (local->ap != NULL)
02278                         local->ap->nullfunc_ack = value;
02279                 break;
02280 
02281         case PRISM2_PARAM_MAX_WDS:
02282                 local->wds_max_connections = value;
02283                 break;
02284 
02285         case PRISM2_PARAM_AP_AUTOM_AP_WDS:
02286                 if (local->ap != NULL) {
02287                         if (!local->ap->autom_ap_wds && value) {
02288                                 /* add WDS link to all APs in STA table */
02289                                 hostap_add_wds_links(local);
02290                         }
02291                         local->ap->autom_ap_wds = value;
02292                 }
02293                 break;
02294 
02295         case PRISM2_PARAM_AP_AUTH_ALGS:
02296                 local->auth_algs = value;
02297                 if (hostap_set_auth_algs(local))
02298                         ret = -EINVAL;
02299                 break;
02300 
02301         case PRISM2_PARAM_MONITOR_ALLOW_FCSERR:
02302                 local->monitor_allow_fcserr = value;
02303                 break;
02304 
02305         case PRISM2_PARAM_TX_OK:
02306           if (value) {
02307             local->tx_control |= HFA384X_TX_CTRL_TX_OK;
02308           } else {
02309             local->tx_control &= ~HFA384X_TX_CTRL_TX_OK;
02310           }
02311           break;
02312 
02313         case PRISM2_PARAM_TX_EX:
02314           if (value) {
02315             local->tx_control |= HFA384X_TX_CTRL_TX_EX;
02316           } else {
02317             local->tx_control &= ~HFA384X_TX_CTRL_TX_EX;
02318           }
02319           break;
02320 
02321         case PRISM2_PARAM_HOST_ENCRYPT:
02322                 local->host_encrypt = value;
02323                 if (hostap_set_encryption(local) ||
02324                     local->func->reset_port(dev))
02325                         ret = -EINVAL;
02326                 break;
02327 
02328         case PRISM2_PARAM_HOST_DECRYPT:
02329                 local->host_decrypt = value;
02330                 if (hostap_set_encryption(local) ||
02331                     local->func->reset_port(dev))
02332                         ret = -EINVAL;
02333                 break;
02334 
02335         case PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX:
02336                 local->bus_master_threshold_rx = value;
02337                 break;
02338 
02339         case PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX:
02340                 local->bus_master_threshold_tx = value;
02341                 break;
02342 
02343 #ifndef PRISM2_NO_STATION_MODES
02344         case PRISM2_PARAM_HOST_ROAMING:
02345                 if (value < 0 || value > 2) {
02346                         ret = -EINVAL;
02347                         break;
02348                 }
02349                 local->host_roaming = value;
02350                 if (hostap_set_roaming(local) || local->func->reset_port(dev))
02351                         ret = -EINVAL;
02352                 break;
02353 #endif /* PRISM2_NO_STATION_MODES */
02354 
02355         case PRISM2_PARAM_BCRX_STA_KEY:
02356                 local->bcrx_sta_key = value;
02357                 break;
02358 
02359         case PRISM2_PARAM_IEEE_802_1X:
02360                 local->ieee_802_1x = value;
02361                 break;
02362 
02363         case PRISM2_PARAM_ANTSEL_TX:
02364                 if (value < 0 || value > HOSTAP_ANTSEL_HIGH) {
02365                         ret = -EINVAL;
02366                         break;
02367                 }
02368                 local->antsel_tx = value;
02369                 hostap_set_antsel(local);
02370                 break;
02371 
02372         case PRISM2_PARAM_ANTSEL_RX:
02373                 if (value < 0 || value > HOSTAP_ANTSEL_HIGH) {
02374                         ret = -EINVAL;
02375                         break;
02376                 }
02377                 local->antsel_rx = value;
02378                 hostap_set_antsel(local);
02379                 break;
02380 
02381         case PRISM2_PARAM_MONITOR_TYPE:
02382                 if (value != PRISM2_MONITOR_80211 &&
02383                     value != PRISM2_MONITOR_CAPHDR &&
02384                     value != PRISM2_MONITOR_PRISM) {
02385                         ret = -EINVAL;
02386                         break;
02387                 }
02388                 local->monitor_type = value;
02389                 if (local->iw_mode == IW_MODE_MONITOR)
02390                         hostap_monitor_set_type(local);
02391                 break;
02392 
02393         case PRISM2_PARAM_WDS_TYPE:
02394                 local->wds_type = value;
02395                 break;
02396 
02397         case PRISM2_PARAM_HOSTSCAN:
02398         {
02399                 struct hfa384x_hostscan_request scan_req;
02400                 u16 rate;
02401 
02402                 memset(&scan_req, 0, sizeof(scan_req));
02403                 scan_req.channel_list = __constant_cpu_to_le16(0x3fff);
02404                 switch (value) {
02405                 case 1: rate = HFA384X_RATES_1MBPS; break;
02406                 case 2: rate = HFA384X_RATES_2MBPS; break;
02407                 case 3: rate = HFA384X_RATES_5MBPS; break;
02408                 case 4: rate = HFA384X_RATES_11MBPS; break;
02409                 default: rate = HFA384X_RATES_1MBPS; break;
02410                 }
02411                 scan_req.txrate = cpu_to_le16(rate);
02412                 /* leave SSID empty to accept all SSIDs */
02413 
02414                 if (local->iw_mode == IW_MODE_MASTER) {
02415                         if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
02416                                             HFA384X_PORTTYPE_BSS) ||
02417                             local->func->reset_port(dev))
02418                                 printk(KERN_DEBUG "Leaving Host AP mode "
02419                                        "for HostScan failed\n");
02420                 }
02421 
02422                 if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req,
02423                                          sizeof(scan_req))) {
02424                         printk(KERN_DEBUG "HOSTSCAN failed\n");
02425                         ret = -EINVAL;
02426                 }
02427                 if (local->iw_mode == IW_MODE_MASTER) {
02428                         wait_queue_t __wait;
02429                         init_waitqueue_entry(&__wait, current);
02430                         add_wait_queue(&local->hostscan_wq, &__wait);
02431                         set_current_state(TASK_INTERRUPTIBLE);
02432                         schedule_timeout(HZ);
02433                         if (signal_pending(current))
02434                                 ret = -EINTR;
02435                         set_current_state(TASK_RUNNING);
02436                         remove_wait_queue(&local->hostscan_wq, &__wait);
02437 
02438                         if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
02439                                             HFA384X_PORTTYPE_HOSTAP) ||
02440                             local->func->reset_port(dev))
02441                                 printk(KERN_DEBUG "Returning to Host AP mode "
02442                                        "after HostScan failed\n");
02443                 }
02444                 break;
02445         }
02446 
02447         case PRISM2_PARAM_AP_SCAN:
02448                 local->passive_scan_interval = value;
02449                 if (timer_pending(&local->passive_scan_timer))
02450                         del_timer(&local->passive_scan_timer);
02451                 if (value > 0) {
02452                         local->passive_scan_timer.expires = jiffies +
02453                                 local->passive_scan_interval * HZ;
02454                         add_timer(&local->passive_scan_timer);
02455                 }
02456                 break;
02457 
02458         case PRISM2_PARAM_ENH_SEC:
02459                 if (value < 0 || value > 3) {
02460                         ret = -EINVAL;
02461                         break;
02462                 }
02463                 local->enh_sec = value;
02464                 if (hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY,
02465                                     local->enh_sec) ||
02466                     local->func->reset_port(dev)) {
02467                         printk(KERN_INFO "%s: cnfEnhSecurity requires STA f/w "
02468                                "1.6.3 or newer\n", dev->name);
02469                         ret = -EOPNOTSUPP;
02470                 }
02471                 break;
02472 
02473 #ifdef PRISM2_IO_DEBUG
02474         case PRISM2_PARAM_IO_DEBUG:
02475                 local->io_debug_enabled = value;
02476                 break;
02477 #endif /* PRISM2_IO_DEBUG */
02478 
02479         case PRISM2_PARAM_BASIC_RATES:
02480                 if ((value & local->tx_rate_control) != value || value == 0) {
02481                         printk(KERN_INFO "%s: invalid basic rate set - basic "
02482                                "rates must be in supported rate set\n",
02483                                dev->name);
02484                         ret = -EINVAL;
02485                         break;
02486                 }
02487                 local->basic_rates = value;
02488                 if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
02489                                     local->basic_rates) ||
02490                     local->func->reset_port(dev))
02491                         ret = -EINVAL;
02492                 break;
02493 
02494         case PRISM2_PARAM_OPER_RATES:
02495                 local->tx_rate_control = value;
02496                 if (hostap_set_rate(dev))
02497                         ret = -EINVAL;
02498                 break;
02499 
02500         case PRISM2_PARAM_HOSTAPD:
02501                 ret = hostap_set_hostapd(local, value, 1);
02502                 break;
02503 
02504         default:
02505                 printk(KERN_DEBUG "%s: prism2_param: unknown param %d\n",
02506                        dev->name, param);
02507                 ret = -EOPNOTSUPP;
02508                 break;
02509         }
02510 
02511         return ret;
02512 }
02513 
02514 
02515 #if WIRELESS_EXT >= 12
02516 static int prism2_ioctl_priv_get_prism2_param(struct net_device *dev,
02517                                               struct iw_request_info *info,
02518                                               void *wrqu, char *extra)
02519 {
02520         struct hostap_interface *iface = dev->priv;
02521         local_info_t *local = iface->local;
02522         int *param = (int *) extra;
02523         int ret = 0;
02524         u16 val;
02525 
02526         switch (*param) {
02527         case PRISM2_PARAM_PTYPE:
02528                 if (local->func->get_rid(dev, HFA384X_RID_CNFPORTTYPE,
02529                                          &val, 2, 1) < 0)
02530                         ret = -EINVAL;
02531                 else
02532                         *param = le16_to_cpu(val);
02533                 break;
02534 
02535         case PRISM2_PARAM_TXRATECTRL:
02536                 *param = local->fw_tx_rate_control;
02537                 break;
02538 
02539         case PRISM2_PARAM_BEACON_INT:
02540                 *param = local->beacon_int;
02541                 break;
02542 
02543         case PRISM2_PARAM_PSEUDO_IBSS:
02544                 *param = local->pseudo_adhoc;
02545                 break;
02546 
02547         case PRISM2_PARAM_ALC:
02548                 ret = -EOPNOTSUPP; /* FIX */
02549                 break;
02550 
02551         case PRISM2_PARAM_TXPOWER:
02552                 if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF,
02553                                 HFA386X_CR_MANUAL_TX_POWER, NULL, &val))
02554                         ret = -EOPNOTSUPP;
02555                 *param = val;
02556                 break;
02557 
02558         case PRISM2_PARAM_DUMP:
02559                 *param = local->frame_dump;
02560                 break;
02561 
02562         case PRISM2_PARAM_OTHER_AP_POLICY:
02563                 if (local->ap != NULL)
02564                         *param = local->ap->ap_policy;
02565                 else
02566                         ret = -EOPNOTSUPP;
02567                 break;
02568 
02569         case PRISM2_PARAM_AP_MAX_INACTIVITY:
02570                 if (local->ap != NULL)
02571                         *param = local->ap->max_inactivity / HZ;
02572                 else
02573                         ret = -EOPNOTSUPP;
02574                 break;
02575 
02576         case PRISM2_PARAM_AP_BRIDGE_PACKETS:
02577                 if (local->ap != NULL)
02578                         *param = local->ap->bridge_packets;
02579                 else
02580                         ret = -EOPNOTSUPP;
02581                 break;
02582 
02583         case PRISM2_PARAM_DTIM_PERIOD:
02584                 *param = local->dtim_period;
02585                 break;
02586 
02587         case PRISM2_PARAM_AP_NULLFUNC_ACK:
02588                 if (local->ap != NULL)
02589                         *param = local->ap->nullfunc_ack;
02590                 else
02591                         ret = -EOPNOTSUPP;
02592                 break;
02593 
02594         case PRISM2_PARAM_MAX_WDS:
02595                 *param = local->wds_max_connections;
02596                 break;
02597 
02598         case PRISM2_PARAM_AP_AUTOM_AP_WDS:
02599                 if (local->ap != NULL)
02600                         *param = local->ap->autom_ap_wds;
02601                 else
02602                         ret = -EOPNOTSUPP;
02603                 break;
02604 
02605         case PRISM2_PARAM_AP_AUTH_ALGS:
02606                 *param = local->auth_algs;
02607                 break;
02608 
02609         case PRISM2_PARAM_MONITOR_ALLOW_FCSERR:
02610                 *param = local->monitor_allow_fcserr;
02611                 break;
02612 
02613         case PRISM2_PARAM_TX_OK:
02614           *param = (local->tx_control & HFA384X_TX_CTRL_TX_OK)
02615             ? 1 : 0;
02616           break;
02617           
02618         case PRISM2_PARAM_TX_EX:
02619           *param = (local->tx_control & HFA384X_TX_CTRL_TX_EX) 
02620             ? 1 : 0;
02621           break;
02622           
02623         case PRISM2_PARAM_HOST_ENCRYPT:
02624                 *param = local->host_encrypt;
02625                 break;
02626 
02627         case PRISM2_PARAM_HOST_DECRYPT:
02628                 *param = local->host_decrypt;
02629                 break;
02630 
02631         case PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX:
02632                 *param = local->bus_master_threshold_rx;
02633                 break;
02634 
02635         case PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX:
02636                 *param = local->bus_master_threshold_tx;
02637                 break;
02638 
02639         case PRISM2_PARAM_HOST_ROAMING:
02640                 *param = local->host_roaming;
02641                 break;
02642 
02643         case PRISM2_PARAM_BCRX_STA_KEY:
02644                 *param = local->bcrx_sta_key;
02645                 break;
02646 
02647         case PRISM2_PARAM_IEEE_802_1X:
02648                 *param = local->ieee_802_1x;
02649                 break;
02650 
02651         case PRISM2_PARAM_ANTSEL_TX:
02652                 *param = local->antsel_tx;
02653                 break;
02654 
02655         case PRISM2_PARAM_ANTSEL_RX:
02656                 *param = local->antsel_rx;
02657                 break;
02658 
02659         case PRISM2_PARAM_MONITOR_TYPE:
02660                 *param = local->monitor_type;
02661                 break;
02662 
02663         case PRISM2_PARAM_WDS_TYPE:
02664                 *param = local->wds_type;
02665                 break;
02666 
02667         case PRISM2_PARAM_HOSTSCAN:
02668                 ret = -EOPNOTSUPP;
02669                 break;
02670 
02671         case PRISM2_PARAM_AP_SCAN:
02672                 *param = local->passive_scan_interval;
02673                 break;
02674 
02675         case PRISM2_PARAM_ENH_SEC:
02676                 *param = local->enh_sec;
02677                 break;
02678 
02679 #ifdef PRISM2_IO_DEBUG
02680         case PRISM2_PARAM_IO_DEBUG:
02681                 *param = local->io_debug_enabled;
02682                 break;
02683 #endif /* PRISM2_IO_DEBUG */
02684 
02685         case PRISM2_PARAM_BASIC_RATES:
02686                 *param = local->basic_rates;
02687                 break;
02688 
02689         case PRISM2_PARAM_OPER_RATES:
02690                 *param = local->tx_rate_control;
02691                 break;
02692 
02693         case PRISM2_PARAM_HOSTAPD:
02694                 *param = local->hostapd;
02695                 break;
02696 
02697         default:
02698                 printk(KERN_DEBUG "%s: get_prism2_param: unknown param %d\n",
02699                        dev->name, *param);
02700                 ret = -EOPNOTSUPP;
02701                 break;
02702         }
02703 
02704         return ret;
02705 }
02706 #endif /* WIRELESS_EXT >= 12 */
02707 
02708 
02709 static int prism2_ioctl_priv_readmif(struct net_device *dev,
02710                                      struct iw_request_info *info,
02711                                      void *wrqu, char *extra)
02712 {
02713         struct hostap_interface *iface = dev->priv;
02714         local_info_t *local = iface->local;
02715         u16 resp0;
02716 
02717         if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, *extra, NULL,
02718                              &resp0))
02719                 return -EOPNOTSUPP;
02720         else
02721                 *extra = resp0;
02722 
02723         return 0;
02724 }
02725 
02726 
02727 static int prism2_ioctl_priv_writemif(struct net_device *dev,
02728                                       struct iw_request_info *info,
02729                                       void *wrqu, char *extra)
02730 {
02731         struct hostap_interface *iface = dev->priv;
02732         local_info_t *local = iface->local;
02733         u16 cr, val;
02734 
02735         cr = *extra;
02736         val = *(extra + 1);
02737         if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, cr, &val, NULL))
02738                 return -EOPNOTSUPP;
02739 
02740         return 0;
02741 }
02742 
02743 
02744 static int prism2_ioctl_priv_dssstest(struct net_device *dev, int *i)
02745 {
02746   struct hostap_interface *iface = dev->priv;
02747   local_info_t *local = iface->local;
02748   int ret = 0;
02749   
02750   if (*i == 0) {
02751     ret = hostap_dssstest_mode_disable(local);
02752   } else if (*i == 1) {
02753     ret = hostap_dssstest_mode_enable(local);
02754   } else
02755     ret = -EINVAL;
02756   
02757   return ret;
02758   
02759 }
02760 
02761 static int prism2_ioctl_priv_monitor(struct net_device *dev, int *i)
02762 {
02763         struct hostap_interface *iface = dev->priv;
02764         local_info_t *local = iface->local;
02765         int ret = 0;
02766         u32 mode;
02767 
02768         printk(KERN_DEBUG "%s: process %d (%s) used deprecated iwpriv monitor "
02769                "- update software to use iwconfig mode monitor\n",
02770                dev->name, current->pid, current->comm);
02771 
02772         /* Backward compatibility code - this can be removed at some point */
02773 
02774         if (*i == 0) {
02775                 /* Disable monitor mode - old mode was not saved, so go to
02776                  * Master mode */
02777                 mode = IW_MODE_MASTER;
02778                 ret = prism2_ioctl_siwmode(dev, NULL, &mode, NULL);
02779         } else if (*i == 1) {
02780                 /* netlink socket mode is not supported anymore since it did
02781                  * not separate different devices from each other and was not
02782                  * best method for delivering large amount of packets to
02783                  * user space */
02784                 ret = -EOPNOTSUPP;
02785         } else if (*i == 2 || *i == 3) {
02786                 switch (*i) {
02787                 case 2:
02788                         local->monitor_type = PRISM2_MONITOR_80211;
02789                         break;
02790                 case 3:
02791                         local->monitor_type = PRISM2_MONITOR_PRISM;
02792                         break;
02793                 }
02794                 mode = IW_MODE_MONITOR;
02795                 ret = prism2_ioctl_siwmode(dev, NULL, &mode, NULL);
02796                 hostap_monitor_mode_enable(local);
02797         } else
02798                 ret = -EINVAL;
02799 
02800         return ret;
02801 }
02802 
02803 
02804 static int prism2_ioctl_priv_reset(struct net_device *dev, int *i)
02805 {
02806         struct hostap_interface *iface = dev->priv;
02807         local_info_t *local = iface->local;
02808 
02809         printk(KERN_DEBUG "%s: manual reset request(%d)\n", dev->name, *i);
02810         switch (*i) {
02811         case 0:
02812                 /* Disable and enable card */
02813                 local->func->hw_shutdown(dev, 1);
02814                 local->func->hw_config(dev, 0);
02815                 break;
02816 
02817         case 1:
02818                 /* COR sreset */
02819                 local->func->hw_reset(dev);
02820                 break;
02821 
02822         case 2:
02823                 /* Disable and enable port 0 */
02824                 local->func->reset_port(dev);
02825                 break;
02826 
02827         case 3:
02828                 if (local->func->cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL,
02829                                      NULL))
02830                         return -EINVAL;
02831                 break;
02832 
02833         case 4:
02834                 if (local->func->cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL,
02835                                      NULL))
02836                         return -EINVAL;
02837                 break;
02838 
02839         default:
02840                 printk(KERN_DEBUG "Unknown reset request %d\n", *i);
02841                 return -EOPNOTSUPP;
02842         }
02843 
02844         return 0;
02845 }
02846 
02847 
02848 #ifndef PRISM2_USE_WE_TYPE_ADDR
02849 static inline int hex2int(char c)
02850 {
02851         if (c >= '0' && c <= '9')
02852                 return (c - '0');
02853         if (c >= 'a' && c <= 'f')
02854                 return (c - 'a' + 10);
02855         if (c >= 'A' && c <= 'F')
02856                 return (c - 'A' + 10);
02857         return -1;
02858 }
02859 
02860 static int macstr2addr(char *macstr, u8 *addr)
02861 {
02862         int i, val, val2;
02863         char *pos = macstr;
02864 
02865         for (i = 0; i < 6; i++) {
02866                 val = hex2int(*pos++);
02867                 if (val < 0)
02868                         return -1;
02869                 val2 = hex2int(*pos++);
02870                 if (val2 < 0)
02871                         return -1;
02872                 addr[i] = (val * 16 + val2) & 0xff;
02873 
02874                 if (i < 5 && *pos++ != ':')
02875                         return -1;
02876         }
02877 
02878         return 0;
02879 }
02880 
02881 
02882 static int prism2_ioctl_priv_wds(struct net_device *dev, int add, char *macstr)
02883 {
02884         struct hostap_interface *iface = dev->priv;
02885         local_info_t *local = iface->local;
02886         u8 addr[6];
02887 
02888         if (macstr2addr(macstr, addr)) {
02889                 printk(KERN_DEBUG "Invalid MAC address\n");
02890                 return -EINVAL;
02891         }
02892 
02893         if (add)
02894                 return prism2_wds_add(local, addr, 1);
02895         else
02896                 return prism2_wds_del(local, addr, 1, 0);
02897 }
02898 #endif /* PRISM2_USE_WE_TYPE_ADDR */
02899 
02900 
02901 static int prism2_ioctl_priv_set_rid_word(struct net_device *dev, int *i)
02902 {
02903         int rid = *i;
02904         int value = *(i + 1);
02905 
02906         printk(KERN_DEBUG "%s: Set RID[0x%X] = %d\n", dev->name, rid, value);
02907 
02908         if (hostap_set_word(dev, rid, value))
02909                 return -EINVAL;
02910 
02911         return 0;
02912 }
02913 
02914 
02915 #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
02916 static int ap_mac_cmd_ioctl(local_info_t *local, int *cmd)
02917 {
02918         int ret = 0;
02919 
02920         switch (*cmd) {
02921         case AP_MAC_CMD_POLICY_OPEN:
02922                 local->ap->mac_restrictions.policy = MAC_POLICY_OPEN;
02923                 break;
02924         case AP_MAC_CMD_POLICY_ALLOW:
02925                 local->ap->mac_restrictions.policy = MAC_POLICY_ALLOW;
02926                 break;
02927         case AP_MAC_CMD_POLICY_DENY:
02928                 local->ap->mac_restrictions.policy = MAC_POLICY_DENY;
02929                 break;
02930         case AP_MAC_CMD_FLUSH:
02931                 ap_control_flush_macs(&local->ap->mac_restrictions);
02932                 break;
02933         case AP_MAC_CMD_KICKALL:
02934                 ap_control_kickall(local->ap);
02935                 hostap_deauth_all_stas(local->dev, local->ap, 0);
02936                 break;
02937         default:
02938                 ret = -EOPNOTSUPP;
02939                 break;
02940         }
02941 
02942         return ret;
02943 }
02944 
02945 
02946 enum { AP_CTRL_MAC_ADD, AP_CTRL_MAC_DEL, AP_CTRL_MAC_KICK };
02947 
02948 #ifndef PRISM2_USE_WE_TYPE_ADDR
02949 static int ap_mac_ioctl(local_info_t *local, char *macstr, int cmd)
02950 {
02951         u8 addr[6];
02952 
02953         if (macstr2addr(macstr, addr)) {
02954                 printk(KERN_DEBUG "Invalid MAC address '%s'\n", macstr);
02955                 return -EINVAL;
02956         }
02957 
02958         switch (cmd) {
02959         case AP_CTRL_MAC_ADD:
02960                 return ap_control_add_mac(&local->ap->mac_restrictions, addr);
02961         case AP_CTRL_MAC_DEL:
02962                 return ap_control_del_mac(&local->ap->mac_restrictions, addr);
02963         case AP_CTRL_MAC_KICK:
02964                 return ap_control_kick_mac(local->ap, local->dev, addr);
02965         default:
02966                 return -EOPNOTSUPP;
02967         }
02968 }
02969 #endif /* PRISM2_USE_WE_TYPE_ADDR */
02970 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
02971 
02972 
02973 #ifdef PRISM2_DOWNLOAD_SUPPORT
02974 static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p)
02975 {
02976         struct prism2_download_param *param;
02977         int ret = 0;
02978 
02979         if (p->length < sizeof(struct prism2_download_param) ||
02980             p->length > 1024 || !p->pointer)
02981                 return -EINVAL;
02982 
02983         param = (struct prism2_download_param *)
02984                 kmalloc(p->length, GFP_KERNEL);
02985         if (param == NULL)
02986                 return -ENOMEM;
02987 
02988         if (copy_from_user(param, p->pointer, p->length)) {
02989                 ret = -EFAULT;
02990                 goto out;
02991         }
02992 
02993         if (p->length < sizeof(struct prism2_download_param) +
02994             param->num_areas * sizeof(struct prism2_download_area)) {
02995                 ret = -EINVAL;
02996                 goto out;
02997         }
02998 
02999         ret = local->func->download(local, param);
03000 
03001  out:
03002         if (param != NULL)
03003                 kfree(param);
03004 
03005         return ret;
03006 }
03007 #endif /* PRISM2_DOWNLOAD_SUPPORT */
03008 
03009 
03010 static int prism2_ioctl_set_encryption(local_info_t *local,
03011                                        struct prism2_hostapd_param *param,
03012                                        int param_len)
03013 {
03014         int ret = 0;
03015         struct hostap_crypto_ops *ops;
03016         struct prism2_crypt_data **crypt;
03017         void *sta_ptr;
03018 
03019         param->u.crypt.err = 0;
03020         param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0';
03021 
03022         if (param_len !=
03023             (int) ((char *) param->u.crypt.key - (char *) param) +
03024             param->u.crypt.key_len)
03025                 return -EINVAL;
03026 
03027         if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
03028             param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
03029             param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
03030                 sta_ptr = NULL;
03031                 crypt = &local->crypt;
03032         } else {
03033                 sta_ptr = ap_crypt_get_ptrs(
03034                         local->ap, param->sta_addr,
03035                         (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_PERMANENT),
03036                         &crypt);
03037 
03038                 if (sta_ptr == NULL) {
03039                         param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
03040                         return -EINVAL;
03041                 }
03042         }
03043 
03044         if (strcmp(param->u.crypt.alg, "none") == 0) {
03045                 prism2_crypt_delayed_deinit(local, crypt);
03046                 goto done;
03047         }
03048 
03049         ops = hostap_get_crypto_ops(param->u.crypt.alg);
03050         if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) {
03051                 request_module("hostap_crypt_wep");
03052                 ops = hostap_get_crypto_ops(param->u.crypt.alg);
03053         }
03054         if (ops == NULL) {
03055                 printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
03056                        local->dev->name, param->u.crypt.alg);
03057                 param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG;
03058                 ret = -EINVAL;
03059                 goto done;
03060         }
03061 
03062         /* station based encryption and other than WEP algorithms require
03063          * host-based encryption, so force them on automatically */
03064         local->host_decrypt = local->host_encrypt = 1;
03065 
03066         if (*crypt == NULL || (*crypt)->ops != ops) {
03067                 struct prism2_crypt_data *new_crypt;
03068 
03069                 prism2_crypt_delayed_deinit(local, crypt);
03070 
03071                 new_crypt = (struct prism2_crypt_data *)
03072                         kmalloc(sizeof(struct prism2_crypt_data), GFP_KERNEL);
03073                 if (new_crypt == NULL) {
03074                         ret = -ENOMEM;
03075                         goto done;
03076                 }
03077                 memset(new_crypt, 0, sizeof(struct prism2_crypt_data));
03078                 new_crypt->ops = ops;
03079                 new_crypt->priv = new_crypt->ops->init();
03080                 if (new_crypt->priv == NULL) {
03081                         kfree(new_crypt);
03082                         param->u.crypt.err =
03083                                 HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED;
03084                         ret = -EINVAL;
03085                         goto done;
03086                 }
03087 
03088                 *crypt = new_crypt;
03089         }
03090 
03091         if ((!(param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) ||
03092              param->u.crypt.key_len > 0) && (*crypt)->ops->set_key &&
03093             (*crypt)->ops->set_key(param->u.crypt.idx, param->u.crypt.key,
03094                               param->u.crypt.key_len, (*crypt)->priv) < 0) {
03095                 printk(KERN_DEBUG "%s: key setting failed\n",
03096                        local->dev->name);
03097                 param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED;
03098                 ret = -EINVAL;
03099                 goto done;
03100         }
03101 
03102         if ((param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) &&
03103             (*crypt)->ops->set_key_idx &&
03104             (*crypt)->ops->set_key_idx(param->u.crypt.idx, (*crypt)->priv) < 0)
03105         {
03106                 printk(KERN_DEBUG "%s: TX key idx setting failed\n",
03107                        local->dev->name);
03108                 param->u.crypt.err = HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED;
03109                 ret = -EINVAL;
03110                 goto done;
03111         }
03112 
03113  done:
03114         if (sta_ptr)
03115                 hostap_handle_sta_release(sta_ptr);
03116 
03117         if (ret == 0 &&
03118             (hostap_set_encryption(local) ||
03119              local->func->reset_port(local->dev))) {
03120                 param->u.crypt.err = HOSTAP_CRYPT_ERR_CARD_CONF_FAILED;
03121                 return -EINVAL;
03122         }
03123 
03124         return ret;
03125 }
03126 
03127 
03128 static int prism2_ioctl_get_encryption(local_info_t *local,
03129                                        struct prism2_hostapd_param *param,
03130                                        int param_len)
03131 {
03132         struct prism2_crypt_data **crypt;
03133         void *sta_ptr;
03134         int max_key_len;
03135 
03136         param->u.crypt.err = 0;
03137 
03138         max_key_len = param_len -
03139                 (int) ((char *) param->u.crypt.key - (char *) param);
03140         if (max_key_len < 0)
03141                 return -EINVAL;
03142 
03143         if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
03144             param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
03145             param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
03146                 sta_ptr = NULL;
03147                 crypt = &local->crypt;
03148         } else {
03149                 sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0,
03150                                             &crypt);
03151 
03152                 if (sta_ptr == NULL) {
03153                         param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
03154                         return -EINVAL;
03155                 }
03156         }
03157 
03158         if (*crypt == NULL || (*crypt)->ops == NULL) {
03159                 memcpy(param->u.crypt.alg, "none", 5);
03160                 param->u.crypt.key_len = 0;
03161                 param->u.crypt.idx = 0xff;
03162         } else {
03163                 strncpy(param->u.crypt.alg, (*crypt)->ops->name,
03164                         HOSTAP_CRYPT_ALG_NAME_LEN);
03165                 param->u.crypt.key_len = 0;
03166                 if (param->u.crypt.idx >= WEP_KEYS &&
03167                     (*crypt)->ops->get_key_idx)
03168                         param->u.crypt.idx =
03169                                 (*crypt)->ops->get_key_idx((*crypt)->priv);
03170 
03171                 if (param->u.crypt.idx < WEP_KEYS && (*crypt)->ops->get_key)
03172                         param->u.crypt.key_len =
03173                                 (*crypt)->ops->get_key(param->u.crypt.idx,
03174                                                        param->u.crypt.key,
03175                                                        max_key_len,
03176                                                        (*crypt)->priv);
03177         }
03178 
03179         if (sta_ptr)
03180                 hostap_handle_sta_release(sta_ptr);
03181 
03182         return 0;
03183 }
03184 
03185 
03186 static int prism2_ioctl_get_rid(local_info_t *local,
03187                                 struct prism2_hostapd_param *param,
03188                                 int param_len)
03189 {
03190         int max_len, res;
03191 
03192         max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN;
03193         if (max_len < 0)
03194                 return -EINVAL;
03195 
03196         res = local->func->get_rid(local->dev, param->u.rid.rid,
03197                                    param->u.rid.data, param->u.rid.len, 0);
03198         if (res >= 0) {
03199                 param->u.rid.len = res;
03200                 return 0;
03201         }
03202 
03203         return res;
03204 }
03205 
03206 
03207 static int prism2_ioctl_set_rid(local_info_t *local,
03208                                 struct prism2_hostapd_param *param,
03209                                 int param_len)
03210 {
03211         int max_len;
03212 
03213         max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN;
03214         if (max_len < 0 || max_len < param->u.rid.len)
03215                 return -EINVAL;
03216 
03217         return local->func->set_rid(local->dev, param->u.rid.rid,
03218                                     param->u.rid.data, param->u.rid.len);
03219 }
03220 
03221 
03222 static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local,
03223                                           struct prism2_hostapd_param *param,
03224                                           int param_len)
03225 {
03226         printk(KERN_DEBUG "%ssta: associated as client with AP " MACSTR "\n",
03227                local->dev->name, MAC2STR(param->sta_addr));
03228         memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN);
03229         return 0;
03230 }
03231 
03232 
03233 static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p)
03234 {
03235         struct prism2_hostapd_param *param;
03236         int ret = 0;
03237         int ap_ioctl = 0;
03238 
03239         if (p->length < sizeof(struct prism2_hostapd_param) ||
03240             p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
03241                 return -EINVAL;
03242 
03243         param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL);
03244         if (param == NULL)
03245                 return -ENOMEM;
03246 
03247         if (copy_from_user(param, p->pointer, p->length)) {
03248                 ret = -EFAULT;
03249                 goto out;
03250         }
03251 
03252         switch (param->cmd) {
03253         case PRISM2_SET_ENCRYPTION:
03254                 ret = prism2_ioctl_set_encryption(local, param, p->length);
03255                 break;
03256         case PRISM2_GET_ENCRYPTION:
03257                 ret = prism2_ioctl_get_encryption(local, param, p->length);
03258                 break;
03259         case PRISM2_HOSTAPD_GET_RID:
03260                 ret = prism2_ioctl_get_rid(local, param, p->length);
03261                 break;
03262         case PRISM2_HOSTAPD_SET_RID:
03263                 ret = prism2_ioctl_set_rid(local, param, p->length);
03264                 break;
03265         case PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR:
03266                 ret = prism2_ioctl_set_assoc_ap_addr(local, param, p->length);
03267                 break;
03268         default:
03269                 ret = prism2_hostapd(local->ap, param);
03270                 ap_ioctl = 1;
03271                 break;
03272         }
03273 
03274         if (ret == 1 || !ap_ioctl) {
03275                 if (copy_to_user(p->pointer, param, p->length)) {
03276                         ret = -EFAULT;
03277                         goto out;
03278                 } else if (ap_ioctl)
03279                         ret = 0;
03280         }
03281 
03282  out:
03283         if (param != NULL)
03284                 kfree(param);
03285 
03286         return ret;
03287 }
03288 
03289 
03290 #if WIRELESS_EXT > 12
03291 /* Structures to export the Wireless Handlers */
03292 
03293 static const iw_handler prism2_handler[] =
03294 {
03295         (iw_handler) NULL,                              /* SIOCSIWCOMMIT */
03296         (iw_handler) prism2_get_name,                   /* SIOCGIWNAME */
03297         (iw_handler) NULL,                              /* SIOCSIWNWID */
03298         (iw_handler) NULL,                              /* SIOCGIWNWID */
03299         (iw_handler) prism2_ioctl_siwfreq,              /* SIOCSIWFREQ */
03300         (iw_handler) prism2_ioctl_giwfreq,              /* SIOCGIWFREQ */
03301         (iw_handler) prism2_ioctl_siwmode,              /* SIOCSIWMODE */
03302         (iw_handler) prism2_ioctl_giwmode,              /* SIOCGIWMODE */
03303         (iw_handler) prism2_ioctl_siwsens,              /* SIOCSIWSENS */
03304         (iw_handler) prism2_ioctl_giwsens,              /* SIOCGIWSENS */
03305         (iw_handler) NULL /* not used */,               /* SIOCSIWRANGE */
03306         (iw_handler) prism2_ioctl_giwrange,             /* SIOCGIWRANGE */
03307         (iw_handler) NULL /* not used */,               /* SIOCSIWPRIV */
03308         (iw_handler) NULL /* kernel code */,            /* SIOCGIWPRIV */
03309         (iw_handler) NULL /* not used */,               /* SIOCSIWSTATS */
03310         (iw_handler) NULL /* kernel code */,            /* SIOCGIWSTATS */
03311 #if WIRELESS_EXT > 15
03312         iw_handler_set_spy,                             /* SIOCSIWSPY */
03313         iw_handler_get_spy,                             /* SIOCGIWSPY */
03314         iw_handler_set_thrspy,                          /* SIOCSIWTHRSPY */
03315         iw_handler_get_thrspy,                          /* SIOCGIWTHRSPY */
03316 #else /* WIRELESS_EXT > 15 */
03317         (iw_handler) NULL,                              /* SIOCSIWSPY */
03318         (iw_handler) prism2_ioctl_giwspy,               /* SIOCGIWSPY */
03319         (iw_handler) NULL,                              /* -- hole -- */
03320         (iw_handler) NULL,                              /* -- hole -- */
03321 #endif /* WIRELESS_EXT > 15 */
03322         (iw_handler) prism2_ioctl_siwap,                /* SIOCSIWAP */
03323         (iw_handler) prism2_ioctl_giwap,                /* SIOCGIWAP */
03324         (iw_handler) NULL,                              /* -- hole -- */
03325         (iw_handler) prism2_ioctl_giwaplist,            /* SIOCGIWAPLIST */
03326 #if WIRELESS_EXT > 13
03327         (iw_handler) prism2_ioctl_siwscan,              /* SIOCSIWSCAN */
03328         (iw_handler) prism2_ioctl_giwscan,              /* SIOCGIWSCAN */
03329 #else /* WIRELESS_EXT > 13 */
03330         (iw_handler) NULL,                              /* SIOCSIWSCAN */
03331         (iw_handler) NULL,                              /* SIOCGIWSCAN */
03332 #endif /* WIRELESS_EXT > 13 */
03333         (iw_handler) prism2_ioctl_siwessid,             /* SIOCSIWESSID */
03334         (iw_handler) prism2_ioctl_giwessid,             /* SIOCGIWESSID */
03335         (iw_handler) prism2_ioctl_siwnickn,             /* SIOCSIWNICKN */
03336         (iw_handler) prism2_ioctl_giwnickn,             /* SIOCGIWNICKN */
03337         (iw_handler) NULL,                              /* -- hole -- */
03338         (iw_handler) NULL,                              /* -- hole -- */
03339         (iw_handler) prism2_ioctl_siwrate,              /* SIOCSIWRATE */
03340         (iw_handler) prism2_ioctl_giwrate,              /* SIOCGIWRATE */
03341         (iw_handler) prism2_ioctl_siwrts,               /* SIOCSIWRTS */
03342         (iw_handler) prism2_ioctl_giwrts,               /* SIOCGIWRTS */
03343         (iw_handler) prism2_ioctl_siwfrag,              /* SIOCSIWFRAG */
03344         (iw_handler) prism2_ioctl_giwfrag,              /* SIOCGIWFRAG */
03345         (iw_handler) prism2_ioctl_siwtxpow,             /* SIOCSIWTXPOW */
03346         (iw_handler) prism2_ioctl_giwtxpow,             /* SIOCGIWTXPOW */
03347         (iw_handler) prism2_ioctl_siwretry,             /* SIOCSIWRETRY */
03348         (iw_handler) prism2_ioctl_giwretry,             /* SIOCGIWRETRY */
03349         (iw_handler) prism2_ioctl_siwencode,            /* SIOCSIWENCODE */
03350         (iw_handler) prism2_ioctl_giwencode,            /* SIOCGIWENCODE */
03351         (iw_handler) prism2_ioctl_siwpower,             /* SIOCSIWPOWER */
03352         (iw_handler) prism2_ioctl_giwpower,             /* SIOCGIWPOWER */
03353 };
03354 
03355 static const iw_handler prism2_private_handler[] =
03356 {                                                       /* SIOCIWFIRSTPRIV + */
03357         (iw_handler) prism2_ioctl_priv_prism2_param,    /* 0 */
03358         (iw_handler) prism2_ioctl_priv_get_prism2_param, /* 1 */
03359         (iw_handler) prism2_ioctl_priv_writemif,        /* 2 */
03360         (iw_handler) prism2_ioctl_priv_readmif,         /* 3 */
03361 };
03362 
03363 static const struct iw_handler_def hostap_iw_handler_def =
03364 {
03365         .num_standard   = sizeof(prism2_handler) / sizeof(iw_handler),
03366         .num_private    = sizeof(prism2_private_handler) / sizeof(iw_handler),
03367         .num_private_args = sizeof(prism2_priv) / sizeof(struct iw_priv_args),
03368         .standard       = (iw_handler *) prism2_handler,
03369         .private        = (iw_handler *) prism2_private_handler,
03370         .private_args   = (struct iw_priv_args *) prism2_priv,
03371 #if WIRELESS_EXT > 15
03372         .spy_offset     = offsetof(struct hostap_interface, spy_data),
03373 #endif /* WIRELESS_EXT > 15 */
03374 };
03375 #endif  /* WIRELESS_EXT > 12 */
03376 
03377 
03378 int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
03379 {
03380         struct iwreq *wrq = (struct iwreq *) ifr;
03381         struct hostap_interface *iface = dev->priv;
03382         local_info_t *local = iface->local;
03383         int ret = 0;
03384 
03385         switch (cmd) {
03386 
03387 #if WIRELESS_EXT <= 12
03388         case SIOCGIWNAME:
03389                 ret = prism2_get_name(dev, NULL, (char *) &wrq->u, NULL);
03390                 break;
03391 
03392         case SIOCSIWFREQ:
03393                 ret = prism2_ioctl_siwfreq(dev, NULL, &wrq->u.freq, NULL);
03394                 break;
03395         case SIOCGIWFREQ:
03396                 ret = prism2_ioctl_giwfreq(dev, NULL, &wrq->u.freq, NULL);
03397                 break;
03398 
03399         case SIOCSIWAP:
03400                 ret = prism2_ioctl_siwap(dev, NULL, &wrq->u.ap_addr, NULL);
03401                 break;
03402         case SIOCGIWAP:
03403                 ret = prism2_ioctl_giwap(dev, NULL, &wrq->u.ap_addr, NULL);
03404                 break;
03405 
03406         case SIOCSIWESSID:
03407                 if (!wrq->u.essid.pointer)
03408                         ret = -EINVAL;
03409                 else if (wrq->u.essid.length > IW_ESSID_MAX_SIZE)
03410                         ret = -E2BIG;
03411                 else {
03412                         char ssid[IW_ESSID_MAX_SIZE];
03413                         if (copy_from_user(ssid, wrq->u.essid.pointer,
03414                                            wrq->u.essid.length)) {
03415                                 ret = -EFAULT;
03416                                 break;
03417                         }
03418                         ret = prism2_ioctl_siwessid(dev, NULL, &wrq->u.essid,
03419                                                     ssid);
03420                 }
03421                 break;
03422         case SIOCGIWESSID:
03423                 if (wrq->u.essid.length > IW_ESSID_MAX_SIZE)
03424                         ret = -E2BIG;
03425                 else if (wrq->u.essid.pointer) {
03426                         char ssid[IW_ESSID_MAX_SIZE];
03427                         ret = prism2_ioctl_giwessid(dev, NULL, &wrq->u.essid,
03428                                                     ssid);
03429                         if (copy_to_user(wrq->u.essid.pointer, ssid,
03430                                          wrq->u.essid.length))
03431                                 ret = -EFAULT;
03432                 }
03433                 break;
03434 
03435         case SIOCSIWRATE:
03436                 ret = prism2_ioctl_siwrate(dev, NULL, &wrq->u.bitrate, NULL);
03437                 break;
03438         case SIOCGIWRATE:
03439                 ret = prism2_ioctl_giwrate(dev, NULL, &wrq->u.bitrate, NULL);
03440                 break;
03441 
03442         case SIOCSIWRTS:
03443                 ret = prism2_ioctl_siwrts(dev, NULL, &wrq->u.rts, NULL);
03444                 break;
03445         case SIOCGIWRTS:
03446                 ret = prism2_ioctl_giwrts(dev, NULL, &wrq->u.rts, NULL);
03447                 break;
03448 
03449         case SIOCSIWFRAG:
03450                 ret = prism2_ioctl_siwfrag(dev, NULL, &wrq->u.rts, NULL);
03451                 break;
03452         case SIOCGIWFRAG:
03453                 ret = prism2_ioctl_giwfrag(dev, NULL, &wrq->u.rts, NULL);
03454                 break;
03455 
03456         case SIOCSIWENCODE:
03457                 {
03458                         char keybuf[WEP_KEY_LEN];
03459                         if (wrq->u.encoding.pointer) {
03460                                 if (wrq->u.encoding.length > WEP_KEY_LEN) {
03461                                         ret = -E2BIG;
03462                                         break;
03463                                 }
03464                                 if (copy_from_user(keybuf,
03465                                                    wrq->u.encoding.pointer,
03466                                                    wrq->u.encoding.length)) {
03467                                         ret = -EFAULT;
03468                                         break;
03469                                 }
03470                         } else if (wrq->u.encoding.length != 0) {
03471                                 ret = -EINVAL;
03472                                 break;
03473                         }
03474                         ret = prism2_ioctl_siwencode(dev, NULL,
03475                                                      &wrq->u.encoding, keybuf);
03476                 }
03477                 break;
03478         case SIOCGIWENCODE:
03479                 if (!capable(CAP_NET_ADMIN))
03480                         ret = -EPERM;
03481                 else if (wrq->u.encoding.pointer) {
03482                         char keybuf[WEP_KEY_LEN];
03483                         ret = prism2_ioctl_giwencode(dev, NULL,
03484                                                      &wrq->u.encoding, keybuf);
03485                         if (copy_to_user(wrq->u.encoding.pointer, keybuf,
03486                                          wrq->u.encoding.length))
03487                                 ret = -EFAULT;
03488                 }
03489                 break;
03490 
03491         case SIOCSIWNICKN:
03492                 if (wrq->u.essid.length > IW_ESSID_MAX_SIZE)
03493                         ret = -E2BIG;
03494                 else if (wrq->u.essid.pointer) {
03495                         char nickbuf[IW_ESSID_MAX_SIZE + 1];
03496                         if (copy_from_user(nickbuf, wrq->u.essid.pointer,
03497                                            wrq->u.essid.length)) {
03498                                 ret = -EFAULT;
03499                                 break;
03500                         }
03501                         ret = prism2_ioctl_siwnickn(dev, NULL, &wrq->u.essid,
03502                                                     nickbuf);
03503                 }
03504                 break;
03505         case SIOCGIWNICKN:
03506                 if (wrq->u.essid.pointer) {
03507                         char nickbuf[IW_ESSID_MAX_SIZE + 1];
03508                         ret = prism2_ioctl_giwnickn(dev, NULL, &wrq->u.essid,
03509                                                     nickbuf);
03510                         if (copy_to_user(wrq->u.essid.pointer, nickbuf,
03511                                          wrq->u.essid.length))
03512                                 ret = -EFAULT;
03513                 }
03514                 break;
03515 
03516         case SIOCGIWSPY:
03517                 {
03518                         char buffer[IW_MAX_SPY * (sizeof(struct sockaddr) +
03519                                                   sizeof(struct iw_quality))];
03520                         ret = prism2_ioctl_giwspy(dev, NULL, &wrq->u.data,
03521                                                   buffer);
03522                         if (ret == 0 && wrq->u.data.pointer &&
03523                             copy_to_user(wrq->u.data.pointer, buffer,
03524                                          wrq->u.data.length *
03525                                          (sizeof(struct sockaddr) +
03526                                           sizeof(struct iw_quality))))
03527                                 ret = -EFAULT;
03528                 }
03529                 break;
03530 
03531         case SIOCGIWRANGE:
03532                 {
03533                         struct iw_range range;
03534                         ret = prism2_ioctl_giwrange(dev, NULL, &wrq->u.data,
03535                                                     (char *) &range);
03536                         if (copy_to_user(wrq->u.data.pointer, &range,
03537                                          sizeof(struct iw_range)))
03538                                 ret = -EFAULT;
03539                 }
03540                 break;
03541 
03542         case SIOCSIWSENS:
03543                 ret = prism2_ioctl_siwsens(dev, NULL, &wrq->u.sens, NULL);
03544                 break;
03545         case SIOCGIWSENS:
03546                 ret = prism2_ioctl_giwsens(dev, NULL, &wrq->u.sens, NULL);
03547                 break;
03548 
03549         case SIOCGIWAPLIST:
03550                 if (wrq->u.data.pointer) {
03551                         char buffer[IW_MAX_AP * (sizeof(struct sockaddr) +
03552                                                  sizeof(struct iw_quality))];
03553                         ret = prism2_ioctl_giwaplist(dev, NULL, &wrq->u.data,
03554                                                      buffer);
03555                         if (copy_to_user(wrq->u.data.pointer, buffer,
03556                                          (wrq->u.data.length *
03557                                           (sizeof(struct sockaddr) +
03558                                            sizeof(struct iw_quality)))))
03559                                 ret = -EFAULT;
03560                 }
03561                 break;
03562 
03563         case SIOCSIWMODE:
03564                 ret = prism2_ioctl_siwmode(dev, NULL, &wrq->u.mode, NULL);
03565                 break;
03566         case SIOCGIWMODE:
03567                 ret = prism2_ioctl_giwmode(dev, NULL, &wrq->u.mode, NULL);
03568                 break;
03569 
03570         case SIOCSIWPOWER:
03571                 ret = prism2_ioctl_siwpower(dev, NULL, &wrq->u.power, NULL);
03572                 break;
03573         case SIOCGIWPOWER:
03574                 ret = prism2_ioctl_giwpower(dev, NULL, &wrq->u.power, NULL);
03575                 break;
03576 
03577         case SIOCGIWPRIV:
03578                 ret = prism2_ioctl_giwpriv(dev, &wrq->u.data);
03579                 break;
03580 
03581 #if WIRELESS_EXT > 9
03582         case SIOCSIWTXPOW:
03583                 ret = prism2_ioctl_siwtxpow(dev, NULL, &wrq->u.txpower, NULL);
03584                 break;
03585         case SIOCGIWTXPOW:
03586                 ret = prism2_ioctl_giwtxpow(dev, NULL, &wrq->u.txpower, NULL);
03587                 break;
03588 #endif /* WIRELESS_EXT > 9 */
03589 
03590 #if WIRELESS_EXT > 10
03591         case SIOCSIWRETRY:
03592                 ret = prism2_ioctl_siwretry(dev, NULL, &wrq->u.retry, NULL);
03593                 break;
03594         case SIOCGIWRETRY:
03595                 ret = prism2_ioctl_giwretry(dev, NULL, &wrq->u.retry, NULL);
03596                 break;
03597 #endif /* WIRELESS_EXT > 10 */
03598 
03599         /* not supported wireless extensions */
03600         case SIOCSIWNWID:
03601         case SIOCGIWNWID:
03602                 ret = -EOPNOTSUPP;
03603                 break;
03604 
03605         /* FIX: add support for this: */
03606         case SIOCSIWSPY:
03607                 printk(KERN_DEBUG "%s unsupported WIRELESS_EXT ioctl(0x%04x)\n"
03608                        , dev->name, cmd);
03609                 ret = -EOPNOTSUPP;
03610                 break;
03611 
03612 
03613                 /* Private ioctls (iwpriv); these are in SIOCDEVPRIVATE range
03614                  * if WIRELESS_EXT < 12, so better check privileges */
03615 
03616         case PRISM2_IOCTL_PRISM2_PARAM:
03617                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03618                 else ret = prism2_ioctl_priv_prism2_param(dev, NULL, &wrq->u,
03619                                                           (char *) &wrq->u);
03620                 break;
03621 #if WIRELESS_EXT >= 12
03622         case PRISM2_IOCTL_GET_PRISM2_PARAM:
03623                 ret = prism2_ioctl_priv_get_prism2_param(dev, NULL, &wrq->u,
03624                                                          (char *) &wrq->u);
03625                 break;
03626 #endif /* WIRELESS_EXT >= 12 */
03627 
03628         case PRISM2_IOCTL_WRITEMIF:
03629                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03630                 else ret = prism2_ioctl_priv_writemif(dev, NULL, &wrq->u,
03631                                                       (char *) &wrq->u);
03632                 break;
03633 
03634         case PRISM2_IOCTL_READMIF:
03635                 ret = prism2_ioctl_priv_readmif(dev, NULL, &wrq->u,
03636                                                 (char *) &wrq->u);
03637                 break;
03638 
03639 #endif /* WIRELESS_EXT <= 12 */
03640 
03641 
03642                 /* Private ioctls (iwpriv) that have not yet been converted
03643                  * into new wireless extensions API */
03644 
03645         case PRISM2_IOCTL_INQUIRE:
03646                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03647                 else ret = prism2_ioctl_priv_inquire(dev, (int *) wrq->u.name);
03648                 break;
03649 
03650         case PRISM2_IOCTL_MONITOR:
03651           if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03652           else ret = prism2_ioctl_priv_monitor(dev, (int *) wrq->u.name);
03653           break;
03654 
03655         case PRISM2_IOCTL_DSSSTEST:
03656           if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03657           else ret = prism2_ioctl_priv_dssstest(dev, (int *)
03658                                                 wrq->u.name);
03659           break;  
03660 
03661         case PRISM2_IOCTL_RESET:
03662                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03663                 else ret = prism2_ioctl_priv_reset(dev, (int *) wrq->u.name);
03664                 break;
03665 
03666 #ifdef PRISM2_USE_WE_TYPE_ADDR
03667         case PRISM2_IOCTL_WDS_ADD:
03668                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03669                 else ret = prism2_wds_add(local, wrq->u.ap_addr.sa_data, 1);
03670                 break;
03671 
03672         case PRISM2_IOCTL_WDS_DEL:
03673                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03674                 else ret = prism2_wds_del(local, wrq->u.ap_addr.sa_data, 1, 0);
03675                 break;
03676 #else /* PRISM2_USE_WE_TYPE_ADDR */
03677         case PRISM2_IOCTL_WDS_ADD:
03678                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03679                 else if (wrq->u.data.pointer) {
03680                         char addrbuf[18];
03681                         if (copy_from_user(addrbuf, wrq->u.data.pointer, 18)) {
03682                                 ret = -EFAULT;
03683                                 break;
03684                         }
03685                         ret = prism2_ioctl_priv_wds(dev, 1, addrbuf);
03686                 }
03687                 break;
03688 
03689         case PRISM2_IOCTL_WDS_DEL:
03690                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03691                 else if (wrq->u.data.pointer) {
03692                         char addrbuf[18];
03693                         if (copy_from_user(addrbuf, wrq->u.data.pointer, 18)) {
03694                                 ret = -EFAULT;
03695                                 break;
03696                         }
03697                         ret = prism2_ioctl_priv_wds(dev, 0, addrbuf);
03698                 }
03699                 break;
03700 #endif /* PRISM2_USE_WE_TYPE_ADDR */
03701 
03702         case PRISM2_IOCTL_SET_RID_WORD:
03703                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03704                 else ret = prism2_ioctl_priv_set_rid_word(dev,
03705                                                           (int *) wrq->u.name);
03706                 break;
03707 
03708 #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
03709         case PRISM2_IOCTL_MACCMD:
03710                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03711                 else ret = ap_mac_cmd_ioctl(local, (int *) wrq->u.name);
03712                 break;
03713 
03714 #ifdef PRISM2_USE_WE_TYPE_ADDR
03715         case PRISM2_IOCTL_ADDMAC:
03716                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03717                 else ret = ap_control_add_mac(&local->ap->mac_restrictions,
03718                                               wrq->u.ap_addr.sa_data);
03719                 break;
03720         case PRISM2_IOCTL_DELMAC:
03721                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03722                 else ret = ap_control_del_mac(&local->ap->mac_restrictions,
03723                                               wrq->u.ap_addr.sa_data);
03724                 break;
03725         case PRISM2_IOCTL_KICKMAC:
03726                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03727                 else ret = ap_control_kick_mac(local->ap, local->dev,
03728                                                wrq->u.ap_addr.sa_data);
03729                 break;
03730 #else /* PRISM2_USE_WE_TYPE_ADDR */
03731         case PRISM2_IOCTL_ADDMAC:
03732                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03733                 else if (wrq->u.data.pointer) {
03734                         char addrbuf[18];
03735                         if (copy_from_user(addrbuf, wrq->u.data.pointer, 18)) {
03736                                 ret = -EFAULT;
03737                                 break;
03738                         }
03739                         ret = ap_mac_ioctl(local, addrbuf, AP_CTRL_MAC_ADD);
03740                 }
03741                 break;
03742 
03743         case PRISM2_IOCTL_DELMAC:
03744                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03745                 else if (wrq->u.data.pointer) {
03746                         char addrbuf[18];
03747                         if (copy_from_user(addrbuf, wrq->u.data.pointer, 18)) {
03748                                 ret = -EFAULT;
03749                                 break;
03750                         }
03751                         ret = ap_mac_ioctl(local, addrbuf, AP_CTRL_MAC_DEL);
03752                 }
03753                 break;
03754 
03755         case PRISM2_IOCTL_KICKMAC:
03756                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03757                 else if (wrq->u.data.pointer) {
03758                         char addrbuf[18];
03759                         if (copy_from_user(addrbuf, wrq->u.data.pointer, 18)) {
03760                                 ret = -EFAULT;
03761                                 break;
03762                         }
03763                         ret = ap_mac_ioctl(local, addrbuf, AP_CTRL_MAC_KICK);
03764                 }
03765                 break;
03766 #endif /* PRISM2_USE_WE_TYPE_ADDR */
03767 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
03768 
03769 
03770                 /* Private ioctls that are not used with iwpriv;
03771                  * in SIOCDEVPRIVATE range */
03772 
03773 #ifdef PRISM2_DOWNLOAD_SUPPORT
03774         case PRISM2_IOCTL_DOWNLOAD:
03775                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03776                 else ret = prism2_ioctl_priv_download(local, &wrq->u.data);
03777                 break;
03778 #endif /* PRISM2_DOWNLOAD_SUPPORT */
03779 
03780         case PRISM2_IOCTL_HOSTAPD:
03781                 if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
03782                 else ret = prism2_ioctl_priv_hostapd(local, &wrq->u.data);
03783                 break;
03784 
03785         default:
03786 #if WIRELESS_EXT > 12
03787                 if (cmd >= SIOCSIWCOMMIT && cmd <= SIOCGIWPOWER) {
03788                         /* unsupport wireless extensions get through here - do
03789                          * not report these to debug log */
03790                         ret = -EOPNOTSUPP;
03791                         break;
03792                 }
03793 #endif /* WIRELESS_EXT > 12 */
03794                 printk(KERN_DEBUG "%s unsupported ioctl(0x%04x)\n",
03795                        dev->name, cmd);
03796                 ret = -EOPNOTSUPP;
03797                 break;
03798         }
03799 
03800         return ret;
03801 }
03802 
03803 #endif /* WIRELESS_EXT */

Generated on Mon Nov 21 15:58:09 2005 for openwifi by  doxygen 1.4.1