diff --git a/include/net/d80211.h b/include/net/d80211.h
index ba5cb4c..0cde91f 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -256,6 +256,7 @@ struct ieee80211_conf {
u8 antenna_max; /* maximum antenna gain */
short tx_power_reduction; /* in 0.1 dBm */
+ u8 power_management_enable; /* flag to enable/disable power
management*/
int antenna_sel; /* default antenna conf:
* 0 = default/diversity,
* 1 = Ant0,
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 11804d5..86a5373 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1250,6 +1250,10 @@ static int ieee80211_tx(struct net_devic
break;
}
+ /* only data unicast frame */
+ if ((tx.u.tx.rate) && !mgmt && !control->no_ack)
+ local->last_rate = tx.u.tx.rate->rate * 100000;
+
skb = tx.skb; /* handlers are allowed to change skb */
if (sta)
@@ -4358,6 +4362,8 @@ struct net_device *ieee80211_alloc_hw(si
local->long_retry_limit = 4;
local->conf.calib_int = 60;
local->conf.radio_enabled = 1;
+ local->last_rate = -1;
+ local->conf.power_management_enable = 0;
local->rate_ctrl_num_up = RATE_CONTROL_NUM_UP;
local->rate_ctrl_num_down = RATE_CONTROL_NUM_DOWN;
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index bdaaf5e..29c40c5 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -396,6 +396,9 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12
int *supp_rates[NUM_IEEE80211_MODES];
int *basic_rates[NUM_IEEE80211_MODES];
+ u32 last_rate; /* last tx data rate value. management and multi cast
frame
+ * wont be used. */
+
int rts_threshold;
int cts_protect_erp_frames;
int fragmentation_threshold;
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index b983716..5e01659 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -1537,6 +1537,19 @@ static int ieee80211_ioctl_giwname(struc
char *name, char *extra)
{
struct ieee80211_local *local = dev->ieee80211_ptr;
+ struct ieee80211_sub_if_data *sdata;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (!local->conf.radio_enabled) {
+ strcpy(name, "radio off");
+ return 0;
+ } else if (sdata->type == IEEE80211_IF_TYPE_STA) {
+ if (!(sdata->u.sta.associated) ||
+ (sdata->u.sta.probereq_poll)) {
+ strcpy(name, "unassociated");
+ return 0;
+ }
+ }
switch (local->conf.phymode) {
case MODE_IEEE80211A:
@@ -1565,6 +1578,9 @@ static int ieee80211_ioctl_giwrange(stru
struct iw_point *data, char *extra)
{
struct iw_range *range = (struct iw_range *) extra;
+ int i,j,c;
+ int skip_bg = 0;
+ struct ieee80211_local *local = dev->ieee80211_ptr;
data->length = sizeof(struct iw_range);
memset(range, 0, sizeof(struct iw_range));
@@ -1580,6 +1596,42 @@ static int ieee80211_ioctl_giwrange(stru
range->min_frag = 256;
range->max_frag = 2346;
+ j = 0;
+ for (i = 0; i < local->num_curr_rates ; i++) {
+ struct ieee80211_rate *rate = &local->curr_rates[i];
+
+ if (rate->flags & IEEE80211_RATE_SUPPORTED) {
+ range->bitrate[j] = rate->rate * 100000;
+ j++;
+ }
+ }
+ range->num_bitrates = j;
+
+ c = 0;
+ for (i = 0; i < local->hw->num_modes; i++) {
+ struct ieee80211_hw_modes *mode = &local->hw->modes[i];
+ if (skip_bg &&
+ ((mode->mode == MODE_IEEE80211G) ||
+ (mode->mode == MODE_IEEE80211B)))
+ continue;
+
+ for (j = 0;
+ j < mode->num_channels && c < IW_MAX_FREQUENCIES; j++) {
+ struct ieee80211_channel *chan = &mode->channels[j];
+
+ range->freq[c].i = chan->chan;
+ range->freq[c].m = chan->freq * 100000;
+ range->freq[c].e = 1;
+ c++;
+ }
+ if ((mode->mode == MODE_IEEE80211G) ||
+ (mode->mode == MODE_IEEE80211B))
+ skip_bg = 1;
+
+ }
+ range->num_channels = c;
+ range->num_frequency = c;
+
return 0;
}
@@ -2138,6 +2190,169 @@ static int ieee80211_ioctl_giwretry(stru
}
+static int ieee80211_ioctl_siwrate(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ieee80211_local *local = dev->ieee80211_ptr;
+ int i, j;
+ u32 target_rate = wrqu->bitrate.value /100000;
+ u32 fixed;
+ int *old_supp = local->supp_rates[local->conf.phymode];
+ int *supp = NULL;
+
+ /* value = -1, fixed = 0 means auto only, so we should use
+ * all rates offered by AP
+ * value = X, fixed = 1 means only rate X
+ * value = X, fixed = 0 means all rates lower equal X */
+ if (target_rate == -1) {
+ fixed = 0;
+ goto apply;
+ }
+
+ fixed = wrqu->bitrate.fixed;
+ supp = (int *) kmalloc((local->num_curr_rates + 1) *
+ sizeof(int), GFP_KERNEL);
+ if (!supp)
+ return 0;
+
+ j = 0;
+ for (i=0; i< local->num_curr_rates; i++) {
+ struct ieee80211_rate *rate = &local->curr_rates[i];
+
+ if (target_rate == rate->rate) {
+ supp[j++] = rate->rate;
+ break;
+ } else if (!fixed)
+ supp[j++] = rate->rate;
+ }
+
+ supp[j] = -1;
+
+ if ((j >= local->num_curr_rates) || (j == 0)) {
+ kfree(supp);
+ supp = NULL;
+ }
+
+ apply:
+ if (!old_supp && !supp)
+ return 0;
+
+ local->supp_rates[local->conf.phymode] = supp;
+ if (old_supp)
+ kfree(old_supp);
+
+
+ ieee80211_prepare_rates(dev);
+ ieee80211_hw_config(dev);
+ return 0;
+}
+
+static int ieee80211_ioctl_giwrate(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ieee80211_local *local = dev->ieee80211_ptr;
+ u32 max_rate = 0;
+ int i;
+
+ for (i = local->num_curr_rates - 1; i >= 0 ; i--) {
+ struct ieee80211_rate *rate = &local->curr_rates[i];
+
+ if (rate->flags & IEEE80211_RATE_SUPPORTED) {
+ max_rate = rate->rate * 100000;
+ break;
+ }
+ }
+
+ if (max_rate >= local->last_rate)
+ wrqu->bitrate.value = local->last_rate;
+ else
+ wrqu->bitrate.value = max_rate;
+ return 0;
+}
+
+static int ieee80211_ioctl_giwtxpow(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ieee80211_conf *conf = ieee80211_get_hw_conf(dev);
+
+ wrqu->txpower.flags = IW_TXPOW_DBM;
+ wrqu->txpower.fixed = 1;
+ wrqu->txpower.disabled = (conf->radio_enabled) ? 0 : 1;
+ wrqu->txpower.value = conf->power_level;
+ return 0;
+}
+
+
+static int ieee80211_ioctl_siwtxpow(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int rc = 0;
+ struct ieee80211_conf *conf = ieee80211_get_hw_conf(dev);
+
+ /* we need to add flag in ieee80211_conf to mark the changed fields.
+ */
+ if (wrqu->txpower.flags != IW_TXPOW_DBM)
+ rc = -EINVAL;
+ else
+ conf->power_level = wrqu->txpower.value;
+
+
+ ieee80211_ioctl_set_radio_enabled(dev, !wrqu->txpower.disabled);
+ return rc;
+}
+
+static int ieee80211_ioctl_siwpower(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ieee80211_conf *conf = ieee80211_get_hw_conf(dev);
+
+ /* We might need to add new callback function instead of
+ calling ieee80211_hw_config
+ */
+ if (wrqu->power.disabled) {
+ conf->power_management_enable = 0;
+ ieee80211_hw_config(dev);
+ return 0;
+ }
+
+ if (wrqu->power.flags & IW_POWER_TYPE)
+ return -EOPNOTSUPP;
+
+ switch (wrqu->power.flags & IW_POWER_MODE) {
+ case IW_POWER_ON: /* If not specified */
+ case IW_POWER_MODE: /* If set all mask */
+ case IW_POWER_ALL_R: /* If explicitely state all */
+ break;
+ default: /* Otherwise we don't support it */
+ return -EOPNOTSUPP;
+ }
+
+ conf->power_management_enable = 1;
+ ieee80211_hw_config(dev);
+
+ return 0;
+}
+
+static int ieee80211_ioctl_giwpower(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ieee80211_conf *conf = ieee80211_get_hw_conf(dev);
+
+ if (!conf->power_management_enable)
+ wrqu->power.disabled = 1;
+ else {
+ wrqu->power.disabled = 0;
+ }
+ return 0;
+}
+
+
static void ieee80211_ioctl_unmask_channels(struct ieee80211_local *local)
{
int m, c;
@@ -3141,20 +3356,20 @@ static const iw_handler ieee80211_handle
(iw_handler) NULL, /* SIOCGIWNICKN */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* SIOCSIWRATE */
- (iw_handler) NULL, /* SIOCGIWRATE */
+ (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */
+ (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */
(iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */
(iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */
(iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */
(iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */
- (iw_handler) NULL, /* SIOCSIWTXPOW */
- (iw_handler) NULL, /* SIOCGIWTXPOW */
+ (iw_handler) ieee80211_ioctl_siwtxpow, /* SIOCSIWTXPOW */
+ (iw_handler) ieee80211_ioctl_giwtxpow, /* SIOCGIWTXPOW */
(iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */
(iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */
(iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */
(iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */
- (iw_handler) NULL, /* SIOCSIWPOWER */
- (iw_handler) NULL, /* SIOCGIWPOWER */
+ (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */
+ (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) ieee80211_ioctl_siwgenie, /* SIOCSIWGENIE */
the attached patch will add support to handle these iw_handle
SIOC[S/G]IWRATE, SIOC[S/G]IWTXPOW and SIOC[S/G]IWPOWER. It also added
some changes in ieee80211_ioctl_giwrange function to report supported
channels and rates. a call to ieee80211_hw_config is needed to infor
the low level driver about these changes, I guess we might need to add
flag to indicate which parameters was changed so the low level driver
does not need to make extra calls.
- [PATCH 01/3] d80211: add support for SIOCSIWRATE, SIOCSIWTX... Mohamed Abbas
- [PATCH 02/3] d80211: iwlist scan Mohamed Abbas
- [PATCH 03/3] d80211: adhoc Mohamed Abbas
- Re: [PATCH 03/3] d80211: adhoc Jiri Benc
- Re: [PATCH 01/3] d80211: add support for SIOCSIWRATE, ... Jiri Benc
- Re: [PATCH 01/3] d80211: add support for SIOCSIWRATE, ... Jouni Malinen
- Re: [PATCH 01/3] d80211: add support for SIOCSIWRA... Mohamed Abbas
