o wl3501: fix bug in iw_mgmt_info_element id field and more

. unfortunately we can't use enum iw_mgmt_info_element_ids for the
  id field in iw_mgmt_info_element, as it has to be u8 and sizeof(enum)
  is bigger than that, but we use the enum in the relevant functions to
  help catch invalid elements being used.
. also we can't have iw_mgmt_info_element with a fixed size data field,
  as it is variable as per the 802.11 specs, so I do a poor man's OOP
  by subclassing iw_mgmt_info_element into the standard element types. Done
  up to now with iw_mgmt_essid_pset and iw_mgmt_ds_pset, others will follow.
parent 85d95625
...@@ -217,13 +217,21 @@ enum iw_mgmt_info_element_ids { ...@@ -217,13 +217,21 @@ enum iw_mgmt_info_element_ids {
/* 32-255 Reserved, unused */ /* 32-255 Reserved, unused */
}; };
/* FIXME: check if it need to be bigger */
#define IW_MGMT_INFO_ELEMENT_MAX_DATA IW_ESSID_MAX_SIZE
struct iw_mgmt_info_element { struct iw_mgmt_info_element {
enum iw_mgmt_info_element_ids id; u8 id; /* one of enum iw_mgmt_info_element_ids,
u8 len; but sizeof(enum) > sizeof(u8) :-( */
u8 data[IW_MGMT_INFO_ELEMENT_MAX_DATA]; u8 len;
u8 data[0];
} __attribute__ ((packed));
struct iw_mgmt_essid_pset {
struct iw_mgmt_info_element el;
u8 essid[IW_ESSID_MAX_SIZE];
} __attribute__ ((packed));
struct iw_mgmt_ds_pset {
struct iw_mgmt_info_element el;
u8 chan;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct wl3501_tx_hdr { struct wl3501_tx_hdr {
...@@ -272,11 +280,11 @@ struct wl3501_start_req { ...@@ -272,11 +280,11 @@ struct wl3501_start_req {
u16 dtim_period; u16 dtim_period;
u16 probe_delay; u16 probe_delay;
u16 cap_info; u16 cap_info;
struct iw_mgmt_info_element ssid; struct iw_mgmt_essid_pset ssid;
u8 bss_basic_rate_set[10]; u8 bss_basic_rate_set[10];
u8 operational_rate_set[10]; u8 operational_rate_set[10];
u8 cf_pset[8]; u8 cf_pset[8];
struct iw_mgmt_info_element ds_parameter_set; struct iw_mgmt_ds_pset ds_pset;
u8 ibss_pset[4]; u8 ibss_pset[4];
}; };
...@@ -352,8 +360,8 @@ struct wl3501_join_req { ...@@ -352,8 +360,8 @@ struct wl3501_join_req {
u16 cap_info; u16 cap_info;
u8 bss_type; u8 bss_type;
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
struct iw_mgmt_info_element ssid; struct iw_mgmt_essid_pset ssid;
struct iw_mgmt_info_element ds_parameter_set; struct iw_mgmt_ds_pset ds_pset;
u8 cf_pset[8]; u8 cf_pset[8];
u8 ibss_pset[4]; u8 ibss_pset[4];
u8 bss_basic_rate_set[10]; u8 bss_basic_rate_set[10];
...@@ -390,7 +398,7 @@ struct wl3501_scan_req { ...@@ -390,7 +398,7 @@ struct wl3501_scan_req {
u16 max_chan_time; u16 max_chan_time;
u8 chan_list[14]; u8 chan_list[14];
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
struct iw_mgmt_info_element ssid; struct iw_mgmt_essid_pset ssid;
enum wl3501_scan_type scan_type; enum wl3501_scan_type scan_type;
}; };
...@@ -406,8 +414,8 @@ struct wl3501_scan_confirm { ...@@ -406,8 +414,8 @@ struct wl3501_scan_confirm {
u16 cap_info; u16 cap_info;
u8 bss_type; u8 bss_type;
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
struct iw_mgmt_info_element ssid; struct iw_mgmt_essid_pset ssid;
struct iw_mgmt_info_element ds_parameter_set; struct iw_mgmt_ds_pset ds_pset;
u8 cf_pset[8]; u8 cf_pset[8];
u8 ibss_pset[4]; u8 ibss_pset[4];
u8 bss_basic_rate_set[10]; u8 bss_basic_rate_set[10];
...@@ -548,8 +556,8 @@ struct wl3501_card { ...@@ -548,8 +556,8 @@ struct wl3501_card {
u16 esbq_confirm_start; u16 esbq_confirm_start;
u16 esbq_confirm_end; u16 esbq_confirm_end;
u16 esbq_confirm; u16 esbq_confirm;
struct iw_mgmt_info_element essid; struct iw_mgmt_essid_pset essid;
struct iw_mgmt_info_element keep_essid; struct iw_mgmt_essid_pset keep_essid;
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
int net_type; int net_type;
char nick[32]; char nick[32];
......
...@@ -221,14 +221,12 @@ static int iw_default_channel(int reg_domain) ...@@ -221,14 +221,12 @@ static int iw_default_channel(int reg_domain)
} }
static void iw_set_mgmt_info_element(enum iw_mgmt_info_element_ids id, static void iw_set_mgmt_info_element(enum iw_mgmt_info_element_ids id,
struct iw_mgmt_info_element *element, struct iw_mgmt_info_element *el,
void *value, int len) void *value, int len)
{ {
int real_len = min_t(int, len, sizeof(element->data)); el->id = id;
el->len = len;
element->id = id; memcpy(el->data, value, len);
element->len = real_len;
memcpy(element->data, value, real_len);
} }
static void iw_copy_mgmt_info_element(struct iw_mgmt_info_element *to, static void iw_copy_mgmt_info_element(struct iw_mgmt_info_element *to,
...@@ -640,10 +638,12 @@ static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas) ...@@ -640,10 +638,12 @@ static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas)
struct wl3501_join_req sig = { struct wl3501_join_req sig = {
.sig_id = WL3501_SIG_JOIN_REQ, .sig_id = WL3501_SIG_JOIN_REQ,
.timeout = 10, .timeout = 10,
.ds_parameter_set = { .ds_pset = {
.id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, .el = {
.len = 1, .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET,
.data[0] = this->chan, .len = 1,
},
.chan = this->chan,
}, },
}; };
...@@ -657,10 +657,12 @@ static int wl3501_mgmt_start(struct wl3501_card *this) ...@@ -657,10 +657,12 @@ static int wl3501_mgmt_start(struct wl3501_card *this)
.sig_id = WL3501_SIG_START_REQ, .sig_id = WL3501_SIG_START_REQ,
.beacon_period = 400, .beacon_period = 400,
.dtim_period = 1, .dtim_period = 1,
.ds_parameter_set = { .ds_pset = {
.id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, .el = {
.len = 1, .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET,
.data = { [0] = this->chan, }, .len = 1,
},
.chan = this->chan,
}, },
.bss_basic_rate_set = { .bss_basic_rate_set = {
[0] = 0x01, [1] = 0x02, [2] = 0x82, [3] = 0x84, [0] = 0x01, [1] = 0x02, [2] = 0x82, [3] = 0x84,
...@@ -675,8 +677,8 @@ static int wl3501_mgmt_start(struct wl3501_card *this) ...@@ -675,8 +677,8 @@ static int wl3501_mgmt_start(struct wl3501_card *this)
.cap_info = wl3501_fw_cap_info(this), .cap_info = wl3501_fw_cap_info(this),
}; };
iw_copy_mgmt_info_element(&sig.ssid, &this->essid); iw_copy_mgmt_info_element(&sig.ssid.el, &this->essid.el);
iw_copy_mgmt_info_element(&this->keep_essid, &this->essid); iw_copy_mgmt_info_element(&this->keep_essid.el, &this->essid.el);
return wl3501_esbq_exec(this, &sig, sizeof(sig)); return wl3501_esbq_exec(this, &sig, sizeof(sig));
} }
...@@ -695,15 +697,15 @@ static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr) ...@@ -695,15 +697,15 @@ static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr)
(this->net_type == IW_MODE_ADHOC && (this->net_type == IW_MODE_ADHOC &&
(sig.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) || (sig.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) ||
this->net_type == IW_MODE_AUTO) { this->net_type == IW_MODE_AUTO) {
if (!this->essid.len) if (!this->essid.el.len)
matchflag = 1; matchflag = 1;
else if (this->essid.len == 3 && else if (this->essid.el.len == 3 &&
!memcmp(this->essid.data, "ANY", 3)) !memcmp(this->essid.essid, "ANY", 3))
matchflag = 1; matchflag = 1;
else if (this->essid.len != sig.ssid.len) else if (this->essid.el.len != sig.ssid.el.len)
matchflag = 0; matchflag = 0;
else if (memcmp(this->essid.data, sig.ssid.data, else if (memcmp(this->essid.essid, sig.ssid.essid,
this->essid.len)) this->essid.el.len))
matchflag = 0; matchflag = 0;
else else
matchflag = 1; matchflag = 1;
...@@ -915,19 +917,18 @@ static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr) ...@@ -915,19 +917,18 @@ static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr)
const int i = this->join_sta_bss; const int i = this->join_sta_bss;
memcpy(this->bssid, memcpy(this->bssid,
this->bss_set[i].bssid, ETH_ALEN); this->bss_set[i].bssid, ETH_ALEN);
this->chan = this->chan = this->bss_set[i].ds_pset.chan;
this->bss_set[i].ds_parameter_set.data[0]; iw_copy_mgmt_info_element(&this->keep_essid.el,
iw_copy_mgmt_info_element(&this->keep_essid, &this->bss_set[i].ssid.el);
&this->bss_set[i].ssid);
wl3501_mgmt_auth(this); wl3501_mgmt_auth(this);
} }
} else { } else {
const int i = this->join_sta_bss; const int i = this->join_sta_bss;
memcpy(&this->bssid, &this->bss_set[i].bssid, ETH_ALEN); memcpy(&this->bssid, &this->bss_set[i].bssid, ETH_ALEN);
this->chan = this->bss_set[i].ds_parameter_set.data[0]; this->chan = this->bss_set[i].ds_pset.chan;
iw_copy_mgmt_info_element(&this->keep_essid, iw_copy_mgmt_info_element(&this->keep_essid.el,
&this->bss_set[i].ssid); &this->bss_set[i].ssid.el);
wl3501_online(dev); wl3501_online(dev);
} }
} else { } else {
...@@ -1719,11 +1720,11 @@ static int wl3501_set_essid(struct net_device *dev, ...@@ -1719,11 +1720,11 @@ static int wl3501_set_essid(struct net_device *dev,
if (wrqu->data.flags) { if (wrqu->data.flags) {
iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID,
&this->essid, &this->essid.el,
extra, wrqu->data.length); extra, wrqu->data.length);
} else { /* We accept any ESSID */ } else { /* We accept any ESSID */
iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID,
&this->essid, "ANY", 3); &this->essid.el, "ANY", 3);
} }
return wl3501_reset(dev); return wl3501_reset(dev);
} }
...@@ -1737,8 +1738,8 @@ static int wl3501_get_essid(struct net_device *dev, ...@@ -1737,8 +1738,8 @@ static int wl3501_get_essid(struct net_device *dev,
spin_lock_irqsave(&this->lock, flags); spin_lock_irqsave(&this->lock, flags);
wrqu->essid.flags = 1; wrqu->essid.flags = 1;
wrqu->essid.length = this->essid.len; wrqu->essid.length = this->essid.el.len;
memcpy(extra, this->essid.data, this->essid.len); memcpy(extra, this->essid.essid, this->essid.el.len);
spin_unlock_irqrestore(&this->lock, flags); spin_unlock_irqrestore(&this->lock, flags);
return 0; return 0;
} }
...@@ -2143,7 +2144,7 @@ static void wl3501_config(dev_link_t *link) ...@@ -2143,7 +2144,7 @@ static void wl3501_config(dev_link_t *link)
this->bss_cnt = 0; this->bss_cnt = 0;
this->join_sta_bss = 0; this->join_sta_bss = 0;
this->adhoc_times = 0; this->adhoc_times = 0;
iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, &this->essid, iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, &this->essid.el,
"ANY", 3); "ANY", 3);
this->card_name[0] = '\0'; this->card_name[0] = '\0';
this->firmware_date[0] = '\0'; this->firmware_date[0] = '\0';
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment