2 * This file contains ioctl functions
4 #include <linux/ctype.h>
5 #include <linux/delay.h>
7 #include <linux/if_arp.h>
8 #include <linux/wireless.h>
9 #include <linux/bitops.h>
11 #include <net/ieee80211.h>
12 #include <net/iw_handler.h>
25 * the rates supported by the card
27 static u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] =
28 { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
29 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
33 * @brief Convert mw value to dbm value
35 * @param mw the value of mw
36 * @return the value of dbm
38 static int mw_to_dbm(int mw)
79 * @brief Find the channel frequency power info with specific channel
81 * @param adapter A pointer to wlan_adapter structure
82 * @param band it can be BAND_A, BAND_G or BAND_B
83 * @param channel the channel for looking
84 * @return A pointer to struct chan_freq_power structure or NULL if not find.
86 struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter,
89 struct chan_freq_power *cfp = NULL;
90 struct region_channel *rc;
91 int count = sizeof(adapter->region_channel) /
92 sizeof(adapter->region_channel[0]);
95 for (j = 0; !cfp && (j < count); j++) {
96 rc = &adapter->region_channel[j];
98 if (adapter->enable11d)
99 rc = &adapter->universal_channel[j];
100 if (!rc->valid || !rc->CFP)
102 if (rc->band != band)
104 for (i = 0; i < rc->nrcfp; i++) {
105 if (rc->CFP[i].channel == channel) {
113 lbs_deb_wext("libertas_find_cfp_by_band_and_channel: can't find "
114 "cfp by band %d / channel %d\n", band, channel);
120 * @brief Find the channel frequency power info with specific frequency
122 * @param adapter A pointer to wlan_adapter structure
123 * @param band it can be BAND_A, BAND_G or BAND_B
124 * @param freq the frequency for looking
125 * @return A pointer to struct chan_freq_power structure or NULL if not find.
127 static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
130 struct chan_freq_power *cfp = NULL;
131 struct region_channel *rc;
132 int count = sizeof(adapter->region_channel) /
133 sizeof(adapter->region_channel[0]);
136 for (j = 0; !cfp && (j < count); j++) {
137 rc = &adapter->region_channel[j];
139 if (adapter->enable11d)
140 rc = &adapter->universal_channel[j];
141 if (!rc->valid || !rc->CFP)
143 if (rc->band != band)
145 for (i = 0; i < rc->nrcfp; i++) {
146 if (rc->CFP[i].freq == freq) {
154 lbs_deb_wext("find_cfp_by_band_and_freql: can't find cfp by "
155 "band %d / freq %d\n", band, freq);
160 static int updatecurrentchannel(wlan_private * priv)
165 ** the channel in f/w could be out of sync, get the current channel
167 ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
168 cmd_opt_802_11_rf_channel_get,
169 cmd_option_waitforrsp, 0, NULL);
171 lbs_deb_wext("current channel %d\n",
172 priv->adapter->curbssparams.channel);
177 static int setcurrentchannel(wlan_private * priv, int channel)
179 lbs_deb_wext("set channel %d\n", channel);
182 ** Current channel is not set to adhocchannel requested, set channel
184 return (libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
185 cmd_opt_802_11_rf_channel_set,
186 cmd_option_waitforrsp, 0, &channel));
189 static int changeadhocchannel(wlan_private * priv, int channel)
192 wlan_adapter *adapter = priv->adapter;
194 adapter->adhocchannel = channel;
196 updatecurrentchannel(priv);
198 if (adapter->curbssparams.channel == adapter->adhocchannel) {
199 /* adhocchannel is set to the current channel already */
203 lbs_deb_wext("updating channel from %d to %d\n",
204 adapter->curbssparams.channel, adapter->adhocchannel);
206 setcurrentchannel(priv, adapter->adhocchannel);
208 updatecurrentchannel(priv);
210 if (adapter->curbssparams.channel != adapter->adhocchannel) {
211 lbs_deb_wext("failed to updated channel to %d, channel = %d\n",
212 adapter->adhocchannel, adapter->curbssparams.channel);
217 if (adapter->connect_status == libertas_connected) {
219 struct WLAN_802_11_SSID curadhocssid;
221 lbs_deb_wext("channel changed while in IBSS\n");
223 /* Copy the current ssid */
224 memcpy(&curadhocssid, &adapter->curbssparams.ssid,
225 sizeof(struct WLAN_802_11_SSID));
227 /* Exit Adhoc mode */
228 lbs_deb_wext("in changeadhocchannel(): sending Adhoc stop\n");
229 ret = libertas_stop_adhoc_network(priv);
234 /* Scan for the network, do not save previous results. Stale
235 * scan data will cause us to join a non-existant adhoc network
237 libertas_send_specific_SSID_scan(priv, &curadhocssid, 0);
239 // find out the BSSID that matches the current SSID
240 i = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL,
244 lbs_deb_wext("SSID found at %d in list,"
246 libertas_join_adhoc_network(priv, &adapter->scantable[i]);
248 // else send START command
249 lbs_deb_wext("SSID not found in list, "
250 "creating AdHoc with SSID '%s'\n",
252 libertas_start_adhoc_network(priv, &curadhocssid);
253 } // end of else (START command)
257 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
262 * @brief Set Radio On/OFF
264 * @param priv A pointer to wlan_private structure
265 * @option Radio Option
266 * @return 0 --success, otherwise fail
268 int wlan_radio_ioctl(wlan_private * priv, u8 option)
271 wlan_adapter *adapter = priv->adapter;
273 lbs_deb_enter(LBS_DEB_WEXT);
275 if (adapter->radioon != option) {
276 lbs_deb_wext("switching radio %s\n", option ? "on" : "off");
277 adapter->radioon = option;
279 ret = libertas_prepare_and_send_command(priv,
280 cmd_802_11_radio_control,
282 cmd_option_waitforrsp, 0, NULL);
285 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
292 * @param dest A pointer to Dest Buf
293 * @param src A pointer to Src Buf
294 * @param len The len of Src Buf
295 * @return Number of rates copyed
297 static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
301 for (i = 0; i < len && src[i]; i++, pos++) {
302 if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
311 * @brief Get active data rates
313 * @param adapter A pointer to wlan_adapter structure
314 * @param rate The buf to return the active rates
315 * @return The number of rates
317 static int get_active_data_rates(wlan_adapter * adapter,
322 lbs_deb_enter(LBS_DEB_WEXT);
324 if (adapter->connect_status != libertas_connected) {
325 if (adapter->mode == IW_MODE_INFRA) {
326 lbs_deb_wext("infra\n");
327 k = copyrates(rates, k, libertas_supported_rates,
328 sizeof(libertas_supported_rates));
330 lbs_deb_wext("Adhoc G\n");
331 k = copyrates(rates, k, libertas_adhoc_rates_g,
332 sizeof(libertas_adhoc_rates_g));
335 k = copyrates(rates, 0, adapter->curbssparams.datarates,
336 adapter->curbssparams.numofrates);
339 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", k);
343 static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
344 char *cwrq, char *extra)
347 char comm[6] = { "COMM-" };
348 char mrvl[6] = { "MRVL-" };
351 lbs_deb_enter(LBS_DEB_WEXT);
355 cp = strstr(libertas_driver_version, comm);
356 if (cp == libertas_driver_version) //skip leading "COMM-"
357 cp = libertas_driver_version + strlen(comm);
359 cp = libertas_driver_version;
363 while (cnt < 16 && (*cp != '-')) {
364 *cwrq++ = toupper(*cp++);
369 lbs_deb_leave(LBS_DEB_WEXT);
373 static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
374 struct iw_freq *fwrq, char *extra)
376 wlan_private *priv = dev->priv;
377 wlan_adapter *adapter = priv->adapter;
378 struct chan_freq_power *cfp;
380 lbs_deb_enter(LBS_DEB_WEXT);
382 cfp = libertas_find_cfp_by_band_and_channel(adapter, 0,
383 adapter->curbssparams.channel);
386 if (adapter->curbssparams.channel)
387 lbs_deb_wext("invalid channel %d\n",
388 adapter->curbssparams.channel);
392 fwrq->m = (long)cfp->freq * 100000;
395 lbs_deb_wext("freq %u\n", fwrq->m);
396 lbs_deb_leave(LBS_DEB_WEXT);
400 static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
401 struct sockaddr *awrq, char *extra)
403 wlan_private *priv = dev->priv;
404 wlan_adapter *adapter = priv->adapter;
406 lbs_deb_enter(LBS_DEB_WEXT);
408 if (adapter->connect_status == libertas_connected) {
409 memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
411 memset(awrq->sa_data, 0, ETH_ALEN);
413 awrq->sa_family = ARPHRD_ETHER;
415 lbs_deb_leave(LBS_DEB_WEXT);
419 static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
420 struct iw_point *dwrq, char *extra)
422 wlan_private *priv = dev->priv;
423 wlan_adapter *adapter = priv->adapter;
425 lbs_deb_enter(LBS_DEB_WEXT);
428 * Check the size of the string
431 if (dwrq->length > 16) {
435 mutex_lock(&adapter->lock);
436 memset(adapter->nodename, 0, sizeof(adapter->nodename));
437 memcpy(adapter->nodename, extra, dwrq->length);
438 mutex_unlock(&adapter->lock);
440 lbs_deb_leave(LBS_DEB_WEXT);
444 static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
445 struct iw_point *dwrq, char *extra)
447 wlan_private *priv = dev->priv;
448 wlan_adapter *adapter = priv->adapter;
450 lbs_deb_enter(LBS_DEB_WEXT);
453 * Get the Nick Name saved
456 mutex_lock(&adapter->lock);
457 strncpy(extra, adapter->nodename, 16);
458 mutex_unlock(&adapter->lock);
463 * If none, we may want to get the one that was set
469 dwrq->length = strlen(extra) + 1;
471 lbs_deb_leave(LBS_DEB_WEXT);
475 static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
476 struct iw_param *vwrq, char *extra)
479 wlan_private *priv = dev->priv;
480 wlan_adapter *adapter = priv->adapter;
481 int rthr = vwrq->value;
483 lbs_deb_enter(LBS_DEB_WEXT);
485 if (vwrq->disabled) {
486 adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
488 if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
490 adapter->rtsthsd = rthr;
493 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
494 cmd_act_set, cmd_option_waitforrsp,
495 OID_802_11_RTS_THRESHOLD, &rthr);
497 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
501 static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
502 struct iw_param *vwrq, char *extra)
505 wlan_private *priv = dev->priv;
506 wlan_adapter *adapter = priv->adapter;
508 lbs_deb_enter(LBS_DEB_WEXT);
510 adapter->rtsthsd = 0;
511 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
512 cmd_act_get, cmd_option_waitforrsp,
513 OID_802_11_RTS_THRESHOLD, NULL);
517 vwrq->value = adapter->rtsthsd;
518 vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
519 || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
523 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
527 static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
528 struct iw_param *vwrq, char *extra)
531 int fthr = vwrq->value;
532 wlan_private *priv = dev->priv;
533 wlan_adapter *adapter = priv->adapter;
535 lbs_deb_enter(LBS_DEB_WEXT);
537 if (vwrq->disabled) {
538 adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
540 if (fthr < MRVDRV_FRAG_MIN_VALUE
541 || fthr > MRVDRV_FRAG_MAX_VALUE)
543 adapter->fragthsd = fthr;
546 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
547 cmd_act_set, cmd_option_waitforrsp,
548 OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
550 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
554 static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
555 struct iw_param *vwrq, char *extra)
558 wlan_private *priv = dev->priv;
559 wlan_adapter *adapter = priv->adapter;
561 lbs_deb_enter(LBS_DEB_WEXT);
563 adapter->fragthsd = 0;
564 ret = libertas_prepare_and_send_command(priv,
566 cmd_act_get, cmd_option_waitforrsp,
567 OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
571 vwrq->value = adapter->fragthsd;
572 vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
573 || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
577 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
581 static int wlan_get_mode(struct net_device *dev,
582 struct iw_request_info *info, u32 * uwrq, char *extra)
584 wlan_private *priv = dev->priv;
585 wlan_adapter *adapter = priv->adapter;
587 lbs_deb_enter(LBS_DEB_WEXT);
589 *uwrq = adapter->mode;
591 lbs_deb_leave(LBS_DEB_WEXT);
595 static int wlan_get_txpow(struct net_device *dev,
596 struct iw_request_info *info,
597 struct iw_param *vwrq, char *extra)
600 wlan_private *priv = dev->priv;
601 wlan_adapter *adapter = priv->adapter;
603 lbs_deb_enter(LBS_DEB_WEXT);
605 ret = libertas_prepare_and_send_command(priv,
606 cmd_802_11_rf_tx_power,
607 cmd_act_tx_power_opt_get,
608 cmd_option_waitforrsp, 0, NULL);
613 lbs_deb_wext("tx power level %d dbm\n", adapter->txpowerlevel);
614 vwrq->value = adapter->txpowerlevel;
616 if (adapter->radioon) {
618 vwrq->flags = IW_TXPOW_DBM;
624 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
628 static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
629 struct iw_param *vwrq, char *extra)
632 wlan_private *priv = dev->priv;
633 wlan_adapter *adapter = priv->adapter;
635 lbs_deb_enter(LBS_DEB_WEXT);
637 if (vwrq->flags == IW_RETRY_LIMIT) {
638 /* The MAC has a 4-bit Total_Tx_Count register
639 Total_Tx_Count = 1 + Tx_Retry_Count */
640 #define TX_RETRY_MIN 0
641 #define TX_RETRY_MAX 14
642 if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
645 /* Adding 1 to convert retry count to try count */
646 adapter->txretrycount = vwrq->value + 1;
648 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
650 cmd_option_waitforrsp,
651 OID_802_11_TX_RETRYCOUNT, NULL);
660 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
664 static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
665 struct iw_param *vwrq, char *extra)
667 wlan_private *priv = dev->priv;
668 wlan_adapter *adapter = priv->adapter;
671 lbs_deb_enter(LBS_DEB_WEXT);
673 adapter->txretrycount = 0;
674 ret = libertas_prepare_and_send_command(priv,
676 cmd_act_get, cmd_option_waitforrsp,
677 OID_802_11_TX_RETRYCOUNT, NULL);
683 vwrq->flags = IW_RETRY_LIMIT;
684 /* Subtract 1 to convert try count to retry count */
685 vwrq->value = adapter->txretrycount - 1;
689 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
693 static inline void sort_channels(struct iw_freq *freq, int num)
698 for (i = 0; i < num; i++)
699 for (j = i + 1; j < num; j++)
700 if (freq[i].i > freq[j].i) {
704 freq[i].i = freq[j].i;
705 freq[i].m = freq[j].m;
715 Infra G(12) A(8) B(4) G(12)
716 Adhoc A+B(12) A(8) B(4) B(4)
724 * @brief Get Range Info
726 * @param dev A pointer to net_device structure
727 * @param info A pointer to iw_request_info structure
728 * @param vwrq A pointer to iw_param structure
729 * @param extra A pointer to extra data buf
730 * @return 0 --success, otherwise fail
732 static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
733 struct iw_point *dwrq, char *extra)
736 wlan_private *priv = dev->priv;
737 wlan_adapter *adapter = priv->adapter;
738 struct iw_range *range = (struct iw_range *)extra;
739 struct chan_freq_power *cfp;
740 u8 rates[WLAN_SUPPORTED_RATES];
744 lbs_deb_enter(LBS_DEB_WEXT);
746 dwrq->length = sizeof(struct iw_range);
747 memset(range, 0, sizeof(struct iw_range));
752 memset(rates, 0, sizeof(rates));
753 range->num_bitrates = get_active_data_rates(adapter, rates);
755 for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i];
757 range->bitrate[i] = (rates[i] & 0x7f) * 500000;
759 range->num_bitrates = i;
760 lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
761 range->num_bitrates);
763 range->num_frequency = 0;
764 if (priv->adapter->enable11d &&
765 adapter->connect_status == libertas_connected) {
769 struct parsed_region_chan_11d *parsed_region_chan =
770 &adapter->parsed_region_chan;
772 if (parsed_region_chan == NULL) {
773 lbs_deb_wext("11d: parsed_region_chan is NULL\n");
776 band = parsed_region_chan->band;
777 lbs_deb_wext("band %d, nr_char %d\n", band,
778 parsed_region_chan->nr_chan);
780 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
781 && (i < parsed_region_chan->nr_chan); i++) {
782 chan_no = parsed_region_chan->chanpwr[i].chan;
783 lbs_deb_wext("chan_no %d\n", chan_no);
784 range->freq[range->num_frequency].i = (long)chan_no;
785 range->freq[range->num_frequency].m =
786 (long)libertas_chan_2_freq(chan_no, band) * 100000;
787 range->freq[range->num_frequency].e = 1;
788 range->num_frequency++;
793 for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
794 && (j < sizeof(adapter->region_channel)
795 / sizeof(adapter->region_channel[0])); j++) {
796 cfp = adapter->region_channel[j].CFP;
797 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
798 && adapter->region_channel[j].valid
800 && (i < adapter->region_channel[j].nrcfp); i++) {
801 range->freq[range->num_frequency].i =
803 range->freq[range->num_frequency].m =
804 (long)cfp->freq * 100000;
805 range->freq[range->num_frequency].e = 1;
807 range->num_frequency++;
812 lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
813 IW_MAX_FREQUENCIES, range->num_frequency);
815 range->num_channels = range->num_frequency;
817 sort_channels(&range->freq[0], range->num_frequency);
820 * Set an indication of the max TCP throughput in bit/s that we can
821 * expect using this interface
824 range->throughput = 5000 * 1000;
826 range->throughput = 1500 * 1000;
828 range->min_rts = MRVDRV_RTS_MIN_VALUE;
829 range->max_rts = MRVDRV_RTS_MAX_VALUE;
830 range->min_frag = MRVDRV_FRAG_MIN_VALUE;
831 range->max_frag = MRVDRV_FRAG_MAX_VALUE;
833 range->encoding_size[0] = 5;
834 range->encoding_size[1] = 13;
835 range->num_encoding_sizes = 2;
836 range->max_encoding_tokens = 4;
838 range->min_pmp = 1000000;
839 range->max_pmp = 120000000;
840 range->min_pmt = 1000;
841 range->max_pmt = 1000000;
842 range->pmp_flags = IW_POWER_PERIOD;
843 range->pmt_flags = IW_POWER_TIMEOUT;
844 range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
847 * Minimum version we recommend
849 range->we_version_source = 15;
852 * Version we are compiled with
854 range->we_version_compiled = WIRELESS_EXT;
856 range->retry_capa = IW_RETRY_LIMIT;
857 range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
859 range->min_retry = TX_RETRY_MIN;
860 range->max_retry = TX_RETRY_MAX;
863 * Set the qual, level and noise range values
865 range->max_qual.qual = 100;
866 range->max_qual.level = 0;
867 range->max_qual.noise = 0;
868 range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
870 range->avg_qual.qual = 70;
871 /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
872 range->avg_qual.level = 0;
873 range->avg_qual.noise = 0;
874 range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
876 range->sensitivity = 0;
879 * Setup the supported power level ranges
881 memset(range->txpower, 0, sizeof(range->txpower));
882 range->txpower[0] = 5;
883 range->txpower[1] = 7;
884 range->txpower[2] = 9;
885 range->txpower[3] = 11;
886 range->txpower[4] = 13;
887 range->txpower[5] = 15;
888 range->txpower[6] = 17;
889 range->txpower[7] = 19;
891 range->num_txpower = 8;
892 range->txpower_capa = IW_TXPOW_DBM;
893 range->txpower_capa |= IW_TXPOW_RANGE;
895 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
896 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
897 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
898 range->event_capa[1] = IW_EVENT_CAPA_K_1;
900 if (adapter->fwcapinfo & FW_CAPINFO_WPA) {
901 range->enc_capa = IW_ENC_CAPA_WPA
903 | IW_ENC_CAPA_CIPHER_TKIP
904 | IW_ENC_CAPA_CIPHER_CCMP;
908 lbs_deb_leave(LBS_DEB_WEXT);
912 static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
913 struct iw_param *vwrq, char *extra)
915 wlan_private *priv = dev->priv;
916 wlan_adapter *adapter = priv->adapter;
918 lbs_deb_enter(LBS_DEB_WEXT);
920 /* PS is currently supported only in Infrastructure mode
921 * Remove this check if it is to be supported in IBSS mode also
924 if (vwrq->disabled) {
925 adapter->psmode = wlan802_11powermodecam;
926 if (adapter->psstate != PS_STATE_FULL_POWER) {
927 libertas_ps_wakeup(priv, cmd_option_waitforrsp);
933 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
935 "setting power timeout is not supported\n");
937 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
938 lbs_deb_wext("setting power period not supported\n");
942 if (adapter->psmode != wlan802_11powermodecam) {
946 adapter->psmode = wlan802_11powermodemax_psp;
948 if (adapter->connect_status == libertas_connected) {
949 libertas_ps_sleep(priv, cmd_option_waitforrsp);
952 lbs_deb_leave(LBS_DEB_WEXT);
956 static int wlan_get_power(struct net_device *dev, struct iw_request_info *info,
957 struct iw_param *vwrq, char *extra)
959 wlan_private *priv = dev->priv;
960 wlan_adapter *adapter = priv->adapter;
963 lbs_deb_enter(LBS_DEB_WEXT);
965 mode = adapter->psmode;
967 if ((vwrq->disabled = (mode == wlan802_11powermodecam))
968 || adapter->connect_status == libertas_disconnected)
976 lbs_deb_leave(LBS_DEB_WEXT);
981 * iwpriv settable callbacks
984 static const iw_handler wlan_private_handler[] = {
985 NULL, /* SIOCIWFIRSTPRIV */
988 static const struct iw_priv_args wlan_private_args[] = {
990 * { cmd, set_args, get_args, name }
992 /* Using iwpriv sub-command feature */
994 WLAN_SETONEINT_GETNONE, /* IOCTL: 24 */
995 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1000 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1004 WLAN_SUBCMD_MESH_SET_TTL,
1005 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1009 WLAN_SETNONE_GETONEINT,
1011 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1016 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1019 WLAN_SUBCMD_FWT_CLEANUP,
1021 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1024 WLAN_SUBCMD_FWT_TIME,
1026 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1029 WLAN_SUBCMD_MESH_GET_TTL,
1031 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1034 WLAN_SETNONE_GETNONE,
1039 WLAN_SUBCMD_FWT_RESET,
1044 WLAN_SUBCMD_BT_RESET,
1049 WLAN_SET128CHAR_GET128CHAR,
1050 IW_PRIV_TYPE_CHAR | 128,
1051 IW_PRIV_TYPE_CHAR | 128,
1056 IW_PRIV_TYPE_CHAR | 128,
1057 IW_PRIV_TYPE_CHAR | 128,
1061 IW_PRIV_TYPE_CHAR | 128,
1062 IW_PRIV_TYPE_CHAR | 128,
1065 WLAN_SUBCMD_BT_LIST,
1066 IW_PRIV_TYPE_CHAR | 128,
1067 IW_PRIV_TYPE_CHAR | 128,
1069 /* FWT Management */
1071 WLAN_SUBCMD_FWT_ADD,
1072 IW_PRIV_TYPE_CHAR | 128,
1073 IW_PRIV_TYPE_CHAR | 128,
1076 WLAN_SUBCMD_FWT_DEL,
1077 IW_PRIV_TYPE_CHAR | 128,
1078 IW_PRIV_TYPE_CHAR | 128,
1081 WLAN_SUBCMD_FWT_LOOKUP,
1082 IW_PRIV_TYPE_CHAR | 128,
1083 IW_PRIV_TYPE_CHAR | 128,
1086 WLAN_SUBCMD_FWT_LIST_NEIGHBOR,
1087 IW_PRIV_TYPE_CHAR | 128,
1088 IW_PRIV_TYPE_CHAR | 128,
1091 WLAN_SUBCMD_FWT_LIST,
1092 IW_PRIV_TYPE_CHAR | 128,
1093 IW_PRIV_TYPE_CHAR | 128,
1096 WLAN_SUBCMD_FWT_LIST_ROUTE,
1097 IW_PRIV_TYPE_CHAR | 128,
1098 IW_PRIV_TYPE_CHAR | 128,
1101 WLAN_SET_GET_SIXTEEN_INT,
1102 IW_PRIV_TYPE_INT | 16,
1103 IW_PRIV_TYPE_INT | 16,
1107 IW_PRIV_TYPE_INT | 16,
1108 IW_PRIV_TYPE_INT | 16,
1112 static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
1122 wlan_private *priv = dev->priv;
1123 wlan_adapter *adapter = priv->adapter;
1127 int stats_valid = 0;
1131 lbs_deb_enter(LBS_DEB_WEXT);
1133 priv->wstats.status = adapter->mode;
1135 /* If we're not associated, all quality values are meaningless */
1136 if (adapter->connect_status != libertas_connected)
1139 /* Quality by RSSI */
1140 priv->wstats.qual.level =
1141 CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
1142 adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
1144 if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
1145 priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
1147 priv->wstats.qual.noise =
1148 CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
1151 lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
1152 lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise);
1154 rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
1156 rssi_qual = rssi * POOR / 10;
1158 rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
1160 rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
1162 rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
1165 rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
1167 quality = rssi_qual;
1169 /* Quality by TX errors */
1170 priv->wstats.discard.retries = priv->stats.tx_errors;
1172 tx_retries = adapter->logmsg.retry;
1174 if (tx_retries > 75)
1175 tx_qual = (90 - tx_retries) * POOR / 15;
1176 else if (tx_retries > 70)
1177 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
1178 else if (tx_retries > 65)
1179 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
1180 else if (tx_retries > 50)
1181 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
1184 tx_qual = (50 - tx_retries) *
1185 (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
1186 quality = min(quality, tx_qual);
1188 priv->wstats.discard.code = adapter->logmsg.wepundecryptable;
1189 priv->wstats.discard.fragment = adapter->logmsg.fcserror;
1190 priv->wstats.discard.retries = tx_retries;
1191 priv->wstats.discard.misc = adapter->logmsg.ackfailure;
1193 /* Calculate quality */
1194 priv->wstats.qual.qual = max(quality, (u32)100);
1195 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
1198 /* update stats asynchronously for future calls */
1199 libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
1201 libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
1205 priv->wstats.miss.beacon = 0;
1206 priv->wstats.discard.retries = 0;
1207 priv->wstats.qual.qual = 0;
1208 priv->wstats.qual.level = 0;
1209 priv->wstats.qual.noise = 0;
1210 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
1211 priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
1212 IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
1215 lbs_deb_leave(LBS_DEB_WEXT);
1216 return &priv->wstats;
1221 static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
1222 struct iw_freq *fwrq, char *extra)
1225 wlan_private *priv = dev->priv;
1226 wlan_adapter *adapter = priv->adapter;
1227 int rc = -EINPROGRESS; /* Call commit handler */
1228 struct chan_freq_power *cfp;
1230 lbs_deb_enter(LBS_DEB_WEXT);
1233 * If setting by frequency, convert to a channel
1237 long f = fwrq->m / 100000;
1240 cfp = find_cfp_by_band_and_freq(adapter, 0, f);
1242 lbs_deb_wext("invalid freq %ld\n", f);
1246 c = (int)cfp->channel;
1256 * Setting by channel number
1258 if (fwrq->m > 1000 || fwrq->e > 0) {
1261 int channel = fwrq->m;
1263 cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, channel);
1267 if (adapter->mode == IW_MODE_ADHOC) {
1268 rc = changeadhocchannel(priv, channel);
1269 /* If station is WEP enabled, send the
1270 * command to set WEP in firmware
1272 if (adapter->secinfo.wep_enabled) {
1273 lbs_deb_wext("set_freq: WEP enabled\n");
1274 ret = libertas_prepare_and_send_command(priv,
1277 cmd_option_waitforrsp,
1286 adapter->currentpacketfilter |=
1287 cmd_act_mac_wep_enable;
1289 libertas_set_mac_packet_filter(priv);
1298 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", rc);
1303 * @brief use index to get the data rate
1305 * @param index The index of data rate
1306 * @return data rate or 0
1308 u32 libertas_index_to_data_rate(u8 index)
1310 if (index >= sizeof(libertas_wlan_data_rates))
1313 return libertas_wlan_data_rates[index];
1317 * @brief use rate to get the index
1319 * @param rate data rate
1320 * @return index or 0
1322 u8 libertas_data_rate_to_index(u32 rate)
1327 if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
1328 sizeof(libertas_wlan_data_rates))))
1329 return (ptr - libertas_wlan_data_rates);
1334 static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
1335 struct iw_param *vwrq, char *extra)
1337 wlan_private *priv = dev->priv;
1338 wlan_adapter *adapter = priv->adapter;
1342 u8 rates[WLAN_SUPPORTED_RATES];
1345 lbs_deb_enter(LBS_DEB_WEXT);
1347 lbs_deb_wext("vwrq->value %d\n", vwrq->value);
1349 if (vwrq->value == -1) {
1350 action = cmd_act_set_tx_auto; // Auto
1351 adapter->is_datarate_auto = 1;
1352 adapter->datarate = 0;
1354 if (vwrq->value % 100000) {
1358 data_rate = vwrq->value / 500000;
1360 memset(rates, 0, sizeof(rates));
1361 get_active_data_rates(adapter, rates);
1364 lbs_deb_wext("rate=0x%X, wanted data_rate 0x%X\n", *rate,
1366 if ((*rate & 0x7f) == (data_rate & 0x7f))
1371 lbs_pr_alert("fixed data rate 0x%X out "
1372 "of range\n", data_rate);
1376 adapter->datarate = data_rate;
1377 action = cmd_act_set_tx_fix_rate;
1378 adapter->is_datarate_auto = 0;
1381 ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
1382 action, cmd_option_waitforrsp, 0, NULL);
1384 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1388 static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
1389 struct iw_param *vwrq, char *extra)
1391 wlan_private *priv = dev->priv;
1392 wlan_adapter *adapter = priv->adapter;
1394 lbs_deb_enter(LBS_DEB_WEXT);
1396 if (adapter->is_datarate_auto) {
1402 vwrq->value = adapter->datarate * 500000;
1404 lbs_deb_leave(LBS_DEB_WEXT);
1408 static int wlan_set_mode(struct net_device *dev,
1409 struct iw_request_info *info, u32 * uwrq, char *extra)
1412 wlan_private *priv = dev->priv;
1413 wlan_adapter *adapter = priv->adapter;
1414 struct assoc_request * assoc_req;
1416 lbs_deb_enter(LBS_DEB_WEXT);
1418 if ( (*uwrq != IW_MODE_ADHOC)
1419 && (*uwrq != IW_MODE_INFRA)
1420 && (*uwrq != IW_MODE_AUTO)) {
1421 lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq);
1426 mutex_lock(&adapter->lock);
1427 assoc_req = wlan_get_association_request(adapter);
1430 wlan_cancel_association_work(priv);
1432 assoc_req->mode = *uwrq;
1433 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
1434 wlan_postpone_association_work(priv);
1435 lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
1437 mutex_unlock(&adapter->lock);
1440 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1446 * @brief Get Encryption key
1448 * @param dev A pointer to net_device structure
1449 * @param info A pointer to iw_request_info structure
1450 * @param vwrq A pointer to iw_param structure
1451 * @param extra A pointer to extra data buf
1452 * @return 0 --success, otherwise fail
1454 static int wlan_get_encode(struct net_device *dev,
1455 struct iw_request_info *info,
1456 struct iw_point *dwrq, u8 * extra)
1458 wlan_private *priv = dev->priv;
1459 wlan_adapter *adapter = priv->adapter;
1460 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1462 lbs_deb_enter(LBS_DEB_WEXT);
1464 lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
1465 dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
1469 /* Authentication method */
1470 switch (adapter->secinfo.auth_mode) {
1471 case IW_AUTH_ALG_OPEN_SYSTEM:
1472 dwrq->flags = IW_ENCODE_OPEN;
1475 case IW_AUTH_ALG_SHARED_KEY:
1476 case IW_AUTH_ALG_LEAP:
1477 dwrq->flags = IW_ENCODE_RESTRICTED;
1480 dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1484 if ( adapter->secinfo.wep_enabled
1485 || adapter->secinfo.WPAenabled
1486 || adapter->secinfo.WPA2enabled) {
1487 dwrq->flags &= ~IW_ENCODE_DISABLED;
1489 dwrq->flags |= IW_ENCODE_DISABLED;
1492 memset(extra, 0, 16);
1494 mutex_lock(&adapter->lock);
1496 /* Default to returning current transmit key */
1498 index = adapter->wep_tx_keyidx;
1500 if ((adapter->wep_keys[index].len) && adapter->secinfo.wep_enabled) {
1501 memcpy(extra, adapter->wep_keys[index].key,
1502 adapter->wep_keys[index].len);
1503 dwrq->length = adapter->wep_keys[index].len;
1505 dwrq->flags |= (index + 1);
1506 /* Return WEP enabled */
1507 dwrq->flags &= ~IW_ENCODE_DISABLED;
1508 } else if ((adapter->secinfo.WPAenabled)
1509 || (adapter->secinfo.WPA2enabled)) {
1510 /* return WPA enabled */
1511 dwrq->flags &= ~IW_ENCODE_DISABLED;
1513 dwrq->flags |= IW_ENCODE_DISABLED;
1516 mutex_unlock(&adapter->lock);
1518 dwrq->flags |= IW_ENCODE_NOKEY;
1520 lbs_deb_wext("key: " MAC_FMT ", keylen %d\n",
1521 extra[0], extra[1], extra[2],
1522 extra[3], extra[4], extra[5], dwrq->length);
1524 lbs_deb_wext("return flags 0x%x\n", dwrq->flags);
1526 lbs_deb_leave(LBS_DEB_WEXT);
1531 * @brief Set Encryption key (internal)
1533 * @param priv A pointer to private card structure
1534 * @param key_material A pointer to key material
1535 * @param key_length length of key material
1536 * @param index key index to set
1537 * @param set_tx_key Force set TX key (1 = yes, 0 = no)
1538 * @return 0 --success, otherwise fail
1540 static int wlan_set_wep_key(struct assoc_request *assoc_req,
1541 const char *key_material,
1547 struct WLAN_802_11_KEY *pkey;
1549 lbs_deb_enter(LBS_DEB_WEXT);
1551 /* Paranoid validation of key index */
1557 /* validate max key length */
1558 if (key_length > KEY_LEN_WEP_104) {
1563 pkey = &assoc_req->wep_keys[index];
1565 if (key_length > 0) {
1566 memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
1567 pkey->type = KEY_TYPE_ID_WEP;
1569 /* Standardize the key length */
1570 pkey->len = (key_length > KEY_LEN_WEP_40) ?
1571 KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
1572 memcpy(pkey->key, key_material, key_length);
1576 /* Ensure the chosen key is valid */
1578 lbs_deb_wext("key not set, so cannot enable it\n");
1582 assoc_req->wep_tx_keyidx = index;
1585 assoc_req->secinfo.wep_enabled = 1;
1588 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1592 static int validate_key_index(u16 def_index, u16 raw_index,
1593 u16 *out_index, u16 *is_default)
1595 if (!out_index || !is_default)
1598 /* Verify index if present, otherwise use default TX key index */
1599 if (raw_index > 0) {
1602 *out_index = raw_index - 1;
1604 *out_index = def_index;
1610 static void disable_wep(struct assoc_request *assoc_req)
1614 /* Set Open System auth mode */
1615 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1617 /* Clear WEP keys and mark WEP as disabled */
1618 assoc_req->secinfo.wep_enabled = 0;
1619 for (i = 0; i < 4; i++)
1620 assoc_req->wep_keys[i].len = 0;
1622 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1623 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1627 * @brief Set Encryption key
1629 * @param dev A pointer to net_device structure
1630 * @param info A pointer to iw_request_info structure
1631 * @param vwrq A pointer to iw_param structure
1632 * @param extra A pointer to extra data buf
1633 * @return 0 --success, otherwise fail
1635 static int wlan_set_encode(struct net_device *dev,
1636 struct iw_request_info *info,
1637 struct iw_point *dwrq, char *extra)
1640 wlan_private *priv = dev->priv;
1641 wlan_adapter *adapter = priv->adapter;
1642 struct assoc_request * assoc_req;
1643 u16 is_default = 0, index = 0, set_tx_key = 0;
1645 lbs_deb_enter(LBS_DEB_WEXT);
1647 mutex_lock(&adapter->lock);
1648 assoc_req = wlan_get_association_request(adapter);
1654 if (dwrq->flags & IW_ENCODE_DISABLED) {
1655 disable_wep (assoc_req);
1659 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1660 (dwrq->flags & IW_ENCODE_INDEX),
1661 &index, &is_default);
1667 /* If WEP isn't enabled, or if there is no key data but a valid
1668 * index, set the TX key.
1670 if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
1673 ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
1678 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1680 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1682 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
1683 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
1684 } else if (dwrq->flags & IW_ENCODE_OPEN) {
1685 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1690 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1691 wlan_postpone_association_work(priv);
1693 wlan_cancel_association_work(priv);
1695 mutex_unlock(&adapter->lock);
1697 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1702 * @brief Get Extended Encryption key (WPA/802.1x and WEP)
1704 * @param dev A pointer to net_device structure
1705 * @param info A pointer to iw_request_info structure
1706 * @param vwrq A pointer to iw_param structure
1707 * @param extra A pointer to extra data buf
1708 * @return 0 on success, otherwise failure
1710 static int wlan_get_encodeext(struct net_device *dev,
1711 struct iw_request_info *info,
1712 struct iw_point *dwrq,
1716 wlan_private *priv = dev->priv;
1717 wlan_adapter *adapter = priv->adapter;
1718 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1719 int index, max_key_len;
1721 lbs_deb_enter(LBS_DEB_WEXT);
1723 max_key_len = dwrq->length - sizeof(*ext);
1724 if (max_key_len < 0)
1727 index = dwrq->flags & IW_ENCODE_INDEX;
1729 if (index < 1 || index > 4)
1733 index = adapter->wep_tx_keyidx;
1736 if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
1737 ext->alg != IW_ENCODE_ALG_WEP) {
1738 if (index != 0 || adapter->mode != IW_MODE_INFRA)
1742 dwrq->flags = index + 1;
1743 memset(ext, 0, sizeof(*ext));
1745 if ( !adapter->secinfo.wep_enabled
1746 && !adapter->secinfo.WPAenabled
1747 && !adapter->secinfo.WPA2enabled) {
1748 ext->alg = IW_ENCODE_ALG_NONE;
1750 dwrq->flags |= IW_ENCODE_DISABLED;
1754 if ( adapter->secinfo.wep_enabled
1755 && !adapter->secinfo.WPAenabled
1756 && !adapter->secinfo.WPA2enabled) {
1757 ext->alg = IW_ENCODE_ALG_WEP;
1758 ext->key_len = adapter->wep_keys[index].len;
1759 key = &adapter->wep_keys[index].key[0];
1760 } else if ( !adapter->secinfo.wep_enabled
1761 && (adapter->secinfo.WPAenabled ||
1762 adapter->secinfo.WPA2enabled)) {
1764 ext->alg = IW_ENCODE_ALG_TKIP;
1770 if (ext->key_len > max_key_len) {
1776 memcpy(ext->key, key, ext->key_len);
1778 dwrq->flags |= IW_ENCODE_NOKEY;
1779 dwrq->flags |= IW_ENCODE_ENABLED;
1784 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1789 * @brief Set Encryption key Extended (WPA/802.1x and WEP)
1791 * @param dev A pointer to net_device structure
1792 * @param info A pointer to iw_request_info structure
1793 * @param vwrq A pointer to iw_param structure
1794 * @param extra A pointer to extra data buf
1795 * @return 0 --success, otherwise fail
1797 static int wlan_set_encodeext(struct net_device *dev,
1798 struct iw_request_info *info,
1799 struct iw_point *dwrq,
1803 wlan_private *priv = dev->priv;
1804 wlan_adapter *adapter = priv->adapter;
1805 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1807 struct assoc_request * assoc_req;
1809 lbs_deb_enter(LBS_DEB_WEXT);
1811 mutex_lock(&adapter->lock);
1812 assoc_req = wlan_get_association_request(adapter);
1818 if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
1819 disable_wep (assoc_req);
1820 } else if (alg == IW_ENCODE_ALG_WEP) {
1821 u16 is_default = 0, index, set_tx_key = 0;
1823 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1824 (dwrq->flags & IW_ENCODE_INDEX),
1825 &index, &is_default);
1829 /* If WEP isn't enabled, or if there is no key data but a valid
1830 * index, or if the set-TX-key flag was passed, set the TX key.
1832 if ( !assoc_req->secinfo.wep_enabled
1833 || (dwrq->length == 0 && !is_default)
1834 || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
1837 /* Copy key to driver */
1838 ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
1843 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
1844 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
1845 } else if (dwrq->flags & IW_ENCODE_OPEN) {
1846 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1849 /* Mark the various WEP bits as modified */
1850 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1852 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1854 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1856 } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
1857 struct WLAN_802_11_KEY * pkey;
1859 /* validate key length */
1860 if (((alg == IW_ENCODE_ALG_TKIP)
1861 && (ext->key_len != KEY_LEN_WPA_TKIP))
1862 || ((alg == IW_ENCODE_ALG_CCMP)
1863 && (ext->key_len != KEY_LEN_WPA_AES))) {
1864 lbs_deb_wext("invalid size %d for key of alg"
1872 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
1873 pkey = &assoc_req->wpa_mcast_key;
1875 pkey = &assoc_req->wpa_unicast_key;
1877 memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
1878 memcpy(pkey->key, ext->key, ext->key_len);
1879 pkey->len = ext->key_len;
1880 pkey->flags = KEY_INFO_WPA_ENABLED;
1882 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1883 pkey->flags |= KEY_INFO_WPA_MCAST;
1884 set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1886 pkey->flags |= KEY_INFO_WPA_UNICAST;
1887 set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1890 if (alg == IW_ENCODE_ALG_TKIP)
1891 pkey->type = KEY_TYPE_ID_TKIP;
1892 else if (alg == IW_ENCODE_ALG_CCMP)
1893 pkey->type = KEY_TYPE_ID_AES;
1895 /* If WPA isn't enabled yet, do that now */
1896 if ( assoc_req->secinfo.WPAenabled == 0
1897 && assoc_req->secinfo.WPA2enabled == 0) {
1898 assoc_req->secinfo.WPAenabled = 1;
1899 assoc_req->secinfo.WPA2enabled = 1;
1900 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1903 disable_wep (assoc_req);
1908 wlan_postpone_association_work(priv);
1910 wlan_cancel_association_work(priv);
1912 mutex_unlock(&adapter->lock);
1914 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1919 static int wlan_set_genie(struct net_device *dev,
1920 struct iw_request_info *info,
1921 struct iw_point *dwrq,
1924 wlan_private *priv = dev->priv;
1925 wlan_adapter *adapter = priv->adapter;
1927 struct assoc_request * assoc_req;
1929 lbs_deb_enter(LBS_DEB_WEXT);
1931 mutex_lock(&adapter->lock);
1932 assoc_req = wlan_get_association_request(adapter);
1938 if (dwrq->length > MAX_WPA_IE_LEN ||
1939 (dwrq->length && extra == NULL)) {
1945 memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
1946 assoc_req->wpa_ie_len = dwrq->length;
1948 memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
1949 assoc_req->wpa_ie_len = 0;
1954 set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
1955 wlan_postpone_association_work(priv);
1957 wlan_cancel_association_work(priv);
1959 mutex_unlock(&adapter->lock);
1961 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1965 static int wlan_get_genie(struct net_device *dev,
1966 struct iw_request_info *info,
1967 struct iw_point *dwrq,
1971 wlan_private *priv = dev->priv;
1972 wlan_adapter *adapter = priv->adapter;
1974 lbs_deb_enter(LBS_DEB_WEXT);
1976 if (adapter->wpa_ie_len == 0) {
1981 if (dwrq->length < adapter->wpa_ie_len) {
1986 dwrq->length = adapter->wpa_ie_len;
1987 memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
1990 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1995 static int wlan_set_auth(struct net_device *dev,
1996 struct iw_request_info *info,
1997 struct iw_param *dwrq,
2000 wlan_private *priv = dev->priv;
2001 wlan_adapter *adapter = priv->adapter;
2002 struct assoc_request * assoc_req;
2006 lbs_deb_enter(LBS_DEB_WEXT);
2008 mutex_lock(&adapter->lock);
2009 assoc_req = wlan_get_association_request(adapter);
2015 switch (dwrq->flags & IW_AUTH_INDEX) {
2016 case IW_AUTH_TKIP_COUNTERMEASURES:
2017 case IW_AUTH_CIPHER_PAIRWISE:
2018 case IW_AUTH_CIPHER_GROUP:
2019 case IW_AUTH_KEY_MGMT:
2021 * libertas does not use these parameters
2025 case IW_AUTH_WPA_VERSION:
2026 if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
2027 assoc_req->secinfo.WPAenabled = 0;
2028 assoc_req->secinfo.WPA2enabled = 0;
2030 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
2031 assoc_req->secinfo.WPAenabled = 1;
2032 assoc_req->secinfo.wep_enabled = 0;
2033 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
2035 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
2036 assoc_req->secinfo.WPA2enabled = 1;
2037 assoc_req->secinfo.wep_enabled = 0;
2038 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
2043 case IW_AUTH_DROP_UNENCRYPTED:
2045 adapter->currentpacketfilter |=
2046 cmd_act_mac_strict_protection_enable;
2048 adapter->currentpacketfilter &=
2049 ~cmd_act_mac_strict_protection_enable;
2054 case IW_AUTH_80211_AUTH_ALG:
2055 if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
2056 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
2057 } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
2058 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
2059 } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
2060 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;
2067 case IW_AUTH_WPA_ENABLED:
2069 if (!assoc_req->secinfo.WPAenabled &&
2070 !assoc_req->secinfo.WPA2enabled) {
2071 assoc_req->secinfo.WPAenabled = 1;
2072 assoc_req->secinfo.WPA2enabled = 1;
2073 assoc_req->secinfo.wep_enabled = 0;
2074 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
2077 assoc_req->secinfo.WPAenabled = 0;
2078 assoc_req->secinfo.WPA2enabled = 0;
2091 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
2092 wlan_postpone_association_work(priv);
2093 } else if (ret != -EOPNOTSUPP) {
2094 wlan_cancel_association_work(priv);
2096 mutex_unlock(&adapter->lock);
2098 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2102 static int wlan_get_auth(struct net_device *dev,
2103 struct iw_request_info *info,
2104 struct iw_param *dwrq,
2108 wlan_private *priv = dev->priv;
2109 wlan_adapter *adapter = priv->adapter;
2111 lbs_deb_enter(LBS_DEB_WEXT);
2113 switch (dwrq->flags & IW_AUTH_INDEX) {
2114 case IW_AUTH_WPA_VERSION:
2116 if (adapter->secinfo.WPAenabled)
2117 dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
2118 if (adapter->secinfo.WPA2enabled)
2119 dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
2121 dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
2124 case IW_AUTH_DROP_UNENCRYPTED:
2126 if (adapter->currentpacketfilter &
2127 cmd_act_mac_strict_protection_enable)
2131 case IW_AUTH_80211_AUTH_ALG:
2132 dwrq->value = adapter->secinfo.auth_mode;
2135 case IW_AUTH_WPA_ENABLED:
2136 if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
2144 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2149 static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
2150 struct iw_param *vwrq, char *extra)
2153 wlan_private *priv = dev->priv;
2154 wlan_adapter *adapter = priv->adapter;
2158 lbs_deb_enter(LBS_DEB_WEXT);
2160 if (vwrq->disabled) {
2161 wlan_radio_ioctl(priv, RADIO_OFF);
2165 adapter->preamble = cmd_type_auto_preamble;
2167 wlan_radio_ioctl(priv, RADIO_ON);
2169 if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
2170 dbm = (u16) mw_to_dbm(vwrq->value);
2172 dbm = (u16) vwrq->value;
2174 /* auto tx power control */
2176 if (vwrq->fixed == 0)
2179 lbs_deb_wext("txpower set %d dbm\n", dbm);
2181 ret = libertas_prepare_and_send_command(priv,
2182 cmd_802_11_rf_tx_power,
2183 cmd_act_tx_power_opt_set_low,
2184 cmd_option_waitforrsp, 0, (void *)&dbm);
2186 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2190 static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
2191 struct iw_point *dwrq, char *extra)
2193 wlan_private *priv = dev->priv;
2194 wlan_adapter *adapter = priv->adapter;
2196 lbs_deb_enter(LBS_DEB_WEXT);
2199 * Note : if dwrq->flags != 0, we should get the relevant SSID from
2204 * Get the current SSID
2206 if (adapter->connect_status == libertas_connected) {
2207 memcpy(extra, adapter->curbssparams.ssid.ssid,
2208 adapter->curbssparams.ssid.ssidlength);
2209 extra[adapter->curbssparams.ssid.ssidlength] = '\0';
2211 memset(extra, 0, 32);
2212 extra[adapter->curbssparams.ssid.ssidlength] = '\0';
2215 * If none, we may want to get the one that was set
2218 /* To make the driver backward compatible with WPA supplicant v0.2.4 */
2219 if (dwrq->length == 32) /* check with WPA supplicant buffer size */
2220 dwrq->length = min_t(size_t, adapter->curbssparams.ssid.ssidlength,
2223 dwrq->length = adapter->curbssparams.ssid.ssidlength + 1;
2225 dwrq->flags = 1; /* active */
2227 lbs_deb_leave(LBS_DEB_WEXT);
2231 static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
2232 struct iw_point *dwrq, char *extra)
2234 wlan_private *priv = dev->priv;
2235 wlan_adapter *adapter = priv->adapter;
2237 struct WLAN_802_11_SSID ssid;
2238 struct assoc_request * assoc_req;
2239 int ssid_len = dwrq->length;
2241 lbs_deb_enter(LBS_DEB_WEXT);
2244 * WE-20 and earlier NULL pad the end of the SSID and increment
2245 * SSID length so it can be used like a string. WE-21 and later don't,
2246 * but some userspace tools aren't able to cope with the change.
2248 if ((ssid_len > 0) && (extra[ssid_len - 1] == '\0'))
2251 /* Check the size of the string */
2252 if (ssid_len > IW_ESSID_MAX_SIZE) {
2257 memset(&ssid, 0, sizeof(struct WLAN_802_11_SSID));
2259 if (!dwrq->flags || !ssid_len) {
2260 /* "any" SSID requested; leave SSID blank */
2262 /* Specific SSID requested */
2263 memcpy(&ssid.ssid, extra, ssid_len);
2264 ssid.ssidlength = ssid_len;
2267 lbs_deb_wext("requested new SSID '%s'\n",
2268 (ssid.ssidlength > 0) ? (char *)ssid.ssid : "any");
2271 mutex_lock(&adapter->lock);
2273 /* Get or create the current association request */
2274 assoc_req = wlan_get_association_request(adapter);
2278 /* Copy the SSID to the association request */
2279 memcpy(&assoc_req->ssid, &ssid, sizeof(struct WLAN_802_11_SSID));
2280 set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
2281 wlan_postpone_association_work(priv);
2285 /* Cancel the association request if there was an error */
2287 wlan_cancel_association_work(priv);
2290 mutex_unlock(&adapter->lock);
2292 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2297 * @brief Connect to the AP or Ad-hoc Network with specific bssid
2299 * @param dev A pointer to net_device structure
2300 * @param info A pointer to iw_request_info structure
2301 * @param awrq A pointer to iw_param structure
2302 * @param extra A pointer to extra data buf
2303 * @return 0 --success, otherwise fail
2305 static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
2306 struct sockaddr *awrq, char *extra)
2308 wlan_private *priv = dev->priv;
2309 wlan_adapter *adapter = priv->adapter;
2310 struct assoc_request * assoc_req;
2313 lbs_deb_enter(LBS_DEB_WEXT);
2315 if (awrq->sa_family != ARPHRD_ETHER)
2318 lbs_deb_wext("ASSOC: WAP: sa_data " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
2320 mutex_lock(&adapter->lock);
2322 /* Get or create the current association request */
2323 assoc_req = wlan_get_association_request(adapter);
2325 wlan_cancel_association_work(priv);
2328 /* Copy the BSSID to the association request */
2329 memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
2330 set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
2331 wlan_postpone_association_work(priv);
2334 mutex_unlock(&adapter->lock);
2339 void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
2347 mutex_lock(&adapter->lock);
2348 ver.l = adapter->fwreleasenumber;
2349 mutex_unlock(&adapter->lock);
2352 sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]);
2354 sprintf(fwver, "%u.%u.%u.p%u",
2355 ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
2357 snprintf(fwversion, maxlen, fwver);
2362 * iwconfig settable callbacks
2364 static const iw_handler wlan_handler[] = {
2365 (iw_handler) NULL, /* SIOCSIWCOMMIT */
2366 (iw_handler) wlan_get_name, /* SIOCGIWNAME */
2367 (iw_handler) NULL, /* SIOCSIWNWID */
2368 (iw_handler) NULL, /* SIOCGIWNWID */
2369 (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */
2370 (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */
2371 (iw_handler) wlan_set_mode, /* SIOCSIWMODE */
2372 (iw_handler) wlan_get_mode, /* SIOCGIWMODE */
2373 (iw_handler) NULL, /* SIOCSIWSENS */
2374 (iw_handler) NULL, /* SIOCGIWSENS */
2375 (iw_handler) NULL, /* SIOCSIWRANGE */
2376 (iw_handler) wlan_get_range, /* SIOCGIWRANGE */
2377 (iw_handler) NULL, /* SIOCSIWPRIV */
2378 (iw_handler) NULL, /* SIOCGIWPRIV */
2379 (iw_handler) NULL, /* SIOCSIWSTATS */
2380 (iw_handler) NULL, /* SIOCGIWSTATS */
2381 iw_handler_set_spy, /* SIOCSIWSPY */
2382 iw_handler_get_spy, /* SIOCGIWSPY */
2383 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2384 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
2385 (iw_handler) wlan_set_wap, /* SIOCSIWAP */
2386 (iw_handler) wlan_get_wap, /* SIOCGIWAP */
2387 (iw_handler) NULL, /* SIOCSIWMLME */
2388 (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
2389 (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */
2390 (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */
2391 (iw_handler) wlan_set_essid, /* SIOCSIWESSID */
2392 (iw_handler) wlan_get_essid, /* SIOCGIWESSID */
2393 (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */
2394 (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */
2395 (iw_handler) NULL, /* -- hole -- */
2396 (iw_handler) NULL, /* -- hole -- */
2397 (iw_handler) wlan_set_rate, /* SIOCSIWRATE */
2398 (iw_handler) wlan_get_rate, /* SIOCGIWRATE */
2399 (iw_handler) wlan_set_rts, /* SIOCSIWRTS */
2400 (iw_handler) wlan_get_rts, /* SIOCGIWRTS */
2401 (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */
2402 (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */
2403 (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */
2404 (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */
2405 (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */
2406 (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */
2407 (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */
2408 (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */
2409 (iw_handler) wlan_set_power, /* SIOCSIWPOWER */
2410 (iw_handler) wlan_get_power, /* SIOCGIWPOWER */
2411 (iw_handler) NULL, /* -- hole -- */
2412 (iw_handler) NULL, /* -- hole -- */
2413 (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */
2414 (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */
2415 (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */
2416 (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */
2417 (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
2418 (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
2419 (iw_handler) NULL, /* SIOCSIWPMKSA */
2422 struct iw_handler_def libertas_handler_def = {
2423 .num_standard = sizeof(wlan_handler) / sizeof(iw_handler),
2424 .num_private = sizeof(wlan_private_handler) / sizeof(iw_handler),
2425 .num_private_args = sizeof(wlan_private_args) /
2426 sizeof(struct iw_priv_args),
2427 .standard = (iw_handler *) wlan_handler,
2428 .private = (iw_handler *) wlan_private_handler,
2429 .private_args = (struct iw_priv_args *)wlan_private_args,
2430 .get_wireless_stats = wlan_get_wireless_stats,