]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/atmel.c
Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / atmel.c
index 050aa518d7d1473ce595ec3220786d212c0a0037..98a76f10a0f71f29f09ef031b000659dbbccb09c 100644 (file)
@@ -1407,6 +1407,17 @@ static int atmel_close(struct net_device *dev)
 {
        struct atmel_private *priv = netdev_priv(dev);
 
+       /* Send event to userspace that we are disassociating */
+       if (priv->station_state == STATION_STATE_READY) {
+               union iwreq_data wrqu;
+
+               wrqu.data.length = 0;
+               wrqu.data.flags = 0;
+               wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+               memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+               wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+       }
+
        atmel_enter_state(priv, STATION_STATE_DOWN);
 
        if (priv->bus_type == BUS_TYPE_PCCARD)
@@ -1511,6 +1522,7 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
                                   struct device *sys_dev,
                                   int (*card_present)(void *), void *card)
 {
+       struct proc_dir_entry *ent;
        struct net_device *dev;
        struct atmel_private *priv;
        int rc;
@@ -1624,7 +1636,9 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
 
        netif_carrier_off(dev);
 
-       create_proc_read_entry ("driver/atmel", 0, NULL, atmel_read_proc, priv);
+       ent = create_proc_read_entry ("driver/atmel", 0, NULL, atmel_read_proc, priv);
+       if (!ent)
+               printk(KERN_WARNING "atmel: unable to create /proc entry.\n");
 
        printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
               dev->name, DRIVER_MAJOR, DRIVER_MINOR,
@@ -1704,11 +1718,11 @@ static int atmel_get_essid(struct net_device *dev,
        if (priv->new_SSID_size != 0) {
                memcpy(extra, priv->new_SSID, priv->new_SSID_size);
                extra[priv->new_SSID_size] = '\0';
-               dwrq->length = priv->new_SSID_size + 1;
+               dwrq->length = priv->new_SSID_size;
        } else {
                memcpy(extra, priv->SSID, priv->SSID_size);
                extra[priv->SSID_size] = '\0';
-               dwrq->length = priv->SSID_size + 1;
+               dwrq->length = priv->SSID_size;
        }
 
        dwrq->flags = !priv->connect_to_any_BSS; /* active */
@@ -1777,10 +1791,10 @@ static int atmel_set_encode(struct net_device *dev,
                        priv->wep_is_on = 1;
                        priv->exclude_unencrypted = 1;
                        if (priv->wep_key_len[index] > 5) {
-                               priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64;
+                               priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128;
                                priv->encryption_level = 2;
                        } else {
-                               priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128;
+                               priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64;
                                priv->encryption_level = 1;
                        }
                }
@@ -1850,6 +1864,181 @@ static int atmel_get_encode(struct net_device *dev,
        return 0;
 }
 
+static int atmel_set_encodeext(struct net_device *dev,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu,
+                           char *extra)
+{
+       struct atmel_private *priv = netdev_priv(dev);
+       struct iw_point *encoding = &wrqu->encoding;
+       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+       int idx, key_len;
+
+       /* Determine and validate the key index */
+       idx = encoding->flags & IW_ENCODE_INDEX;
+       if (idx) {
+               if (idx < 1 || idx > WEP_KEYS)
+                       return -EINVAL;
+               idx--;
+       } else
+               idx = priv->default_key;
+
+       if ((encoding->flags & IW_ENCODE_DISABLED) ||
+           ext->alg == IW_ENCODE_ALG_NONE) {
+               priv->wep_is_on = 0;
+               priv->encryption_level = 0;
+               priv->pairwise_cipher_suite = CIPHER_SUITE_NONE;
+       }
+
+       if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+               priv->default_key = idx;
+
+       /* Set the requested key */
+       switch (ext->alg) {
+       case IW_ENCODE_ALG_NONE:
+               break;
+       case IW_ENCODE_ALG_WEP:
+               if (ext->key_len > 5) {
+                       priv->wep_key_len[idx] = 13;
+                       priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128;
+                       priv->encryption_level = 2;
+               } else if (ext->key_len > 0) {
+                       priv->wep_key_len[idx] = 5;
+                       priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64;
+                       priv->encryption_level = 1;
+               } else {
+                       return -EINVAL;
+               }
+               priv->wep_is_on = 1;
+               memset(priv->wep_keys[idx], 0, 13);
+               key_len = min ((int)ext->key_len, priv->wep_key_len[idx]);
+               memcpy(priv->wep_keys[idx], ext->key, key_len);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return -EINPROGRESS;
+}
+
+static int atmel_get_encodeext(struct net_device *dev,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu,
+                           char *extra)
+{
+       struct atmel_private *priv = netdev_priv(dev);
+       struct iw_point *encoding = &wrqu->encoding;
+       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+       int idx, max_key_len;
+
+       max_key_len = encoding->length - sizeof(*ext);
+       if (max_key_len < 0)
+               return -EINVAL;
+
+       idx = encoding->flags & IW_ENCODE_INDEX;
+       if (idx) {
+               if (idx < 1 || idx > WEP_KEYS)
+                       return -EINVAL;
+               idx--;
+       } else
+               idx = priv->default_key;
+
+       encoding->flags = idx + 1;
+       memset(ext, 0, sizeof(*ext));
+       
+       if (!priv->wep_is_on) {
+               ext->alg = IW_ENCODE_ALG_NONE;
+               ext->key_len = 0;
+               encoding->flags |= IW_ENCODE_DISABLED;
+       } else {
+               if (priv->encryption_level > 0)
+                       ext->alg = IW_ENCODE_ALG_WEP;
+               else
+                       return -EINVAL;
+
+               ext->key_len = priv->wep_key_len[idx];
+               memcpy(ext->key, priv->wep_keys[idx], ext->key_len);
+               encoding->flags |= IW_ENCODE_ENABLED;
+       }
+
+       return 0;
+}
+
+static int atmel_set_auth(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       struct atmel_private *priv = netdev_priv(dev);
+       struct iw_param *param = &wrqu->param;
+
+       switch (param->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_WPA_VERSION:
+       case IW_AUTH_CIPHER_PAIRWISE:
+       case IW_AUTH_CIPHER_GROUP:
+       case IW_AUTH_KEY_MGMT:
+       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+       case IW_AUTH_PRIVACY_INVOKED:
+               /*
+                * atmel does not use these parameters
+                */
+               break;
+
+       case IW_AUTH_DROP_UNENCRYPTED:
+               priv->exclude_unencrypted = param->value ? 1 : 0;
+               break;
+
+       case IW_AUTH_80211_AUTH_ALG: {
+                       if (param->value & IW_AUTH_ALG_SHARED_KEY) {
+                               priv->exclude_unencrypted = 1;
+                       } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
+                               priv->exclude_unencrypted = 0;
+                       } else
+                               return -EINVAL;
+                       break;
+               }
+
+       case IW_AUTH_WPA_ENABLED:
+               /* Silently accept disable of WPA */
+               if (param->value > 0)
+                       return -EOPNOTSUPP;
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+       return -EINPROGRESS;
+}
+
+static int atmel_get_auth(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       struct atmel_private *priv = netdev_priv(dev);
+       struct iw_param *param = &wrqu->param;
+
+       switch (param->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_DROP_UNENCRYPTED:
+               param->value = priv->exclude_unencrypted;
+               break;
+
+       case IW_AUTH_80211_AUTH_ALG:
+               if (priv->exclude_unencrypted == 1)
+                       param->value = IW_AUTH_ALG_SHARED_KEY;
+               else
+                       param->value = IW_AUTH_ALG_OPEN_SYSTEM;
+               break;
+
+       case IW_AUTH_WPA_ENABLED:
+               param->value = 0;
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+
 static int atmel_get_name(struct net_device *dev,
                          struct iw_request_info *info,
                          char *cwrq,
@@ -2286,13 +2475,15 @@ static int atmel_set_wap(struct net_device *dev,
 {
        struct atmel_private *priv = netdev_priv(dev);
        int i;
-       static const u8 bcast[] = { 255, 255, 255, 255, 255, 255 };
+       static const u8 any[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+       static const u8 off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
        unsigned long flags;
 
        if (awrq->sa_family != ARPHRD_ETHER)
                return -EINVAL;
 
-       if (memcmp(bcast, awrq->sa_data, 6) == 0) {
+       if (!memcmp(any, awrq->sa_data, 6) ||
+           !memcmp(off, awrq->sa_data, 6)) {
                del_timer_sync(&priv->management_timer);
                spin_lock_irqsave(&priv->irqlock, flags);
                atmel_scan(priv, 1);
@@ -2375,6 +2566,15 @@ static const iw_handler atmel_handler[] =
        (iw_handler) atmel_get_encode,          /* SIOCGIWENCODE */
        (iw_handler) atmel_set_power,           /* SIOCSIWPOWER */
        (iw_handler) atmel_get_power,           /* SIOCGIWPOWER */
+       (iw_handler) NULL,                      /* -- hole -- */
+       (iw_handler) NULL,                      /* -- hole -- */
+       (iw_handler) NULL,                      /* SIOCSIWGENIE */
+       (iw_handler) NULL,                      /* SIOCGIWGENIE */
+       (iw_handler) atmel_set_auth,            /* SIOCSIWAUTH */
+       (iw_handler) atmel_get_auth,            /* SIOCGIWAUTH */
+       (iw_handler) atmel_set_encodeext,       /* SIOCSIWENCODEEXT */
+       (iw_handler) atmel_get_encodeext,       /* SIOCGIWENCODEEXT */
+       (iw_handler) NULL,                      /* SIOCSIWPMKSA */
 };
 
 static const iw_handler atmel_private_handler[] =
@@ -2921,6 +3121,8 @@ static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype)
        u16 ass_id = le16_to_cpu(ass_resp->ass_id);
        u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length;
 
+       union iwreq_data wrqu;
+
        if (frame_len < 8 + rates_len)
                return;
 
@@ -2951,6 +3153,14 @@ static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype)
                priv->station_is_associated = 1;
                priv->station_was_associated = 1;
                atmel_enter_state(priv, STATION_STATE_READY);
+
+               /* Send association event to userspace */
+               wrqu.data.length = 0;
+               wrqu.data.flags = 0;
+               memcpy(wrqu.ap_addr.sa_data, priv->CurrentBSSID, ETH_ALEN);
+               wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+               wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+
                return;
        }
 
@@ -3629,6 +3839,7 @@ static int reset_atmel_card(struct net_device *dev)
 
        struct atmel_private *priv = netdev_priv(dev);
        u8 configuration;
+       int old_state = priv->station_state;
 
        /* data to add to the firmware names, in priority order
           this implemenents firmware versioning */
@@ -3789,6 +4000,17 @@ static int reset_atmel_card(struct net_device *dev)
        else
                build_wep_mib(priv);
 
+       if (old_state == STATION_STATE_READY)
+       {
+               union iwreq_data wrqu;
+
+               wrqu.data.length = 0;
+               wrqu.data.flags = 0;
+               wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+               memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+               wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+       }
+
        return 1;
 }