fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / wireless / prism54 / oid_mgt.c
index cfa541c..e6cf9df 100644 (file)
@@ -1,4 +1,4 @@
-/*   
+/*
  *  Copyright (C) 2003,2004 Aurelien Alleaume <slts@free.fr>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -16,6 +16,7 @@
  *
  */
 
+#include "prismcompat.h"
 #include "islpci_dev.h"
 #include "islpci_mgt.h"
 #include "isl_oid.h"
 #include "isl_ioctl.h"
 
 /* to convert between channel and freq */
-const int frequency_list_bg[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
-       2447, 2452, 2457, 2462, 2467, 2472, 2484
-};
-
-const int frequency_list_a[] = { 5170, 5180, 5190, 5200, 5210, 5220, 5230,
-       5240, 5260, 5280, 5300, 5320
+static const int frequency_list_bg[] = { 2412, 2417, 2422, 2427, 2432,
+       2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484
 };
 
 int
@@ -39,17 +36,11 @@ channel_of_freq(int f)
        if ((f >= 2412) && (f <= 2484)) {
                while ((c < 14) && (f != frequency_list_bg[c]))
                        c++;
-               if (c >= 14)
-                       return 0;
-       } else if ((f >= (int) 5170) && (f <= (int) 5320)) {
-               while ((c < 12) && (f != frequency_list_a[c]))
-                       c++;
-               if (c >= 12)
-                       return 0;
+               return (c >= 14) ? 0 : ++c;
+       } else if ((f >= (int) 5000) && (f <= (int) 6000)) {
+               return ( (f - 5000) / 5 );
        } else
                return 0;
-
-       return ++c;
 }
 
 #define OID_STRUCT(name,oid,s,t) [name] = {oid, 0, sizeof(s), t}
@@ -71,7 +62,7 @@ struct oid_t isl_oid[] = {
 
        /* 802.11 */
        OID_U32_C(DOT11_OID_BSSTYPE, 0x10000000),
-       OID_STRUCT_C(DOT11_OID_BSSID, 0x10000001, u8[6], OID_TYPE_SSID),
+       OID_STRUCT_C(DOT11_OID_BSSID, 0x10000001, u8[6], OID_TYPE_RAW),
        OID_STRUCT_C(DOT11_OID_SSID, 0x10000002, struct obj_ssid,
                     OID_TYPE_SSID),
        OID_U32(DOT11_OID_STATE, 0x10000003),
@@ -210,7 +201,8 @@ struct oid_t isl_oid[] = {
        OID_U32(DOT11_OID_STATIMEOUT, 0x19000000),
        OID_U32_C(DOT11_OID_MLMEAUTOLEVEL, 0x19000001),
        OID_U32(DOT11_OID_BSSTIMEOUT, 0x19000002),
-       OID_UNKNOWN(DOT11_OID_ATTACHMENT, 0x19000003),
+       [DOT11_OID_ATTACHMENT] = {0x19000003, 0,
+               sizeof(struct obj_attachment), OID_TYPE_ATTACH},
        OID_STRUCT_C(DOT11_OID_PSMBUFFER, 0x19000004, struct obj_buffer,
                     OID_TYPE_BUFFER),
 
@@ -228,7 +220,7 @@ struct oid_t isl_oid[] = {
        OID_UNKNOWN(OID_INL_MEMORY, 0xFF020002),
        OID_U32_C(OID_INL_MODE, 0xFF020003),
        OID_UNKNOWN(OID_INL_COMPONENT_NR, 0xFF020004),
-       OID_UNKNOWN(OID_INL_VERSION, 0xFF020005),
+       OID_STRUCT(OID_INL_VERSION, 0xFF020005, u8[8], OID_TYPE_RAW),
        OID_UNKNOWN(OID_INL_INTERFACE_ID, 0xFF020006),
        OID_UNKNOWN(OID_INL_COMPONENT_ID, 0xFF020007),
        OID_U32_C(OID_INL_CONFIG, 0xFF020008),
@@ -243,12 +235,10 @@ mgt_init(islpci_private *priv)
 {
        int i;
 
-       priv->mib = kmalloc(OID_NUM_LAST * sizeof (void *), GFP_KERNEL);
+       priv->mib = kcalloc(OID_NUM_LAST, sizeof (void *), GFP_KERNEL);
        if (!priv->mib)
                return -ENOMEM;
 
-       memset(priv->mib, 0, OID_NUM_LAST * sizeof (void *));
-
        /* Alloc the cache */
        for (i = 0; i < OID_NUM_LAST; i++) {
                if (isl_oid[i].flags & OID_FLAG_CACHED) {
@@ -276,11 +266,10 @@ mgt_clean(islpci_private *priv)
 
        if (!priv->mib)
                return;
-       for (i = 0; i < OID_NUM_LAST; i++)
-               if (priv->mib[i]) {
-                       kfree(priv->mib[i]);
-                       priv->mib[i] = NULL;
-               }
+       for (i = 0; i < OID_NUM_LAST; i++) {
+               kfree(priv->mib[i]);
+               priv->mib[i] = NULL;
+       }
        kfree(priv->mib);
        priv->mib = NULL;
 }
@@ -338,6 +327,12 @@ mgt_le_to_cpu(int type, void *data)
                        mlme->size = le16_to_cpu(mlme->size);
                        break;
                }
+       case OID_TYPE_ATTACH:{
+                       struct obj_attachment *attach = data;
+                       attach->id = le16_to_cpu(attach->id);
+                       attach->size = le16_to_cpu(attach->size);
+                       break;
+       }
        case OID_TYPE_SSID:
        case OID_TYPE_KEY:
        case OID_TYPE_ADDR:
@@ -401,6 +396,12 @@ mgt_cpu_to_le(int type, void *data)
                        mlme->size = cpu_to_le16(mlme->size);
                        break;
                }
+       case OID_TYPE_ATTACH:{
+                       struct obj_attachment *attach = data;
+                       attach->id = cpu_to_le16(attach->id);
+                       attach->size = cpu_to_le16(attach->size);
+                       break;
+       }
        case OID_TYPE_SSID:
        case OID_TYPE_KEY:
        case OID_TYPE_ADDR:
@@ -417,7 +418,7 @@ int
 mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data)
 {
        int ret = 0;
-       struct islpci_mgmtframe *response;
+       struct islpci_mgmtframe *response = NULL;
        int response_op = PIMFOR_OP_ERROR;
        int dlen;
        void *cache, *_data = data;
@@ -449,7 +450,7 @@ mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data)
        if (cache)
                down_write(&priv->mib_sem);
 
-       if (islpci_get_state(priv) >= PRV_STATE_INIT) {
+       if (islpci_get_state(priv) >= PRV_STATE_READY) {
                ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid,
                                             _data, dlen, &response);
                if (!ret) {
@@ -457,7 +458,7 @@ mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data)
                        islpci_mgt_release(response);
                }
                if (ret || response_op == PIMFOR_OP_ERROR)
-                       ret = -EIO;
+                       ret = -EIO;
        } else if (!cache)
                ret = -EIO;
 
@@ -474,6 +475,42 @@ mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data)
        return ret;
 }
 
+/* None of these are cached */
+int
+mgt_set_varlen(islpci_private *priv, enum oid_num_t n, void *data, int extra_len)
+{
+       int ret = 0;
+       struct islpci_mgmtframe *response;
+       int response_op = PIMFOR_OP_ERROR;
+       int dlen;
+       u32 oid;
+
+       BUG_ON(OID_NUM_LAST <= n);
+
+       dlen = isl_oid[n].size;
+       oid = isl_oid[n].oid;
+
+       mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, data);
+
+       if (islpci_get_state(priv) >= PRV_STATE_READY) {
+               ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid,
+                                            data, dlen + extra_len, &response);
+               if (!ret) {
+                       response_op = response->header->operation;
+                       islpci_mgt_release(response);
+               }
+               if (ret || response_op == PIMFOR_OP_ERROR)
+                       ret = -EIO;
+       } else
+               ret = -EIO;
+
+       /* re-set given data to what it was */
+       if (data)
+               mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data);
+
+       return ret;
+}
+
 int
 mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data,
                union oid_res_t *res)
@@ -482,7 +519,7 @@ mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data,
        int ret = -EIO;
        int reslen = 0;
        struct islpci_mgmtframe *response = NULL;
-       
+
        int dlen;
        void *cache, *_res = NULL;
        u32 oid;
@@ -490,6 +527,8 @@ mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data,
        BUG_ON(OID_NUM_LAST <= n);
        BUG_ON(extra > isl_oid[n].range);
 
+       res->ptr = NULL;
+
        if (!priv->mib)
                /* memory has been freed */
                return -1;
@@ -503,11 +542,11 @@ mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data,
        if (cache)
                down_read(&priv->mib_sem);
 
-       if (islpci_get_state(priv) >= PRV_STATE_INIT) {
+       if (islpci_get_state(priv) >= PRV_STATE_READY) {
                ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
                                             oid, data, dlen, &response);
                if (ret || !response ||
-                       response->header->operation == PIMFOR_OP_ERROR) {
+                   response->header->operation == PIMFOR_OP_ERROR) {
                        if (response)
                                islpci_mgt_release(response);
                        ret = -EIO;
@@ -542,9 +581,9 @@ mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data,
        if (reslen > isl_oid[n].size)
                printk(KERN_DEBUG
                       "mgt_get_request(0x%x): received data length was bigger "
-                      "than expected (%d > %d). Memory is probably corrupted... ",
+                      "than expected (%d > %d). Memory is probably corrupted...",
                       oid, reslen, isl_oid[n].size);
-       
+
        return ret;
 }
 
@@ -562,15 +601,18 @@ mgt_commit_list(islpci_private *priv, enum oid_num_t *l, int n)
                u32 oid = t->oid;
                BUG_ON(data == NULL);
                while (j <= t->range) {
-                       response = NULL;
-                       ret |= islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
-                                                     oid, data, t->size,
+                       int r = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
+                                                     oid, data, t->size,
                                                      &response);
                        if (response) {
-                               ret |= (response->header->operation ==
-                                       PIMFOR_OP_ERROR);
+                               r |= (response->header->operation == PIMFOR_OP_ERROR);
                                islpci_mgt_release(response);
                        }
+                       if (r)
+                               printk(KERN_ERR "%s: mgt_commit_list: failure. "
+                                       "oid=%08x err=%d\n",
+                                       priv->ndev->name, oid, r);
+                       ret |= r;
                        j++;
                        oid++;
                        data += t->size;
@@ -622,50 +664,101 @@ static enum oid_num_t commit_part2[] = {
        DOT11_OID_DEFKEYID,
        DOT11_OID_DOT1XENABLE,
        OID_INL_DOT11D_CONFORMANCE,
+       /* Do not initialize this - fw < 1.0.4.3 rejects it
        OID_INL_OUTPUTPOWER,
+       */
 };
 
-void
+/* update the MAC addr. */
+static int
+mgt_update_addr(islpci_private *priv)
+{
+       struct islpci_mgmtframe *res;
+       int ret;
+
+       ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
+                                    isl_oid[GEN_OID_MACADDRESS].oid, NULL,
+                                    isl_oid[GEN_OID_MACADDRESS].size, &res);
+
+       if ((ret == 0) && res && (res->header->operation != PIMFOR_OP_ERROR))
+               memcpy(priv->ndev->dev_addr, res->data, 6);
+       else
+               ret = -EIO;
+       if (res)
+               islpci_mgt_release(res);
+
+       if (ret)
+               printk(KERN_ERR "%s: mgt_update_addr: failure\n", priv->ndev->name);
+       return ret;
+}
+
+#define VEC_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+int
 mgt_commit(islpci_private *priv)
 {
        int rvalue;
        u32 u;
-       union oid_res_t r;
 
        if (islpci_get_state(priv) < PRV_STATE_INIT)
-               return;
+               return 0;
 
-       rvalue = mgt_commit_list(priv, commit_part1,
-                                sizeof (commit_part1) /
-                                sizeof (commit_part1[0]));
+       rvalue = mgt_commit_list(priv, commit_part1, VEC_SIZE(commit_part1));
 
        if (priv->iw_mode != IW_MODE_MONITOR)
-               rvalue |= mgt_commit_list(priv, commit_part2,
-                                         sizeof (commit_part2) /
-                                         sizeof (commit_part2[0]));
+               rvalue |= mgt_commit_list(priv, commit_part2, VEC_SIZE(commit_part2));
 
        u = OID_INL_MODE;
        rvalue |= mgt_commit_list(priv, &u, 1);
+       rvalue |= mgt_update_addr(priv);
 
        if (rvalue) {
                /* some request have failed. The device might be in an
                   incoherent state. We should reset it ! */
-               printk(KERN_DEBUG "%s: mgt_commit has failed. Restart the "
-                "device \n", priv->ndev->name);
+               printk(KERN_DEBUG "%s: mgt_commit: failure\n", priv->ndev->name);
        }
+       return rvalue;
+}
 
-       /* update the MAC addr. As it's not cached, no lock will be acquired by
-        * the mgt_get_request
-        */
-       mgt_get_request(priv, GEN_OID_MACADDRESS, 0, NULL, &r);
-       memcpy(priv->ndev->dev_addr, r.ptr, 6);
-       kfree(r.ptr);
+/* The following OIDs need to be "unlatched":
+ *
+ * MEDIUMLIMIT,BEACONPERIOD,DTIMPERIOD,ATIMWINDOW,LISTENINTERVAL
+ * FREQUENCY,EXTENDEDRATES.
+ *
+ * The way to do this is to set ESSID. Note though that they may get
+ * unlatch before though by setting another OID. */
+#if 0
+void
+mgt_unlatch_all(islpci_private *priv)
+{
+       u32 u;
+       int rvalue = 0;
+
+       if (islpci_get_state(priv) < PRV_STATE_INIT)
+               return;
+
+       u = DOT11_OID_SSID;
+       rvalue = mgt_commit_list(priv, &u, 1);
+       /* Necessary if in MANUAL RUN mode? */
+#if 0
+       u = OID_INL_MODE;
+       rvalue |= mgt_commit_list(priv, &u, 1);
+
+       u = DOT11_OID_MLMEAUTOLEVEL;
+       rvalue |= mgt_commit_list(priv, &u, 1);
 
+       u = OID_INL_MODE;
+       rvalue |= mgt_commit_list(priv, &u, 1);
+#endif
+
+       if (rvalue)
+               printk(KERN_DEBUG "%s: Unlatching OIDs failed\n", priv->ndev->name);
 }
+#endif
 
 /* This will tell you if you are allowed to answer a mlme(ex) request .*/
 
-inline int
+int
 mgt_mlme_answer(islpci_private *priv)
 {
        u32 mlmeautolevel;
@@ -682,18 +775,18 @@ mgt_mlme_answer(islpci_private *priv)
                (mlmeautolevel >= DOT11_MLME_INTERMEDIATE));
 }
 
-inline enum oid_num_t
+enum oid_num_t
 mgt_oidtonum(u32 oid)
 {
        int i;
 
-       for (i = 0; i < OID_NUM_LAST - 1; i++)
+       for (i = 0; i < OID_NUM_LAST; i++)
                if (isl_oid[i].oid == oid)
                        return i;
 
        printk(KERN_DEBUG "looking for an unknown oid 0x%x", oid);
 
-       return 0;
+       return OID_NUM_LAST;
 }
 
 int
@@ -713,8 +806,11 @@ mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str)
        case OID_TYPE_BSS:{
                        struct obj_bss *bss = r->ptr;
                        return snprintf(str, PRIV_STR_SIZE,
-                                       "age=%u\nchannel=%u\n\
-                                       capinfo=0x%X\nrates=0x%X\nbasic_rates=0x%X\n", bss->age, bss->channel, bss->capinfo, bss->rates, bss->basic_rates);
+                                       "age=%u\nchannel=%u\n"
+                                       "capinfo=0x%X\nrates=0x%X\n"
+                                       "basic_rates=0x%X\n", bss->age,
+                                       bss->channel, bss->capinfo,
+                                       bss->rates, bss->basic_rates);
                }
                break;
        case OID_TYPE_BSSLIST:{
@@ -723,7 +819,9 @@ mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str)
                        k = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", list->nr);
                        for (i = 0; i < list->nr; i++)
                                k += snprintf(str + k, PRIV_STR_SIZE - k,
-                                             "bss[%u] : \nage=%u\nchannel=%u\ncapinfo=0x%X\nrates=0x%X\nbasic_rates=0x%X\n",
+                                             "bss[%u] : \nage=%u\nchannel=%u\n"
+                                             "capinfo=0x%X\nrates=0x%X\n"
+                                             "basic_rates=0x%X\n",
                                              i, list->bsslist[i].age,
                                              list->bsslist[i].channel,
                                              list->bsslist[i].capinfo,
@@ -745,23 +843,33 @@ mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str)
                break;
        case OID_TYPE_MLME:{
                        struct obj_mlme *mlme = r->ptr;
-                       return snprintf(str, PRIV_STR_SIZE, "id=0x%X\nstate=0x%X\n\
-                                code=0x%X\n", mlme->id, mlme->state,
-                                       mlme->code);
+                       return snprintf(str, PRIV_STR_SIZE,
+                                       "id=0x%X\nstate=0x%X\ncode=0x%X\n",
+                                       mlme->id, mlme->state, mlme->code);
                }
                break;
        case OID_TYPE_MLMEEX:{
                        struct obj_mlmeex *mlme = r->ptr;
-                       return snprintf(str, PRIV_STR_SIZE, "id=0x%X\nstate=0x%X\n\
-                                code=0x%X\nsize=0x%X\n", mlme->id, mlme->state,
-                                       mlme->code, mlme->size);
+                       return snprintf(str, PRIV_STR_SIZE,
+                                       "id=0x%X\nstate=0x%X\n"
+                                       "code=0x%X\nsize=0x%X\n", mlme->id,
+                                       mlme->state, mlme->code, mlme->size);
+               }
+               break;
+       case OID_TYPE_ATTACH:{
+                       struct obj_attachment *attach = r->ptr;
+                       return snprintf(str, PRIV_STR_SIZE,
+                                       "id=%d\nsize=%d\n",
+                                       attach->id,
+                                       attach->size);
                }
                break;
        case OID_TYPE_SSID:{
                        struct obj_ssid *ssid = r->ptr;
                        return snprintf(str, PRIV_STR_SIZE,
-                                       "length=%u\noctets=%s\n",
-                                       ssid->length, ssid->octets);
+                                       "length=%u\noctets=%.*s\n",
+                                       ssid->length, ssid->length,
+                                       ssid->octets);
                }
                break;
        case OID_TYPE_KEY:{