Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
0002 /*
0003  *
0004  * Request/Indication/MacMgmt interface handling functions
0005  *
0006  * Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
0007  * --------------------------------------------------------------------
0008  *
0009  * linux-wlan
0010  *
0011  *   The contents of this file are subject to the Mozilla Public
0012  *   License Version 1.1 (the "License"); you may not use this file
0013  *   except in compliance with the License. You may obtain a copy of
0014  *   the License at http://www.mozilla.org/MPL/
0015  *
0016  *   Software distributed under the License is distributed on an "AS
0017  *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
0018  *   implied. See the License for the specific language governing
0019  *   rights and limitations under the License.
0020  *
0021  *   Alternatively, the contents of this file may be used under the
0022  *   terms of the GNU Public License version 2 (the "GPL"), in which
0023  *   case the provisions of the GPL are applicable instead of the
0024  *   above.  If you wish to allow the use of your version of this file
0025  *   only under the terms of the GPL and not to allow others to use
0026  *   your version of this file under the MPL, indicate your decision
0027  *   by deleting the provisions above and replace them with the notice
0028  *   and other provisions required by the GPL.  If you do not delete
0029  *   the provisions above, a recipient may use your version of this
0030  *   file under either the MPL or the GPL.
0031  *
0032  * --------------------------------------------------------------------
0033  *
0034  * Inquiries regarding the linux-wlan Open Source project can be
0035  * made directly to:
0036  *
0037  * AbsoluteValue Systems Inc.
0038  * info@linux-wlan.com
0039  * http://www.linux-wlan.com
0040  *
0041  * --------------------------------------------------------------------
0042  *
0043  * Portions of the development of this software were funded by
0044  * Intersil Corporation as part of PRISM(R) chipset product development.
0045  *
0046  * --------------------------------------------------------------------
0047  *
0048  * This file contains the functions, types, and macros to support the
0049  * MLME request interface that's implemented via the device ioctls.
0050  *
0051  * --------------------------------------------------------------------
0052  */
0053 
0054 #include <linux/module.h>
0055 #include <linux/kernel.h>
0056 #include <linux/sched.h>
0057 #include <linux/types.h>
0058 #include <linux/skbuff.h>
0059 #include <linux/wireless.h>
0060 #include <linux/netdevice.h>
0061 #include <linux/etherdevice.h>
0062 #include <net/sock.h>
0063 #include <linux/netlink.h>
0064 
0065 #include "p80211types.h"
0066 #include "p80211hdr.h"
0067 #include "p80211mgmt.h"
0068 #include "p80211conv.h"
0069 #include "p80211msg.h"
0070 #include "p80211netdev.h"
0071 #include "p80211ioctl.h"
0072 #include "p80211metadef.h"
0073 #include "p80211metastruct.h"
0074 #include "p80211req.h"
0075 
0076 static void p80211req_handlemsg(struct wlandevice *wlandev,
0077                 struct p80211msg *msg);
0078 static void p80211req_mibset_mibget(struct wlandevice *wlandev,
0079                     struct p80211msg_dot11req_mibget *mib_msg,
0080                     int isget);
0081 
0082 static void p80211req_handle_action(struct wlandevice *wlandev, u32 *data,
0083                     int isget, u32 flag)
0084 {
0085     if (isget) {
0086         if (wlandev->hostwep & flag)
0087             *data = P80211ENUM_truth_true;
0088         else
0089             *data = P80211ENUM_truth_false;
0090     } else {
0091         wlandev->hostwep &= ~flag;
0092         if (*data == P80211ENUM_truth_true)
0093             wlandev->hostwep |= flag;
0094     }
0095 }
0096 
0097 /*----------------------------------------------------------------
0098  * p80211req_dorequest
0099  *
0100  * Handles an MLME request/confirm message.
0101  *
0102  * Arguments:
0103  *  wlandev     WLAN device struct
0104  *  msgbuf      Buffer containing a request message
0105  *
0106  * Returns:
0107  *  0 on success, an errno otherwise
0108  *
0109  * Call context:
0110  *  Potentially blocks the caller, so it's a good idea to
0111  *  not call this function from an interrupt context.
0112  *----------------------------------------------------------------
0113  */
0114 int p80211req_dorequest(struct wlandevice *wlandev, u8 *msgbuf)
0115 {
0116     struct p80211msg *msg = (struct p80211msg *)msgbuf;
0117 
0118     /* Check to make sure the MSD is running */
0119     if (!((wlandev->msdstate == WLAN_MSD_HWPRESENT &&
0120            msg->msgcode == DIDMSG_LNXREQ_IFSTATE) ||
0121           wlandev->msdstate == WLAN_MSD_RUNNING ||
0122           wlandev->msdstate == WLAN_MSD_FWLOAD)) {
0123         return -ENODEV;
0124     }
0125 
0126     /* Check Permissions */
0127     if (!capable(CAP_NET_ADMIN) &&
0128         (msg->msgcode != DIDMSG_DOT11REQ_MIBGET)) {
0129         netdev_err(wlandev->netdev,
0130                "%s: only dot11req_mibget allowed for non-root.\n",
0131                wlandev->name);
0132         return -EPERM;
0133     }
0134 
0135     /* Check for busy status */
0136     if (test_and_set_bit(1, &wlandev->request_pending))
0137         return -EBUSY;
0138 
0139     /* Allow p80211 to look at msg and handle if desired. */
0140     /* So far, all p80211 msgs are immediate, no waitq/timer necessary */
0141     /* This may change. */
0142     p80211req_handlemsg(wlandev, msg);
0143 
0144     /* Pass it down to wlandev via wlandev->mlmerequest */
0145     if (wlandev->mlmerequest)
0146         wlandev->mlmerequest(wlandev, msg);
0147 
0148     clear_bit(1, &wlandev->request_pending);
0149     return 0;   /* if result==0, msg->status still may contain an err */
0150 }
0151 
0152 /*----------------------------------------------------------------
0153  * p80211req_handlemsg
0154  *
0155  * p80211 message handler.  Primarily looks for messages that
0156  * belong to p80211 and then dispatches the appropriate response.
0157  * TODO: we don't do anything yet.  Once the linuxMIB is better
0158  *  defined we'll need a get/set handler.
0159  *
0160  * Arguments:
0161  *  wlandev     WLAN device struct
0162  *  msg     message structure
0163  *
0164  * Returns:
0165  *  nothing (any results are set in the status field of the msg)
0166  *
0167  * Call context:
0168  *  Process thread
0169  *----------------------------------------------------------------
0170  */
0171 static void p80211req_handlemsg(struct wlandevice *wlandev,
0172                 struct p80211msg *msg)
0173 {
0174     switch (msg->msgcode) {
0175     case DIDMSG_LNXREQ_HOSTWEP: {
0176         struct p80211msg_lnxreq_hostwep *req =
0177             (struct p80211msg_lnxreq_hostwep *)msg;
0178         wlandev->hostwep &=
0179                 ~(HOSTWEP_DECRYPT | HOSTWEP_ENCRYPT);
0180         if (req->decrypt.data == P80211ENUM_truth_true)
0181             wlandev->hostwep |= HOSTWEP_DECRYPT;
0182         if (req->encrypt.data == P80211ENUM_truth_true)
0183             wlandev->hostwep |= HOSTWEP_ENCRYPT;
0184 
0185         break;
0186     }
0187     case DIDMSG_DOT11REQ_MIBGET:
0188     case DIDMSG_DOT11REQ_MIBSET: {
0189         int isget = (msg->msgcode == DIDMSG_DOT11REQ_MIBGET);
0190         struct p80211msg_dot11req_mibget *mib_msg =
0191             (struct p80211msg_dot11req_mibget *)msg;
0192         p80211req_mibset_mibget(wlandev, mib_msg, isget);
0193         break;
0194     }
0195     }           /* switch msg->msgcode */
0196 }
0197 
0198 static void p80211req_mibset_mibget(struct wlandevice *wlandev,
0199                     struct p80211msg_dot11req_mibget *mib_msg,
0200                     int isget)
0201 {
0202     struct p80211itemd *mibitem =
0203         (struct p80211itemd *)mib_msg->mibattribute.data;
0204     struct p80211pstrd *pstr = (struct p80211pstrd *)mibitem->data;
0205     u8 *key = mibitem->data + sizeof(struct p80211pstrd);
0206 
0207     switch (mibitem->did) {
0208     case didmib_dot11smt_wepdefaultkeystable_key(1):
0209     case didmib_dot11smt_wepdefaultkeystable_key(2):
0210     case didmib_dot11smt_wepdefaultkeystable_key(3):
0211     case didmib_dot11smt_wepdefaultkeystable_key(4):
0212         if (!isget)
0213             wep_change_key(wlandev,
0214                        P80211DID_ITEM(mibitem->did) - 1,
0215                        key, pstr->len);
0216         break;
0217 
0218     case DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID: {
0219         u32 *data = (u32 *)mibitem->data;
0220 
0221         if (isget) {
0222             *data = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
0223         } else {
0224             wlandev->hostwep &= ~(HOSTWEP_DEFAULTKEY_MASK);
0225             wlandev->hostwep |= (*data & HOSTWEP_DEFAULTKEY_MASK);
0226         }
0227         break;
0228     }
0229     case DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED: {
0230         u32 *data = (u32 *)mibitem->data;
0231 
0232         p80211req_handle_action(wlandev, data, isget,
0233                     HOSTWEP_PRIVACYINVOKED);
0234         break;
0235     }
0236     case DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED: {
0237         u32 *data = (u32 *)mibitem->data;
0238 
0239         p80211req_handle_action(wlandev, data, isget,
0240                     HOSTWEP_EXCLUDEUNENCRYPTED);
0241         break;
0242     }
0243     }
0244 }