2009-08-05 20:32:59

by Dave Kilroy

[permalink] [raw]
Subject: [RFC 0/4] orinoco: use cfg80211 for key manipulation

First attempt at connect/disconnect, join_ibss/leave_ibss, and add_key
etc. These patches rely on the series I just sent, but conflict with
Holgers set_channel patch. Simple to resolve, and I'll do that in my
next update.

This doesn't work yet*, but I've a number of questions.

- The cfg80211 notification functions like cfg80211_connect_result
are not called in this series. Does the driver need to keep track of
each call and make sure it calls the right notifer? Right now orinoco
arbitrarily sends SIOCGIWAP, IWEVASSOCRESPIE and IWEVASSOCREQIE on
?authorisation? Also not sure how this will tie in with
cfg80211_send_rx_auth/assoc.

- In station mode, is the connect crypto struct fully filled in
regardless of WEP/WPA? I'd like to set priv->encode_alg at this stage,
and then only accept keys of that type via add_key. Unfortunately
join_ibss doesn't have similar info.

- In adhoc mode, how do you set open/shared WEP? i.e. how does orinoco
know to set priv->wep_restrict?

- Digging around cfg80211, it looks like set_default_key isn't called
when authentication is TKIP. How does the driver tell which key to use
for transmit? Are we supposed to assume the group key is the transmit
key?

- TKIP pairwise keys. I think orinoco has always ignored them. The Agere
driver installed pairwaise keys to index 0. Should I attempt anything?

- TKIP and ad-hoc. err... I plan on leaving this alone.


All hints greatly appreciated :)



Dave.

* wpa_supplicant in wext mode gets stuck in the ASSOCIATING state.
Haven't tried nl80211 mode.

---
David Kilroy (4):
orinoco: add cfg80211 connect and disconnect
orinoco: add cfg80211 join_ibss and leave_ibss
orinoco: implement cfg80211 key manipulation functions
orinoco: do WE via cfg80211

drivers/net/wireless/orinoco/cfg.c | 486 +++++++++++++++++++++++
drivers/net/wireless/orinoco/wext.c | 726 +----------------------------------
2 files changed, 497 insertions(+), 715 deletions(-)



2009-08-05 20:33:06

by Dave Kilroy

[permalink] [raw]
Subject: [RFC 2/4] orinoco: add cfg80211 join_ibss and leave_ibss

Basic ad-hoc support.

Signed-off-by: David Kilroy <[email protected]>
---
drivers/net/wireless/orinoco/cfg.c | 51 ++++++++++++++++++++++++++++++++++++
1 files changed, 51 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index 56bd4f1..84a7884 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -390,9 +390,60 @@ static int orinoco_disconnect(struct wiphy *wiphy, struct net_device *dev,
return err;
}

+static int orinoco_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ unsigned long lock;
+ int err;
+
+ if (orinoco_lock(priv, &lock) != 0)
+ return -EBUSY;
+
+ /* Setup the requested parameters in priv. If the card is not
+ * capable, then the driver will just ignore the settings that
+ * it can't do. */
+
+ err = __orinoco_connect(wiphy, params->channel, params->bssid,
+ params->ssid, params->ssid_len);
+ if (err)
+ goto out;
+
+ /* Ignore information elements and beacon interval */
+
+ err = orinoco_commit(priv);
+ out:
+ orinoco_unlock(priv, &lock);
+
+ return err;
+}
+
+static int orinoco_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ unsigned long lock;
+ int err;
+
+ if (orinoco_lock(priv, &lock) != 0)
+ return -EBUSY;
+
+ /* Do we need to disassociate as well? */
+
+ memset(priv->desired_bssid, 0, ETH_ALEN);
+ memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
+
+ err = orinoco_commit(priv);
+
+ orinoco_unlock(priv, &lock);
+
+ return err;
+}
+
const struct cfg80211_ops orinoco_cfg_ops = {
.change_virtual_intf = orinoco_change_vif,
.scan = orinoco_scan,
.connect = orinoco_connect,
.disconnect = orinoco_disconnect,
+ .join_ibss = orinoco_join_ibss,
+ .leave_ibss = orinoco_leave_ibss,
};
--
1.6.3.3


2009-08-07 21:56:01

by Dan Williams

[permalink] [raw]
Subject: Re: [RFC 0/4] orinoco: use cfg80211 for key manipulation

On Fri, 2009-08-07 at 22:38 +0100, Dave wrote:
> Dan Williams wrote:
> > On Fri, 2009-08-07 at 21:42 +0100, Dave wrote:
> >> David Kilroy wrote:
> >>> First attempt at connect/disconnect, join_ibss/leave_ibss, and add_key
> >>> etc. These patches rely on the series I just sent, but conflict with
> >>> Holgers set_channel patch. Simple to resolve, and I'll do that in my
> >>> next update.
> >>>
> >>> This doesn't work yet*, but I've a number of questions.
> >> FYI, I've got this kinda working with wpa_supplicant in wext mode.
> >>
> >> First: on it's own wpa_supplicant keeps doing the 4 way handshake, while
> >> cfg80211 pumps out the following:
> >>
> >> ------------[ cut here ]------------
> >> WARNING: at net/wireless/sme.c:451 __cfg80211_roamed+0x9a/0x1a5 [cfg80211]()
> >> Hardware name: Latitude C600
> >> Modules linked in: orinoco_cs orinoco cfg80211 michael_mic snd_maestro3
> >> aty128fb [last unloaded: cfg80211]
> >> Pid: 5, comm: events/0 Tainted: G M W 2.6.31-rc4-wl #87
> >> Call Trace:
> >> [<c101ca51>] warn_slowpath_common+0x60/0x90
> >> [<c101ca8e>] warn_slowpath_null+0xd/0x10
> >> [<d1521659>] __cfg80211_roamed+0x9a/0x1a5 [cfg80211]
> >> [<d15139a9>] cfg80211_event_work+0x104/0x1bc [cfg80211]
> >> [<c102b39c>] worker_thread+0x15e/0x208
> >> [<d15138a5>] ? cfg80211_event_work+0x0/0x1bc [cfg80211]
> >> [<c102e5d5>] ? autoremove_wake_function+0x0/0x33
> >> [<c102b23e>] ? worker_thread+0x0/0x208
> >> [<c102e261>] kthread+0x66/0x6b
> >> [<c102e1fb>] ? kthread+0x0/0x6b
> >> [<c1003053>] kernel_thread_helper+0x7/0x10
> >> ---[ end trace 12e5dbe2024c37ae ]---
> >>
> >> Cfg80211 is trying to select the bss we've authenticated against.
> >> Unfortunately the BSS list is empty.
> >>
> >> If before starting wpa_supplicant I run:
> >>
> >> iw dev eth1 scan ssid <SSID>
> >>
> >> Then wpa_supplicant connects fine. The AP in question is configured with
> >> a hidden SSID.
> >>
> >> Any suggestions as to how I need to address this?
> >
> > Do a scan before you try to associate? Most fullmac cards do one
> > internally in the firmware before they try to associate anyway, but they
> > may not emit the event to the driver. If you're not doing a scan when
> > you get the associate request, you probably should do one, let cfg80211
> > cache the bss list, and then you're fine, right?
>
> That should work. I just realised why it's doing this. I have
> wpa_supplicant configured with ap_scan=2, so it doesn't scan before
> connecting.

Yeah, Don't Do That :)

You shouldn't really ever use ap_scan=2 unless you want IW_MODE_MASTER
or IW_MODE_IBSS. Think of the children, and let the supplicant do the
work.

Dan

> Just tried wpa_supplicant in nl80211 mode. In that case, it's stuck in
> scanning (presumably ignoring my ap_scan setting). It's not seeing my AP
> (because it's hidden?), and so doesn't proceed. And I can't seem to get
> it to do an active scan for my AP.
>
>
> Dave.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html


2009-08-06 07:40:08

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 0/4] orinoco: use cfg80211 for key manipulation


> - The cfg80211 notification functions like cfg80211_connect_result
> are not called in this series. Does the driver need to keep track of
> each call and make sure it calls the right notifer? Right now orinoco
> arbitrarily sends SIOCGIWAP, IWEVASSOCRESPIE and IWEVASSOCREQIE on
> ?authorisation? Also not sure how this will tie in with
> cfg80211_send_rx_auth/assoc.

You don't have to worry about send_rx_auth/assoc -- those are for
drivers like mac80211 that leave the SME up to cfg80211 or userspace.
All you need to implement is a call to cfg80211_connect_result() and
possibly cfg80211_roamed() when the card can roam itself if no BSSID is
set. Those take the assoc request/response IEs too. You don't need to
call wireless_send_event at all :)

> - In station mode, is the connect crypto struct fully filled in
> regardless of WEP/WPA? I'd like to set priv->encode_alg at this stage,
> and then only accept keys of that type via add_key. Unfortunately
> join_ibss doesn't have similar info.

Yes, it should be filled in. I'm uncertain whether iw does it correctly
for WEP right now, if not I can fix that. For IBSS, nl80211 can actually
pass that info, but doesn't right now, it probably should do that
though.

> - In adhoc mode, how do you set open/shared WEP? i.e. how does orinoco
> know to set priv->wep_restrict?

What's priv->wep_restrict? open/shared in ad-hoc seems very strange
since you have no authentication frames?

> - Digging around cfg80211, it looks like set_default_key isn't called
> when authentication is TKIP. How does the driver tell which key to use
> for transmit? Are we supposed to assume the group key is the transmit
> key?

The pairwise key, of course. But you knew that, so I think I just don't
understand the question.

> - TKIP pairwise keys. I think orinoco has always ignored them. The Agere
> driver installed pairwaise keys to index 0. Should I attempt anything?

I don't think it can have ignored them for proper operation? When you're
doing WPA, you can only receive with the group key, and transmit with
the pairwise key negotiated with the AP.

> - TKIP and ad-hoc. err... I plan on leaving this alone.

:)
So far I've only really supported WEP with IBSS in all this. I'm happy
to work with somebody to add support for more, but I have to admit that
I'm not particularly interested myself.

johannes


Attachments:
signature.asc (801.00 B)
This is a digitally signed message part

2009-08-07 20:42:41

by Dave Kilroy

[permalink] [raw]
Subject: Re: [RFC 0/4] orinoco: use cfg80211 for key manipulation

David Kilroy wrote:
> First attempt at connect/disconnect, join_ibss/leave_ibss, and add_key
> etc. These patches rely on the series I just sent, but conflict with
> Holgers set_channel patch. Simple to resolve, and I'll do that in my
> next update.
>
> This doesn't work yet*, but I've a number of questions.

FYI, I've got this kinda working with wpa_supplicant in wext mode.

First: on it's own wpa_supplicant keeps doing the 4 way handshake, while
cfg80211 pumps out the following:

------------[ cut here ]------------
WARNING: at net/wireless/sme.c:451 __cfg80211_roamed+0x9a/0x1a5 [cfg80211]()
Hardware name: Latitude C600
Modules linked in: orinoco_cs orinoco cfg80211 michael_mic snd_maestro3
aty128fb [last unloaded: cfg80211]
Pid: 5, comm: events/0 Tainted: G M W 2.6.31-rc4-wl #87
Call Trace:
[<c101ca51>] warn_slowpath_common+0x60/0x90
[<c101ca8e>] warn_slowpath_null+0xd/0x10
[<d1521659>] __cfg80211_roamed+0x9a/0x1a5 [cfg80211]
[<d15139a9>] cfg80211_event_work+0x104/0x1bc [cfg80211]
[<c102b39c>] worker_thread+0x15e/0x208
[<d15138a5>] ? cfg80211_event_work+0x0/0x1bc [cfg80211]
[<c102e5d5>] ? autoremove_wake_function+0x0/0x33
[<c102b23e>] ? worker_thread+0x0/0x208
[<c102e261>] kthread+0x66/0x6b
[<c102e1fb>] ? kthread+0x0/0x6b
[<c1003053>] kernel_thread_helper+0x7/0x10
---[ end trace 12e5dbe2024c37ae ]---

Cfg80211 is trying to select the bss we've authenticated against.
Unfortunately the BSS list is empty.

If before starting wpa_supplicant I run:

iw dev eth1 scan ssid <SSID>

Then wpa_supplicant connects fine. The AP in question is configured with
a hidden SSID.

Any suggestions as to how I need to address this?


Regards,

Dave.

2009-08-06 07:47:23

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 1/4] orinoco: add cfg80211 connect and disconnect

On Wed, 2009-08-05 at 21:32 +0100, David Kilroy wrote:

> +static int __orinoco_connect(struct wiphy *wiphy,
> + struct ieee80211_channel *channel,
> + const u8 *bssid, const u8 *ssid,
> + u8 ssid_len)
> +{
> + struct orinoco_private *priv = wiphy_priv(wiphy);
> +

> + /* Intersil firmware hangs if you try to roam manually
> + * without an ESSID set. */
> + if ((priv->firmware_type == FIRMWARE_TYPE_INTERSIL) &&
> + (priv->desired_essid[0] == 0)) {

This is a wrong way to check for an empty SSID, since \0 is a valid byte
in the SSID. You should check for ssid_len == 0 instead.

However, it's also not necessary, cfg80211 will never call this function
without an SSID. So you can even just BUG_ON(!ssid_len); or something :)

> + switch (sme->auth_type) {
> + case NL80211_AUTHTYPE_OPEN_SYSTEM:
> + priv->wep_restrict = 0;
> + break;
> + case NL80211_AUTHTYPE_SHARED_KEY:
> + priv->wep_restrict = 1;
> + break;
> + /* Ignore all other settings */
> + default:
> + break;

I think you should return -EINVAL for other values.

> + }
> +
> + switch (sme->crypto.cipher_group) {
> + case WLAN_CIPHER_SUITE_TKIP:
> + encode_alg = ORINOCO_ALG_TKIP;
> + break;
> +
> + case WLAN_CIPHER_SUITE_WEP40:
> + case WLAN_CIPHER_SUITE_WEP104:
> + encode_alg = ORINOCO_ALG_WEP;
> + break;
> +
> + default:
> + encode_alg = ORINOCO_ALG_NONE;
> + }

Same here, I guess, although that can't really happen since you only
advertised these ones.

Other than that, as noted in my reply to 0/5, this won't work properly
since you don't ever call cfg80211_connect_result().

johannes


Attachments:
signature.asc (801.00 B)
This is a digitally signed message part

2009-08-05 20:33:03

by Dave Kilroy

[permalink] [raw]
Subject: [RFC 1/4] orinoco: add cfg80211 connect and disconnect

Basic station mode support.

Signed-off-by: David Kilroy <[email protected]>
---
drivers/net/wireless/orinoco/cfg.c | 236 ++++++++++++++++++++++++++++++++++++
1 files changed, 236 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index 1a87d3a..56bd4f1 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -156,7 +156,243 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
return err;
}

+/* Helper to ensure all keys are valid for the current encoding
+ algorithm */
+static void orinoco_set_encoding(struct orinoco_private *priv,
+ enum orinoco_alg encoding)
+{
+ if (priv->encode_alg &&
+ priv->encode_alg != encoding) {
+ int i;
+
+ for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
+ kfree(priv->keys[i].key);
+ kfree(priv->keys[i].seq);
+ priv->keys[i].key = NULL;
+ priv->keys[i].seq = NULL;
+ priv->keys[i].key_len = 0;
+ priv->keys[i].seq_len = 0;
+ priv->keys[i].cipher = 0;
+ }
+
+ if (priv->encode_alg == ORINOCO_ALG_TKIP &&
+ priv->has_wpa) {
+ (void) orinoco_clear_tkip_key(priv, i);
+ (void) orinoco_clear_tkip_key(priv, i);
+ (void) orinoco_clear_tkip_key(priv, i);
+ (void) orinoco_clear_tkip_key(priv, i);
+ } else if (priv->encode_alg == ORINOCO_ALG_WEP)
+ __orinoco_hw_setup_wepkeys(priv);
+ }
+ priv->encode_alg = encoding;
+}
+
+/* Helper routine to record keys
+ * Do not call from interrupt context */
+static int orinoco_set_key(struct orinoco_private *priv, int index,
+ enum orinoco_alg alg, const u8 *key, int key_len,
+ const u8 *seq, int seq_len)
+{
+ kzfree(priv->keys[index].key);
+ kzfree(priv->keys[index].seq);
+
+ if (key_len) {
+ priv->keys[index].key = kzalloc(key_len, GFP_KERNEL);
+ if (!priv->keys[index].key)
+ goto nomem;
+ } else
+ priv->keys[index].key = NULL;
+
+ if (seq_len) {
+ priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL);
+ if (!priv->keys[index].seq)
+ goto free_key;
+ } else
+ priv->keys[index].seq = NULL;
+
+ priv->keys[index].key_len = key_len;
+ priv->keys[index].seq_len = seq_len;
+
+ if (key_len)
+ memcpy(priv->keys[index].key, key, key_len);
+ if (seq_len)
+ memcpy(priv->keys[index].seq, seq, seq_len);
+
+
+ switch (alg) {
+ case ORINOCO_ALG_TKIP:
+ priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP;
+ break;
+
+ case ORINOCO_ALG_WEP:
+ priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ?
+ WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40;
+ break;
+
+ case ORINOCO_ALG_NONE:
+ default:
+ priv->keys[index].cipher = 0;
+ break;
+ }
+
+ return 0;
+
+free_key:
+ kfree(priv->keys[index].key);
+ priv->keys[index].key = NULL;
+
+nomem:
+ priv->keys[index].key_len = 0;
+ priv->keys[index].seq_len = 0;
+ priv->keys[index].cipher = 0;
+
+ return -ENOMEM;
+}
+
+/* Setup channel, SSID and BSSID */
+static int __orinoco_connect(struct wiphy *wiphy,
+ struct ieee80211_channel *channel,
+ const u8 *bssid, const u8 *ssid,
+ u8 ssid_len)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+
+ if (channel) {
+ int chan;
+
+ chan = ieee80211_freq_to_dsss_chan(channel->center_freq);
+
+ if ((chan > 0) && (chan < NUM_CHANNELS) &&
+ (priv->channel_mask & (1 << chan)))
+ priv->channel = chan;
+ }
+
+ memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
+ if (ssid)
+ memcpy(priv->desired_essid, ssid, ssid_len);
+
+ if (bssid) {
+ memcpy(priv->desired_bssid, bssid, ETH_ALEN);
+
+ /* Intersil firmware hangs if you try to roam manually
+ * without an ESSID set. */
+ if ((priv->firmware_type == FIRMWARE_TYPE_INTERSIL) &&
+ (priv->desired_essid[0] == 0)) {
+ printk(KERN_WARNING "%s: Desired SSID must be set for "
+ "manual roaming\n", wiphy_name(wiphy));
+ return -EOPNOTSUPP;
+ }
+
+ priv->bssid_fixed = 1;
+ } else {
+ memset(priv->desired_bssid, 0, ETH_ALEN);
+ priv->bssid_fixed = 0;
+ }
+
+ return 0;
+}
+
+static int orinoco_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ enum orinoco_alg encode_alg;
+ unsigned long lock;
+ int err;
+
+ if (orinoco_lock(priv, &lock) != 0)
+ return -EBUSY;
+
+ /* Setup the requested parameters in priv. If the card is not
+ * capable, then the driver will just ignore the settings that
+ * it can't do. */
+ err = __orinoco_connect(wiphy, sme->channel, sme->bssid,
+ sme->ssid, sme->ssid_len);
+ if (err)
+ goto out;
+
+ switch (sme->auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ priv->wep_restrict = 0;
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ priv->wep_restrict = 1;
+ break;
+ /* Ignore all other settings */
+ default:
+ break;
+ }
+
+ switch (sme->crypto.cipher_group) {
+ case WLAN_CIPHER_SUITE_TKIP:
+ encode_alg = ORINOCO_ALG_TKIP;
+ break;
+
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ encode_alg = ORINOCO_ALG_WEP;
+ break;
+
+ default:
+ encode_alg = ORINOCO_ALG_NONE;
+ }
+
+ orinoco_set_encoding(priv, encode_alg);
+
+ /* What are we supposed to do with multiple AKM suites? */
+ if (sme->crypto.n_akm_suites > 0)
+ priv->key_mgmt = sme->crypto.akm_suites[0];
+
+ /* Finally, set WEP key */
+ if (encode_alg == ORINOCO_ALG_WEP) {
+ err = orinoco_set_key(priv, sme->key_idx, encode_alg,
+ &sme->key[0], sme->key_len, NULL, 0);
+ if (err)
+ goto out;
+
+ priv->tx_key = sme->key_idx;
+ }
+
+ err = orinoco_commit(priv);
+
+out:
+ orinoco_unlock(priv, &lock);
+
+ return err;
+}
+
+static int orinoco_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ unsigned long lock;
+ u8 addr[ETH_ALEN];
+ int err;
+
+ if (orinoco_lock(priv, &lock) != 0)
+ return -EBUSY;
+
+ memset(priv->desired_bssid, 0, ETH_ALEN);
+ memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
+
+ err = orinoco_hw_get_current_bssid(priv, &addr[0]);
+
+ if (!err) {
+ err = orinoco_hw_disassociate(priv, &addr[0],
+ reason_code);
+ }
+
+ if (err)
+ err = orinoco_commit(priv);
+
+ orinoco_unlock(priv, &lock);
+
+ return err;
+}
+
const struct cfg80211_ops orinoco_cfg_ops = {
.change_virtual_intf = orinoco_change_vif,
.scan = orinoco_scan,
+ .connect = orinoco_connect,
+ .disconnect = orinoco_disconnect,
};
--
1.6.3.3


2009-08-06 17:34:12

by Dave Kilroy

[permalink] [raw]
Subject: Re: [RFC 0/4] orinoco: use cfg80211 for key manipulation

Johannes Berg wrote:
>> - The cfg80211 notification functions like cfg80211_connect_result
>> are not called in this series. Does the driver need to keep track of
>> each call and make sure it calls the right notifer? Right now orinoco
>> arbitrarily sends SIOCGIWAP, IWEVASSOCRESPIE and IWEVASSOCREQIE on
>> ?authorisation? Also not sure how this will tie in with
>> cfg80211_send_rx_auth/assoc.
>
> You don't have to worry about send_rx_auth/assoc -- those are for
> drivers like mac80211 that leave the SME up to cfg80211 or userspace.
> All you need to implement is a call to cfg80211_connect_result() and
> possibly cfg80211_roamed() when the card can roam itself if no BSSID is
> set. Those take the assoc request/response IEs too. You don't need to
> call wireless_send_event at all :)

I thought as much. I'll add those calls, and see what happens.

>> - In station mode, is the connect crypto struct fully filled in
>> regardless of WEP/WPA? I'd like to set priv->encode_alg at this stage,
>> and then only accept keys of that type via add_key. Unfortunately
>> join_ibss doesn't have similar info.
>
> Yes, it should be filled in. I'm uncertain whether iw does it correctly
> for WEP right now, if not I can fix that. For IBSS, nl80211 can actually
> pass that info, but doesn't right now, it probably should do that
> though.
>
>> - In adhoc mode, how do you set open/shared WEP? i.e. how does orinoco
>> know to set priv->wep_restrict?
>
> What's priv->wep_restrict? open/shared in ad-hoc seems very strange
> since you have no authentication frames?

priv->wep_restrict differentiates between using
NL80211_AUTHTYPE_OPEN_SYSTEM or NL80211_AUTHTYPE_SHARED_KEY. If it makes
no difference, I'll just zero it in ad-hoc mode.

>> - Digging around cfg80211, it looks like set_default_key isn't called
>> when authentication is TKIP. How does the driver tell which key to use
>> for transmit? Are we supposed to assume the group key is the transmit
>> key?
>
> The pairwise key, of course. But you knew that, so I think I just don't
> understand the question.

A bit of confusion on my part, I (think I) meant pairwise key. The tkip
key install RID takes a flag to indicate when the key is the transmit
key. So I'll set this for any pairwise key being installed, and assume
we only get one of those. Should work in station mode.

>> - TKIP pairwise keys. I think orinoco has always ignored them. The Agere
>> driver installed pairwaise keys to index 0. Should I attempt anything?
>
> I don't think it can have ignored them for proper operation? When you're
> doing WPA, you can only receive with the group key, and transmit with
> the pairwise key negotiated with the AP.

I think I'm just misremembering the details of what the Agere driver
did, and confusing myself.

Thanks for taking the time to have a look (and answer my silly questions!).


Dave.

2009-08-05 20:33:11

by Dave Kilroy

[permalink] [raw]
Subject: [RFC 3/4] orinoco: implement cfg80211 key manipulation functions

Signed-off-by: David Kilroy <[email protected]>
---
drivers/net/wireless/orinoco/cfg.c | 199 ++++++++++++++++++++++++++++++++++++
1 files changed, 199 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index 84a7884..9ed690e 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -439,6 +439,201 @@ static int orinoco_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
return err;
}

+static int orinoco_add_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_index, const u8 *mac_addr,
+ struct key_params *params)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int err = 0;
+ unsigned long lock;
+ enum orinoco_alg alg = ORINOCO_ALG_NONE;
+ int key_len;
+
+ if (key_index >= ORINOCO_MAX_KEYS)
+ return -EINVAL;
+
+ if (orinoco_lock(priv, &lock) != 0)
+ return -EBUSY;
+
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ alg = ORINOCO_ALG_WEP;
+
+ if (!priv->has_wep)
+ err = -EOPNOTSUPP;
+
+ if (params->key_len > ORINOCO_MAX_KEY_SIZE)
+ err = -E2BIG;
+ else if (params->key_len > SMALL_KEY_SIZE)
+ key_len = LARGE_KEY_SIZE;
+ else if (params->key_len > 0)
+ key_len = SMALL_KEY_SIZE;
+ else
+ err = -EINVAL;
+
+ break;
+
+ case WLAN_CIPHER_SUITE_TKIP:
+ alg = ORINOCO_ALG_TKIP;
+
+ if (!priv->has_wpa)
+ err = -EOPNOTSUPP;
+ else if (params->key_len < WLAN_KEY_LEN_TKIP)
+ err = -EINVAL;
+
+ key_len = WLAN_KEY_LEN_TKIP;
+ break;
+
+ case WLAN_CIPHER_SUITE_CCMP:
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ default:
+ err = -EOPNOTSUPP;
+ }
+
+ if (err)
+ goto out;
+
+ /* Ensure existing keys are of the same cipher suite */
+ orinoco_set_encoding(priv, alg);
+
+ err = orinoco_set_key(priv, key_index, alg,
+ params->key, params->key_len,
+ params->seq, params->seq_len);
+ if (err)
+ goto out;
+
+ if (alg == ORINOCO_ALG_TKIP) {
+ /* We don't know if this is the tx key yet.
+ * We'll reprogram it when we find out. */
+ err = __orinoco_hw_set_tkip_key(priv, key_index, 0,
+ priv->keys[key_index].key,
+ priv->keys[key_index].seq,
+ priv->keys[key_index].seq_len,
+ NULL, 0);
+
+ priv->wpa_enabled = 1;
+ }
+
+ err = __orinoco_hw_setup_enc(priv);
+
+ out:
+ orinoco_unlock(priv, &lock);
+
+ return err;
+}
+
+static int orinoco_get_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_index, const u8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie, struct key_params*))
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ struct key_params params;
+ u8 key[WLAN_KEY_LEN_TKIP];
+ u8 tsc[ORINOCO_SEQ_LEN];
+ unsigned long lock;
+ int err = 0;
+
+ if (key_index >= ORINOCO_MAX_KEYS)
+ return -EINVAL;
+
+ if (orinoco_lock(priv, &lock) != 0)
+ return -EBUSY;
+
+ /* Take a copy of the key info */
+ memcpy(&key, priv->keys[key_index].key, priv->keys[key_index].key_len);
+
+ params.cipher = priv->keys[key_index].cipher;
+ params.key = &key[0];
+ params.key_len = priv->keys[key_index].key_len;
+
+ if (params.cipher == WLAN_CIPHER_SUITE_TKIP) {
+ /* Populate the current TSC */
+ orinoco_hw_get_tkip_iv(priv, key_index, &tsc[0]);
+ params.seq = &tsc[0];
+ params.seq_len = ORINOCO_SEQ_LEN;
+ } else {
+ params.seq = NULL;
+ params.seq_len = 0;
+ }
+
+ orinoco_unlock(priv, &lock);
+
+ callback(cookie, &params);
+
+ return err;
+}
+
+static int orinoco_del_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_index, const u8 *mac_addr)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int err = 0;
+ unsigned long lock;
+
+ if (key_index >= ORINOCO_MAX_KEYS)
+ return -EINVAL;
+
+ if (orinoco_lock(priv, &lock) != 0)
+ return -EBUSY;
+
+ kzfree(priv->keys[key_index].key);
+ kzfree(priv->keys[key_index].seq);
+ priv->keys[key_index].key = NULL;
+ priv->keys[key_index].seq = NULL;
+ priv->keys[key_index].key_len = 0;
+ priv->keys[key_index].seq_len = 0;
+ priv->keys[key_index].cipher = 0;
+
+ if (priv->has_wpa &&
+ priv->keys[key_index].cipher == WLAN_CIPHER_SUITE_TKIP) {
+ err = orinoco_clear_tkip_key(priv, key_index);
+
+ /* HACK */
+ if (key_index == priv->tx_key)
+ priv->wpa_enabled = 0;
+ }
+
+ err = __orinoco_hw_setup_enc(priv);
+
+ orinoco_unlock(priv, &lock);
+
+ return err;
+}
+
+static int orinoco_set_default_key(struct wiphy *wiphy,
+ struct net_device *netdev,
+ u8 key_index)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int err = 0;
+ unsigned long lock;
+
+ if (key_index >= ORINOCO_MAX_KEYS)
+ return -EINVAL;
+
+ if (orinoco_lock(priv, &lock) != 0)
+ return -EBUSY;
+
+ priv->tx_key = key_index;
+
+ if (priv->has_wpa &&
+ priv->keys[key_index].cipher == WLAN_CIPHER_SUITE_TKIP)
+ err = __orinoco_hw_set_tkip_key(priv, key_index, 1,
+ priv->keys[key_index].key,
+ priv->keys[key_index].seq,
+ priv->keys[key_index].seq_len,
+ NULL, 0);
+ else if (priv->encode_alg == ORINOCO_ALG_WEP)
+ err = __orinoco_hw_setup_wepkeys(priv);
+ else
+ err = -EINVAL;
+
+ orinoco_unlock(priv, &lock);
+
+ return err;
+}
+
const struct cfg80211_ops orinoco_cfg_ops = {
.change_virtual_intf = orinoco_change_vif,
.scan = orinoco_scan,
@@ -446,4 +641,8 @@ const struct cfg80211_ops orinoco_cfg_ops = {
.disconnect = orinoco_disconnect,
.join_ibss = orinoco_join_ibss,
.leave_ibss = orinoco_leave_ibss,
+ .add_key = orinoco_add_key,
+ .get_key = orinoco_get_key,
+ .del_key = orinoco_del_key,
+ .set_default_key = orinoco_set_default_key,
};
--
1.6.3.3


2009-08-07 21:50:25

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 0/4] orinoco: use cfg80211 for key manipulation

On Fri, 2009-08-07 at 22:38 +0100, Dave wrote:

> Just tried wpa_supplicant in nl80211 mode. In that case, it's stuck in
> scanning (presumably ignoring my ap_scan setting). It's not seeing my AP
> (because it's hidden?), and so doesn't proceed. And I can't seem to get
> it to do an active scan for my AP.

(just quickly skimmed this thread, will reply in more detail tomorrow if
there's still a need)

You can put scan_ssid=1 into a network block to make it scan for the
SSID.

johannes


Attachments:
signature.asc (801.00 B)
This is a digitally signed message part

2009-08-07 21:24:00

by Dan Williams

[permalink] [raw]
Subject: Re: [RFC 0/4] orinoco: use cfg80211 for key manipulation

On Fri, 2009-08-07 at 21:42 +0100, Dave wrote:
> David Kilroy wrote:
> > First attempt at connect/disconnect, join_ibss/leave_ibss, and add_key
> > etc. These patches rely on the series I just sent, but conflict with
> > Holgers set_channel patch. Simple to resolve, and I'll do that in my
> > next update.
> >
> > This doesn't work yet*, but I've a number of questions.
>
> FYI, I've got this kinda working with wpa_supplicant in wext mode.
>
> First: on it's own wpa_supplicant keeps doing the 4 way handshake, while
> cfg80211 pumps out the following:
>
> ------------[ cut here ]------------
> WARNING: at net/wireless/sme.c:451 __cfg80211_roamed+0x9a/0x1a5 [cfg80211]()
> Hardware name: Latitude C600
> Modules linked in: orinoco_cs orinoco cfg80211 michael_mic snd_maestro3
> aty128fb [last unloaded: cfg80211]
> Pid: 5, comm: events/0 Tainted: G M W 2.6.31-rc4-wl #87
> Call Trace:
> [<c101ca51>] warn_slowpath_common+0x60/0x90
> [<c101ca8e>] warn_slowpath_null+0xd/0x10
> [<d1521659>] __cfg80211_roamed+0x9a/0x1a5 [cfg80211]
> [<d15139a9>] cfg80211_event_work+0x104/0x1bc [cfg80211]
> [<c102b39c>] worker_thread+0x15e/0x208
> [<d15138a5>] ? cfg80211_event_work+0x0/0x1bc [cfg80211]
> [<c102e5d5>] ? autoremove_wake_function+0x0/0x33
> [<c102b23e>] ? worker_thread+0x0/0x208
> [<c102e261>] kthread+0x66/0x6b
> [<c102e1fb>] ? kthread+0x0/0x6b
> [<c1003053>] kernel_thread_helper+0x7/0x10
> ---[ end trace 12e5dbe2024c37ae ]---
>
> Cfg80211 is trying to select the bss we've authenticated against.
> Unfortunately the BSS list is empty.
>
> If before starting wpa_supplicant I run:
>
> iw dev eth1 scan ssid <SSID>
>
> Then wpa_supplicant connects fine. The AP in question is configured with
> a hidden SSID.
>
> Any suggestions as to how I need to address this?

Do a scan before you try to associate? Most fullmac cards do one
internally in the firmware before they try to associate anyway, but they
may not emit the event to the driver. If you're not doing a scan when
you get the associate request, you probably should do one, let cfg80211
cache the bss list, and then you're fine, right?

Dan



2009-08-05 20:33:16

by Dave Kilroy

[permalink] [raw]
Subject: [RFC 4/4] orinoco: do WE via cfg80211

Now that the driver supports both station and ad-hoc modes in cfg80211,
we can point the WE handlers at the cfg80211 versions.

Signed-off-by: David Kilroy <[email protected]>
---
drivers/net/wireless/orinoco/wext.c | 726 +----------------------------------
1 files changed, 11 insertions(+), 715 deletions(-)

diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index 3e56f76..e72b6b1 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -22,67 +22,6 @@

#define MAX_RID_LEN 1024

-/* Helper routine to record keys
- * Do not call from interrupt context */
-static int orinoco_set_key(struct orinoco_private *priv, int index,
- enum orinoco_alg alg, const u8 *key, int key_len,
- const u8 *seq, int seq_len)
-{
- kzfree(priv->keys[index].key);
- kzfree(priv->keys[index].seq);
-
- if (key_len) {
- priv->keys[index].key = kzalloc(key_len, GFP_KERNEL);
- if (!priv->keys[index].key)
- goto nomem;
- } else
- priv->keys[index].key = NULL;
-
- if (seq_len) {
- priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL);
- if (!priv->keys[index].seq)
- goto free_key;
- } else
- priv->keys[index].seq = NULL;
-
- priv->keys[index].key_len = key_len;
- priv->keys[index].seq_len = seq_len;
-
- if (key_len)
- memcpy(priv->keys[index].key, key, key_len);
- if (seq_len)
- memcpy(priv->keys[index].seq, seq, seq_len);
-
- switch (alg) {
- case ORINOCO_ALG_TKIP:
- priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP;
- break;
-
- case ORINOCO_ALG_WEP:
- priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ?
- WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40;
- break;
-
- case ORINOCO_ALG_NONE:
- default:
- priv->keys[index].cipher = 0;
- break;
- }
-
- return 0;
-
-free_key:
- kfree(priv->keys[index].key);
- priv->keys[index].key = NULL;
-
-nomem:
- priv->keys[index].key_len = 0;
- priv->keys[index].seq_len = 0;
- priv->keys[index].cipher = 0;
-
- return -ENOMEM;
-}
-
static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
{
struct orinoco_private *priv = ndev_priv(dev);
@@ -149,274 +88,6 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
/* Wireless extensions */
/********************************************************************/

-static int orinoco_ioctl_setwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *ap_addr,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int err = -EINPROGRESS; /* Call commit handler */
- unsigned long flags;
- static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Enable automatic roaming - no sanity checks are needed */
- if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 ||
- memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) {
- priv->bssid_fixed = 0;
- memset(priv->desired_bssid, 0, ETH_ALEN);
-
- /* "off" means keep existing connection */
- if (ap_addr->sa_data[0] == 0) {
- __orinoco_hw_set_wap(priv);
- err = 0;
- }
- goto out;
- }
-
- if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
- printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
- "support manual roaming\n",
- dev->name);
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (priv->iw_mode != NL80211_IFTYPE_STATION) {
- printk(KERN_WARNING "%s: Manual roaming supported only in "
- "managed mode\n", dev->name);
- err = -EOPNOTSUPP;
- goto out;
- }
-
- /* Intersil firmware hangs without Desired ESSID */
- if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
- strlen(priv->desired_essid) == 0) {
- printk(KERN_WARNING "%s: Desired ESSID must be set for "
- "manual roaming\n", dev->name);
- err = -EOPNOTSUPP;
- goto out;
- }
-
- /* Finally, enable manual roaming */
- priv->bssid_fixed = 1;
- memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
-
- out:
- orinoco_unlock(priv, &flags);
- return err;
-}
-
-static int orinoco_ioctl_getwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *ap_addr,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
-
- int err = 0;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- ap_addr->sa_family = ARPHRD_ETHER;
- err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data);
-
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_setiwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq,
- char *keybuf)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int index = (erq->flags & IW_ENCODE_INDEX) - 1;
- int setindex = priv->tx_key;
- enum orinoco_alg encode_alg = priv->encode_alg;
- int restricted = priv->wep_restrict;
- int err = -EINPROGRESS; /* Call commit handler */
- unsigned long flags;
-
- if (!priv->has_wep)
- return -EOPNOTSUPP;
-
- if (erq->pointer) {
- /* We actually have a key to set - check its length */
- if (erq->length > LARGE_KEY_SIZE)
- return -E2BIG;
-
- if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep)
- return -E2BIG;
- }
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Clear any TKIP key we have */
- if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP))
- (void) orinoco_clear_tkip_key(priv, setindex);
-
- if (erq->length > 0) {
- if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
- index = priv->tx_key;
-
- /* Switch on WEP if off */
- if (encode_alg != ORINOCO_ALG_WEP) {
- setindex = index;
- encode_alg = ORINOCO_ALG_WEP;
- }
- } else {
- /* Important note : if the user do "iwconfig eth0 enc off",
- * we will arrive there with an index of -1. This is valid
- * but need to be taken care off... Jean II */
- if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
- if ((index != -1) || (erq->flags == 0)) {
- err = -EINVAL;
- goto out;
- }
- } else {
- /* Set the index : Check that the key is valid */
- if (priv->keys[index].key_len == 0) {
- err = -EINVAL;
- goto out;
- }
- setindex = index;
- }
- }
-
- if (erq->flags & IW_ENCODE_DISABLED)
- encode_alg = ORINOCO_ALG_NONE;
- if (erq->flags & IW_ENCODE_OPEN)
- restricted = 0;
- if (erq->flags & IW_ENCODE_RESTRICTED)
- restricted = 1;
-
- if (erq->pointer && erq->length > 0) {
- err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf,
- erq->length, NULL, 0);
- }
- priv->tx_key = setindex;
-
- /* Try fast key change if connected and only keys are changed */
- if ((priv->encode_alg == encode_alg) &&
- (priv->wep_restrict == restricted) &&
- netif_carrier_ok(dev)) {
- err = __orinoco_hw_setup_wepkeys(priv);
- /* No need to commit if successful */
- goto out;
- }
-
- priv->encode_alg = encode_alg;
- priv->wep_restrict = restricted;
-
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_getiwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq,
- char *keybuf)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int index = (erq->flags & IW_ENCODE_INDEX) - 1;
- unsigned long flags;
-
- if (!priv->has_wep)
- return -EOPNOTSUPP;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
- index = priv->tx_key;
-
- erq->flags = 0;
- if (!priv->encode_alg)
- erq->flags |= IW_ENCODE_DISABLED;
- erq->flags |= index + 1;
-
- if (priv->wep_restrict)
- erq->flags |= IW_ENCODE_RESTRICTED;
- else
- erq->flags |= IW_ENCODE_OPEN;
-
- erq->length = priv->keys[index].key_len;
-
- memcpy(keybuf, priv->keys[index].key, erq->length);
-
- orinoco_unlock(priv, &flags);
- return 0;
-}
-
-static int orinoco_ioctl_setessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq,
- char *essidbuf)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- unsigned long flags;
-
- /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
- * anyway... - Jean II */
-
- /* Hum... Should not use Wireless Extension constant (may change),
- * should use our own... - Jean II */
- if (erq->length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
- memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
-
- /* If not ANY, get the new ESSID */
- if (erq->flags)
- memcpy(priv->desired_essid, essidbuf, erq->length);
-
- orinoco_unlock(priv, &flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int orinoco_ioctl_getessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq,
- char *essidbuf)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int active;
- int err = 0;
- unsigned long flags;
-
- if (netif_running(dev)) {
- err = orinoco_hw_get_essid(priv, &active, essidbuf);
- if (err < 0)
- return err;
- erq->length = err;
- } else {
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE);
- erq->length = strlen(priv->desired_essid);
- orinoco_unlock(priv, &flags);
- }
-
- erq->flags = 1;
-
- return 0;
-}
-
static int orinoco_ioctl_setfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *frq,
@@ -827,379 +498,6 @@ static int orinoco_ioctl_getpower(struct net_device *dev,
return err;
}

-static int orinoco_ioctl_set_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int idx, alg = ext->alg, set_key = 1;
- unsigned long flags;
- int err = -EINVAL;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Determine and validate the key index */
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if ((idx < 1) || (idx > 4))
- goto out;
- idx--;
- } else
- idx = priv->tx_key;
-
- if (encoding->flags & IW_ENCODE_DISABLED)
- alg = IW_ENCODE_ALG_NONE;
-
- if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
- /* Clear any TKIP TX key we had */
- (void) orinoco_clear_tkip_key(priv, priv->tx_key);
- }
-
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- priv->tx_key = idx;
- set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
- (ext->key_len > 0)) ? 1 : 0;
- }
-
- if (set_key) {
- /* Set the requested key first */
- switch (alg) {
- case IW_ENCODE_ALG_NONE:
- priv->encode_alg = ORINOCO_ALG_NONE;
- err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE,
- NULL, 0, NULL, 0);
- break;
-
- case IW_ENCODE_ALG_WEP:
- if (ext->key_len <= 0)
- goto out;
-
- priv->encode_alg = ORINOCO_ALG_WEP;
- err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP,
- ext->key, ext->key_len, NULL, 0);
- break;
-
- case IW_ENCODE_ALG_TKIP:
- {
- u8 *tkip_iv = NULL;
-
- if (!priv->has_wpa ||
- (ext->key_len > sizeof(struct orinoco_tkip_key)))
- goto out;
-
- priv->encode_alg = ORINOCO_ALG_TKIP;
-
- if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
- tkip_iv = &ext->rx_seq[0];
-
- err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP,
- ext->key, ext->key_len, tkip_iv,
- ORINOCO_SEQ_LEN);
-
- err = __orinoco_hw_set_tkip_key(priv, idx,
- ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
- priv->keys[idx].key,
- tkip_iv, ORINOCO_SEQ_LEN, NULL, 0);
- if (err)
- printk(KERN_ERR "%s: Error %d setting TKIP key"
- "\n", dev->name, err);
-
- goto out;
- }
- default:
- goto out;
- }
- }
- err = -EINPROGRESS;
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_get_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int idx, max_key_len;
- unsigned long flags;
- int err;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = -EINVAL;
- max_key_len = encoding->length - sizeof(*ext);
- if (max_key_len < 0)
- goto out;
-
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if ((idx < 1) || (idx > 4))
- goto out;
- idx--;
- } else
- idx = priv->tx_key;
-
- encoding->flags = idx + 1;
- memset(ext, 0, sizeof(*ext));
-
- switch (priv->encode_alg) {
- case ORINOCO_ALG_NONE:
- ext->alg = IW_ENCODE_ALG_NONE;
- ext->key_len = 0;
- encoding->flags |= IW_ENCODE_DISABLED;
- break;
- case ORINOCO_ALG_WEP:
- ext->alg = IW_ENCODE_ALG_WEP;
- ext->key_len = min(priv->keys[idx].key_len, max_key_len);
- memcpy(ext->key, priv->keys[idx].key, ext->key_len);
- encoding->flags |= IW_ENCODE_ENABLED;
- break;
- case ORINOCO_ALG_TKIP:
- ext->alg = IW_ENCODE_ALG_TKIP;
- ext->key_len = min(priv->keys[idx].key_len, max_key_len);
- memcpy(ext->key, priv->keys[idx].key, ext->key_len);
- encoding->flags |= IW_ENCODE_ENABLED;
- break;
- }
-
- err = 0;
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- hermes_t *hw = &priv->hw;
- struct iw_param *param = &wrqu->param;
- unsigned long flags;
- int ret = -EINPROGRESS;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- case IW_AUTH_PRIVACY_INVOKED:
- case IW_AUTH_DROP_UNENCRYPTED:
- /*
- * orinoco does not use these parameters
- */
- break;
-
- case IW_AUTH_KEY_MGMT:
- /* wl_lkm implies value 2 == PSK for Hermes I
- * which ties in with WEXT
- * no other hints tho :(
- */
- priv->key_mgmt = param->value;
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- /* When countermeasures are enabled, shut down the
- * card; when disabled, re-enable the card. This must
- * take effect immediately.
- *
- * TODO: Make sure that the EAPOL message is getting
- * out before card disabled
- */
- if (param->value) {
- priv->tkip_cm_active = 1;
- ret = hermes_enable_port(hw, 0);
- } else {
- priv->tkip_cm_active = 0;
- ret = hermes_disable_port(hw, 0);
- }
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- if (param->value & IW_AUTH_ALG_SHARED_KEY)
- priv->wep_restrict = 1;
- else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
- priv->wep_restrict = 0;
- else
- ret = -EINVAL;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- if (priv->has_wpa) {
- priv->wpa_enabled = param->value ? 1 : 0;
- } else {
- if (param->value)
- ret = -EOPNOTSUPP;
- /* else silently accept disable of WPA */
- priv->wpa_enabled = 0;
- }
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- orinoco_unlock(priv, &flags);
- return ret;
-}
-
-static int orinoco_ioctl_get_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct iw_param *param = &wrqu->param;
- unsigned long flags;
- int ret = 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_KEY_MGMT:
- param->value = priv->key_mgmt;
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- param->value = priv->tkip_cm_active;
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- if (priv->wep_restrict)
- param->value = IW_AUTH_ALG_SHARED_KEY;
- else
- param->value = IW_AUTH_ALG_OPEN_SYSTEM;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- param->value = priv->wpa_enabled;
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- orinoco_unlock(priv, &flags);
- return ret;
-}
-
-static int orinoco_ioctl_set_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- u8 *buf;
- unsigned long flags;
-
- /* cut off at IEEE80211_MAX_DATA_LEN */
- if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
- (wrqu->data.length && (extra == NULL)))
- return -EINVAL;
-
- if (wrqu->data.length) {
- buf = kmalloc(wrqu->data.length, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- memcpy(buf, extra, wrqu->data.length);
- } else
- buf = NULL;
-
- if (orinoco_lock(priv, &flags) != 0) {
- kfree(buf);
- return -EBUSY;
- }
-
- kfree(priv->wpa_ie);
- priv->wpa_ie = buf;
- priv->wpa_ie_len = wrqu->data.length;
-
- if (priv->wpa_ie) {
- /* Looks like wl_lkm wants to check the auth alg, and
- * somehow pass it to the firmware.
- * Instead it just calls the key mgmt rid
- * - we do this in set auth.
- */
- }
-
- orinoco_unlock(priv, &flags);
- return 0;
-}
-
-static int orinoco_ioctl_get_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- unsigned long flags;
- int err = 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
- wrqu->data.length = 0;
- goto out;
- }
-
- if (wrqu->data.length < priv->wpa_ie_len) {
- err = -E2BIG;
- goto out;
- }
-
- wrqu->data.length = priv->wpa_ie_len;
- memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
-
-out:
- orinoco_unlock(priv, &flags);
- return err;
-}
-
-static int orinoco_ioctl_set_mlme(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct iw_mlme *mlme = (struct iw_mlme *)extra;
- unsigned long flags;
- int ret = 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- /* silently ignore */
- break;
-
- case IW_MLME_DISASSOC:
-
- ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data,
- mlme->reason_code);
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- orinoco_unlock(priv, &flags);
- return ret;
-}
-
static int orinoco_ioctl_getretry(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rrq,
@@ -1521,12 +819,12 @@ static const iw_handler orinoco_handler[] = {
STD_IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
STD_IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
STD_IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
- STD_IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap),
- STD_IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap),
+ STD_IW_HANDLER(SIOCSIWAP, cfg80211_wext_siwap),
+ STD_IW_HANDLER(SIOCGIWAP, cfg80211_wext_giwap),
STD_IW_HANDLER(SIOCSIWSCAN, cfg80211_wext_siwscan),
STD_IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan),
- STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid),
- STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid),
+ STD_IW_HANDLER(SIOCSIWESSID, cfg80211_wext_siwessid),
+ STD_IW_HANDLER(SIOCGIWESSID, cfg80211_wext_giwessid),
STD_IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate),
STD_IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate),
STD_IW_HANDLER(SIOCSIWRTS, orinoco_ioctl_setrts),
@@ -1534,17 +832,15 @@ static const iw_handler orinoco_handler[] = {
STD_IW_HANDLER(SIOCSIWFRAG, orinoco_ioctl_setfrag),
STD_IW_HANDLER(SIOCGIWFRAG, orinoco_ioctl_getfrag),
STD_IW_HANDLER(SIOCGIWRETRY, orinoco_ioctl_getretry),
- STD_IW_HANDLER(SIOCSIWENCODE, orinoco_ioctl_setiwencode),
- STD_IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode),
+ STD_IW_HANDLER(SIOCSIWENCODE, cfg80211_wext_siwencode),
+ STD_IW_HANDLER(SIOCGIWENCODE, cfg80211_wext_giwencode),
STD_IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower),
STD_IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower),
- STD_IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie),
- STD_IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie),
- STD_IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme),
- STD_IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth),
- STD_IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth),
- STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext),
- STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext),
+ STD_IW_HANDLER(SIOCSIWGENIE, cfg80211_wext_siwgenie),
+ STD_IW_HANDLER(SIOCSIWMLME, cfg80211_wext_siwmlme),
+ STD_IW_HANDLER(SIOCSIWAUTH, cfg80211_wext_siwauth),
+ STD_IW_HANDLER(SIOCGIWAUTH, cfg80211_wext_giwauth),
+ STD_IW_HANDLER(SIOCSIWENCODEEXT, cfg80211_wext_siwencodeext),
};


--
1.6.3.3


2009-08-07 21:38:32

by Dave Kilroy

[permalink] [raw]
Subject: Re: [RFC 0/4] orinoco: use cfg80211 for key manipulation

Dan Williams wrote:
> On Fri, 2009-08-07 at 21:42 +0100, Dave wrote:
>> David Kilroy wrote:
>>> First attempt at connect/disconnect, join_ibss/leave_ibss, and add_key
>>> etc. These patches rely on the series I just sent, but conflict with
>>> Holgers set_channel patch. Simple to resolve, and I'll do that in my
>>> next update.
>>>
>>> This doesn't work yet*, but I've a number of questions.
>> FYI, I've got this kinda working with wpa_supplicant in wext mode.
>>
>> First: on it's own wpa_supplicant keeps doing the 4 way handshake, while
>> cfg80211 pumps out the following:
>>
>> ------------[ cut here ]------------
>> WARNING: at net/wireless/sme.c:451 __cfg80211_roamed+0x9a/0x1a5 [cfg80211]()
>> Hardware name: Latitude C600
>> Modules linked in: orinoco_cs orinoco cfg80211 michael_mic snd_maestro3
>> aty128fb [last unloaded: cfg80211]
>> Pid: 5, comm: events/0 Tainted: G M W 2.6.31-rc4-wl #87
>> Call Trace:
>> [<c101ca51>] warn_slowpath_common+0x60/0x90
>> [<c101ca8e>] warn_slowpath_null+0xd/0x10
>> [<d1521659>] __cfg80211_roamed+0x9a/0x1a5 [cfg80211]
>> [<d15139a9>] cfg80211_event_work+0x104/0x1bc [cfg80211]
>> [<c102b39c>] worker_thread+0x15e/0x208
>> [<d15138a5>] ? cfg80211_event_work+0x0/0x1bc [cfg80211]
>> [<c102e5d5>] ? autoremove_wake_function+0x0/0x33
>> [<c102b23e>] ? worker_thread+0x0/0x208
>> [<c102e261>] kthread+0x66/0x6b
>> [<c102e1fb>] ? kthread+0x0/0x6b
>> [<c1003053>] kernel_thread_helper+0x7/0x10
>> ---[ end trace 12e5dbe2024c37ae ]---
>>
>> Cfg80211 is trying to select the bss we've authenticated against.
>> Unfortunately the BSS list is empty.
>>
>> If before starting wpa_supplicant I run:
>>
>> iw dev eth1 scan ssid <SSID>
>>
>> Then wpa_supplicant connects fine. The AP in question is configured with
>> a hidden SSID.
>>
>> Any suggestions as to how I need to address this?
>
> Do a scan before you try to associate? Most fullmac cards do one
> internally in the firmware before they try to associate anyway, but they
> may not emit the event to the driver. If you're not doing a scan when
> you get the associate request, you probably should do one, let cfg80211
> cache the bss list, and then you're fine, right?

That should work. I just realised why it's doing this. I have
wpa_supplicant configured with ap_scan=2, so it doesn't scan before
connecting.

Just tried wpa_supplicant in nl80211 mode. In that case, it's stuck in
scanning (presumably ignoring my ap_scan setting). It's not seeing my AP
(because it's hidden?), and so doesn't proceed. And I can't seem to get
it to do an active scan for my AP.


Dave.