linux/drivers/staging/wlan-ng/p80211req.c
<<
>>
Prefs
   1/* src/p80211/p80211req.c
   2*
   3* Request/Indication/MacMgmt interface handling functions
   4*
   5* Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
   6* --------------------------------------------------------------------
   7*
   8* linux-wlan
   9*
  10*   The contents of this file are subject to the Mozilla Public
  11*   License Version 1.1 (the "License"); you may not use this file
  12*   except in compliance with the License. You may obtain a copy of
  13*   the License at http://www.mozilla.org/MPL/
  14*
  15*   Software distributed under the License is distributed on an "AS
  16*   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  17*   implied. See the License for the specific language governing
  18*   rights and limitations under the License.
  19*
  20*   Alternatively, the contents of this file may be used under the
  21*   terms of the GNU Public License version 2 (the "GPL"), in which
  22*   case the provisions of the GPL are applicable instead of the
  23*   above.  If you wish to allow the use of your version of this file
  24*   only under the terms of the GPL and not to allow others to use
  25*   your version of this file under the MPL, indicate your decision
  26*   by deleting the provisions above and replace them with the notice
  27*   and other provisions required by the GPL.  If you do not delete
  28*   the provisions above, a recipient may use your version of this
  29*   file under either the MPL or the GPL.
  30*
  31* --------------------------------------------------------------------
  32*
  33* Inquiries regarding the linux-wlan Open Source project can be
  34* made directly to:
  35*
  36* AbsoluteValue Systems Inc.
  37* info@linux-wlan.com
  38* http://www.linux-wlan.com
  39*
  40* --------------------------------------------------------------------
  41*
  42* Portions of the development of this software were funded by
  43* Intersil Corporation as part of PRISM(R) chipset product development.
  44*
  45* --------------------------------------------------------------------
  46*
  47* This file contains the functions, types, and macros to support the
  48* MLME request interface that's implemented via the device ioctls.
  49*
  50* --------------------------------------------------------------------
  51*/
  52
  53#include <linux/module.h>
  54#include <linux/kernel.h>
  55#include <linux/sched.h>
  56#include <linux/types.h>
  57#include <linux/skbuff.h>
  58#include <linux/wireless.h>
  59#include <linux/netdevice.h>
  60#include <linux/etherdevice.h>
  61#include <net/sock.h>
  62#include <linux/netlink.h>
  63
  64#include "p80211types.h"
  65#include "p80211hdr.h"
  66#include "p80211mgmt.h"
  67#include "p80211conv.h"
  68#include "p80211msg.h"
  69#include "p80211netdev.h"
  70#include "p80211ioctl.h"
  71#include "p80211metadef.h"
  72#include "p80211metastruct.h"
  73#include "p80211req.h"
  74
  75static void p80211req_handlemsg(wlandevice_t *wlandev, struct p80211msg *msg);
  76static void p80211req_mibset_mibget(wlandevice_t *wlandev,
  77                                   struct p80211msg_dot11req_mibget *mib_msg,
  78                                   int isget);
  79
  80/*----------------------------------------------------------------
  81* p80211req_dorequest
  82*
  83* Handles an MLME reqest/confirm message.
  84*
  85* Arguments:
  86*       wlandev         WLAN device struct
  87*       msgbuf          Buffer containing a request message
  88*
  89* Returns:
  90*       0 on success, an errno otherwise
  91*
  92* Call context:
  93*       Potentially blocks the caller, so it's a good idea to
  94*       not call this function from an interrupt context.
  95----------------------------------------------------------------*/
  96int p80211req_dorequest(wlandevice_t *wlandev, u8 *msgbuf)
  97{
  98        struct p80211msg *msg = (struct p80211msg *) msgbuf;
  99
 100        /* Check to make sure the MSD is running */
 101        if (!((wlandev->msdstate == WLAN_MSD_HWPRESENT &&
 102               msg->msgcode == DIDmsg_lnxreq_ifstate) ||
 103              wlandev->msdstate == WLAN_MSD_RUNNING ||
 104              wlandev->msdstate == WLAN_MSD_FWLOAD)) {
 105                return -ENODEV;
 106        }
 107
 108        /* Check Permissions */
 109        if (!capable(CAP_NET_ADMIN) &&
 110        (msg->msgcode != DIDmsg_dot11req_mibget)) {
 111                netdev_err(wlandev->netdev,
 112                           "%s: only dot11req_mibget allowed for non-root.\n",
 113                           wlandev->name);
 114                return -EPERM;
 115        }
 116
 117        /* Check for busy status */
 118        if (test_and_set_bit(1, &(wlandev->request_pending)))
 119                return -EBUSY;
 120
 121        /* Allow p80211 to look at msg and handle if desired. */
 122        /* So far, all p80211 msgs are immediate, no waitq/timer necessary */
 123        /* This may change. */
 124        p80211req_handlemsg(wlandev, msg);
 125
 126        /* Pass it down to wlandev via wlandev->mlmerequest */
 127        if (wlandev->mlmerequest != NULL)
 128                wlandev->mlmerequest(wlandev, msg);
 129
 130        clear_bit(1, &(wlandev->request_pending));
 131        return 0;       /* if result==0, msg->status still may contain an err */
 132}
 133
 134/*----------------------------------------------------------------
 135* p80211req_handlemsg
 136*
 137* p80211 message handler.  Primarily looks for messages that
 138* belong to p80211 and then dispatches the appropriate response.
 139* TODO: we don't do anything yet.  Once the linuxMIB is better
 140*       defined we'll need a get/set handler.
 141*
 142* Arguments:
 143*       wlandev         WLAN device struct
 144*       msg             message structure
 145*
 146* Returns:
 147*       nothing (any results are set in the status field of the msg)
 148*
 149* Call context:
 150*       Process thread
 151----------------------------------------------------------------*/
 152static void p80211req_handlemsg(wlandevice_t *wlandev, struct p80211msg *msg)
 153{
 154        switch (msg->msgcode) {
 155
 156        case DIDmsg_lnxreq_hostwep:{
 157                struct p80211msg_lnxreq_hostwep *req =
 158                        (struct p80211msg_lnxreq_hostwep *) msg;
 159                wlandev->hostwep &=
 160                                ~(HOSTWEP_DECRYPT | HOSTWEP_ENCRYPT);
 161                if (req->decrypt.data == P80211ENUM_truth_true)
 162                        wlandev->hostwep |= HOSTWEP_DECRYPT;
 163                if (req->encrypt.data == P80211ENUM_truth_true)
 164                        wlandev->hostwep |= HOSTWEP_ENCRYPT;
 165
 166        break;
 167        }
 168        case DIDmsg_dot11req_mibget:
 169        case DIDmsg_dot11req_mibset:{
 170                int isget = (msg->msgcode == DIDmsg_dot11req_mibget);
 171                struct p80211msg_dot11req_mibget *mib_msg =
 172                        (struct p80211msg_dot11req_mibget *) msg;
 173                p80211req_mibset_mibget(wlandev, mib_msg, isget);
 174        break;
 175        }
 176        }                       /* switch msg->msgcode */
 177}
 178
 179static void p80211req_mibset_mibget(wlandevice_t *wlandev,
 180                                   struct p80211msg_dot11req_mibget *mib_msg,
 181                                   int isget)
 182{
 183        p80211itemd_t *mibitem = (p80211itemd_t *) mib_msg->mibattribute.data;
 184        p80211pstrd_t *pstr = (p80211pstrd_t *) mibitem->data;
 185        u8 *key = mibitem->data + sizeof(p80211pstrd_t);
 186
 187        switch (mibitem->did) {
 188        case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0:{
 189                if (!isget)
 190                        wep_change_key(wlandev, 0, key, pstr->len);
 191        break;
 192        }
 193        case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1:{
 194                if (!isget)
 195                        wep_change_key(wlandev, 1, key, pstr->len);
 196        break;
 197        }
 198        case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2:{
 199                if (!isget)
 200                        wep_change_key(wlandev, 2, key, pstr->len);
 201        break;
 202        }
 203        case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3:{
 204                if (!isget)
 205                        wep_change_key(wlandev, 3, key, pstr->len);
 206        break;
 207        }
 208        case DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID:{
 209                u32 *data = (u32 *) mibitem->data;
 210
 211                if (isget) {
 212                        *data = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
 213                } else {
 214                        wlandev->hostwep &= ~(HOSTWEP_DEFAULTKEY_MASK);
 215                        wlandev->hostwep |= (*data & HOSTWEP_DEFAULTKEY_MASK);
 216                }
 217        break;
 218        }
 219        case DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked:{
 220                u32 *data = (u32 *) mibitem->data;
 221
 222                if (isget) {
 223                        if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED)
 224                                *data = P80211ENUM_truth_true;
 225                        else
 226                                *data = P80211ENUM_truth_false;
 227                } else {
 228                        wlandev->hostwep &= ~(HOSTWEP_PRIVACYINVOKED);
 229                        if (*data == P80211ENUM_truth_true)
 230                                wlandev->hostwep |= HOSTWEP_PRIVACYINVOKED;
 231                }
 232        break;
 233        }
 234        case DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted:{
 235                u32 *data = (u32 *) mibitem->data;
 236
 237                if (isget) {
 238                        if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED)
 239                                *data = P80211ENUM_truth_true;
 240                        else
 241                                *data = P80211ENUM_truth_false;
 242                } else {
 243                        wlandev->hostwep &= ~(HOSTWEP_EXCLUDEUNENCRYPTED);
 244                        if (*data == P80211ENUM_truth_true)
 245                                wlandev->hostwep |= HOSTWEP_EXCLUDEUNENCRYPTED;
 246                }
 247        break;
 248        }
 249        }
 250}
 251