text: /*
   * Copyright (c) 1996, 2005 VIA Networking Technologies, Inc.
   * All rights reserved.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License along
   * with this program; if not, write to the Free Software Foundation, Inc.,
   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   *
   * File: IEEE11h.c
   *
   * Purpose:
   *
   * Functions:
   *
   * Revision History:
   *
   * Author: Yiching Chen
   *
   * Date: Mar. 31, 2005
   *
   */
  
  #include "ttype.h"
  #include "tmacro.h"
  #include "tether.h"
  #include "IEEE11h.h"
  #include "device.h"
  #include "wmgr.h"
  #include "rxtx.h"
  #include "channel.h"
  
  /*---------------------  Static Definitions -------------------------*/
  static int          msglevel                =MSG_LEVEL_INFO;
  
  #pragma pack(1)
  
  typedef struct _WLAN_FRAME_ACTION {
      WLAN_80211HDR_A3    Header;
      unsigned char byCategory;
      unsigned char byAction;
      unsigned char abyVars[1];
  } WLAN_FRAME_ACTION, *PWLAN_FRAME_ACTION;
  
  typedef struct _WLAN_FRAME_MSRREQ {
      WLAN_80211HDR_A3    Header;
      unsigned char byCategory;
      unsigned char byAction;
      unsigned char byDialogToken;
      WLAN_IE_MEASURE_REQ sMSRReqEIDs[1];
  } WLAN_FRAME_MSRREQ, *PWLAN_FRAME_MSRREQ;
  
  typedef struct _WLAN_FRAME_MSRREP {
      WLAN_80211HDR_A3    Header;
      unsigned char byCategory;
      unsigned char byAction;
      unsigned char byDialogToken;
      WLAN_IE_MEASURE_REP sMSRRepEIDs[1];
  } WLAN_FRAME_MSRREP, *PWLAN_FRAME_MSRREP;
  
  typedef struct _WLAN_FRAME_TPCREQ {
      WLAN_80211HDR_A3    Header;
      unsigned char byCategory;
      unsigned char byAction;
      unsigned char byDialogToken;
      WLAN_IE_TPC_REQ     sTPCReqEIDs;
  } WLAN_FRAME_TPCREQ, *PWLAN_FRAME_TPCREQ;
  
  typedef struct _WLAN_FRAME_TPCREP {
      WLAN_80211HDR_A3    Header;
      unsigned char byCategory;
      unsigned char byAction;
      unsigned char byDialogToken;
      WLAN_IE_TPC_REP     sTPCRepEIDs;
  } WLAN_FRAME_TPCREP, *PWLAN_FRAME_TPCREP;
  
  #pragma pack()
  
  // action field reference ieee 802.11h Table 20e
  #define ACTION_MSRREQ       0
  #define ACTION_MSRREP       1
  #define ACTION_TPCREQ       2
  #define ACTION_TPCREP       3
  #define ACTION_CHSW         4
  
  /*---------------------  Static Classes  ----------------------------*/
  
  /*---------------------  Static Variables  --------------------------*/
  
  /*---------------------  Static Functions  --------------------------*/
  static bool s_bRxMSRReq(PSMgmtObject pMgmt, PWLAN_FRAME_MSRREQ pMSRReq,
  		unsigned int uLength)
  {
      size_t    uNumOfEIDs = 0;
      bool bResult = true;
  
      if (uLength <= WLAN_A3FR_MAXLEN) {
          memcpy(pMgmt->abyCurrentMSRReq, pMSRReq, uLength);
      }
      uNumOfEIDs = ((uLength - offsetof(WLAN_FRAME_MSRREQ, sMSRReqEIDs))/ (sizeof(WLAN_IE_MEASURE_REQ)));
      pMgmt->pCurrMeasureEIDRep = &(((PWLAN_FRAME_MSRREP) (pMgmt->abyCurrentMSRRep))->sMSRRepEIDs[0]);
      pMgmt->uLengthOfRepEIDs = 0;
      bResult = CARDbStartMeasure(pMgmt->pAdapter,
                                  ((PWLAN_FRAME_MSRREQ) (pMgmt->abyCurrentMSRReq))->sMSRReqEIDs,
                                  uNumOfEIDs
                                  );
      return (bResult);
  }
  
  
  static bool s_bRxTPCReq(PSMgmtObject pMgmt, PWLAN_FRAME_TPCREQ pTPCReq, unsigned char byRate, unsigned char byRSSI)
  {
      PWLAN_FRAME_TPCREP  pFrame;
      PSTxMgmtPacket      pTxPacket = NULL;
  
  
      pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
      memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN);
      pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
  
      pFrame = (PWLAN_FRAME_TPCREP)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
  
      pFrame->Header.wFrameCtl = (   WLAN_SET_FC_FTYPE(WLAN_FTYPE_MGMT) |
                                      WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ACTION)
                                  );
  
      memcpy( pFrame->Header.abyAddr1, pTPCReq->Header.abyAddr2, WLAN_ADDR_LEN);
      memcpy( pFrame->Header.abyAddr2, CARDpGetCurrentAddress(pMgmt->pAdapter), WLAN_ADDR_LEN);
      memcpy( pFrame->Header.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
  
      pFrame->byCategory = 0;
      pFrame->byAction = 3;
      pFrame->byDialogToken = ((PWLAN_FRAME_MSRREQ) (pMgmt->abyCurrentMSRReq))->byDialogToken;
  
      pFrame->sTPCRepEIDs.byElementID = WLAN_EID_TPC_REP;
      pFrame->sTPCRepEIDs.len = 2;
      pFrame->sTPCRepEIDs.byTxPower = CARDbyGetTransmitPower(pMgmt->pAdapter);
      switch (byRate) {
          case RATE_54M:
              pFrame->sTPCRepEIDs.byLinkMargin = 65 - byRSSI;
              break;
          case RATE_48M:
              pFrame->sTPCRepEIDs.byLinkMargin = 66 - byRSSI;
              break;
          case RATE_36M:
              pFrame->sTPCRepEIDs.byLinkMargin = 70 - byRSSI;
              break;
          case RATE_24M:
              pFrame->sTPCRepEIDs.byLinkMargin = 74 - byRSSI;
              break;
          case RATE_18M:
              pFrame->sTPCRepEIDs.byLinkMargin = 77 - byRSSI;
              break;
          case RATE_12M:
              pFrame->sTPCRepEIDs.byLinkMargin = 79 - byRSSI;
              break;
          case RATE_9M:
              pFrame->sTPCRepEIDs.byLinkMargin = 81 - byRSSI;
              break;
          case RATE_6M:
          default:
              pFrame->sTPCRepEIDs.byLinkMargin = 82 - byRSSI;
              break;
      }
  
      pTxPacket->cbMPDULen = sizeof(WLAN_FRAME_TPCREP);
      pTxPacket->cbPayloadLen = sizeof(WLAN_FRAME_TPCREP) - WLAN_HDR_ADDR3_LEN;
      if (csMgmt_xmit(pMgmt->pAdapter, pTxPacket) != CMD_STATUS_PENDING)
          return (false);
      return (true);
  //    return (CARDbSendPacket(pMgmt->pAdapter, pFrame, PKT_TYPE_802_11_MNG, sizeof(WLAN_FRAME_TPCREP)));
  
  }
  
  
  /*---------------------  Export Variables  --------------------------*/
  
  /*---------------------  Export Functions  --------------------------*/
  
  
  /*+
   *
   * Description:
   *      Handles action management frames.
   *
   * Parameters:
   *  In:
   *      pMgmt           - Management Object structure
   *      pRxPacket       - Received packet
   *  Out:
   *      none
   *
   * Return Value: None.
   *
  -*/
  bool
  IEEE11hbMgrRxAction (
      void *pMgmtHandle,
      void *pRxPacket
      )
  {
      PSMgmtObject            pMgmt = (PSMgmtObject) pMgmtHandle;
      PWLAN_FRAME_ACTION      pAction = NULL;
      unsigned int uLength = 0;
      PWLAN_IE_CH_SW          pChannelSwitch = NULL;
  
  
      // decode the frame
      uLength = ((PSRxMgmtPacket)pRxPacket)->cbMPDULen;
      if (uLength > WLAN_A3FR_MAXLEN) {
          return (false);
      }
  
  
      pAction = (PWLAN_FRAME_ACTION) (((PSRxMgmtPacket)pRxPacket)->p80211Header);
  
      if (pAction->byCategory == 0) {
          switch (pAction->byAction) {
              case ACTION_MSRREQ:
                  return (s_bRxMSRReq(pMgmt, (PWLAN_FRAME_MSRREQ) pAction, uLength));
                  break;
              case ACTION_MSRREP:
                  break;
              case ACTION_TPCREQ:
                  return (s_bRxTPCReq(pMgmt,
                                      (PWLAN_FRAME_TPCREQ) pAction,
                                      ((PSRxMgmtPacket)pRxPacket)->byRxRate,
                                      (unsigned char) ((PSRxMgmtPacket)pRxPacket)->uRSSI));
                  break;
              case ACTION_TPCREP:
                  break;
              case ACTION_CHSW:
                  pChannelSwitch = (PWLAN_IE_CH_SW) (pAction->abyVars);
                  if ((pChannelSwitch->byElementID == WLAN_EID_CH_SWITCH) &&
                      (pChannelSwitch->len == 3)) {
                      // valid element id
                      CARDbChannelSwitch( pMgmt->pAdapter,
                                          pChannelSwitch->byMode,
                                          get_channel_mapping(pMgmt->pAdapter, pChannelSwitch->byChannel, pMgmt->eCurrentPHYMode),
                                          pChannelSwitch->byCount
                                          );
                  }
                  break;
              default:
                  DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Unknown Action = %d\n", pAction->byAction);
                  break;
          }
      } else {
          DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Unknown Category = %d\n", pAction->byCategory);
          pAction->byCategory |= 0x80;
  
         //return (CARDbSendPacket(pMgmt->pAdapter, pAction, PKT_TYPE_802_11_MNG, uLength));
          return (true);
      }
      return (true);
  }
  
  
  bool IEEE11hbMSRRepTx (
      void *pMgmtHandle
      )
  {
      PSMgmtObject            pMgmt = (PSMgmtObject) pMgmtHandle;
      PWLAN_FRAME_MSRREP      pMSRRep = (PWLAN_FRAME_MSRREP) (pMgmt->abyCurrentMSRRep + sizeof(STxMgmtPacket));
      size_t                    uLength = 0;
      PSTxMgmtPacket          pTxPacket = NULL;
  
      pTxPacket = (PSTxMgmtPacket)pMgmt->abyCurrentMSRRep;
      memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN);
      pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
  
  
      pMSRRep->Header.wFrameCtl = (   WLAN_SET_FC_FTYPE(WLAN_FTYPE_MGMT) |
                                      WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ACTION)
                                  );
  
      memcpy( pMSRRep->Header.abyAddr1, ((PWLAN_FRAME_MSRREQ) (pMgmt->abyCurrentMSRReq))->Header.abyAddr2, WLAN_ADDR_LEN);
      memcpy( pMSRRep->Header.abyAddr2, CARDpGetCurrentAddress(pMgmt->pAdapter), WLAN_ADDR_LEN);
      memcpy( pMSRRep->Header.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
  
      pMSRRep->byCategory = 0;
      pMSRRep->byAction = 1;
      pMSRRep->byDialogToken = ((PWLAN_FRAME_MSRREQ) (pMgmt->abyCurrentMSRReq))->byDialogToken;
  
      uLength = pMgmt->uLengthOfRepEIDs + offsetof(WLAN_FRAME_MSRREP, sMSRRepEIDs);
  
      pTxPacket->cbMPDULen = uLength;
      pTxPacket->cbPayloadLen = uLength - WLAN_HDR_ADDR3_LEN;
      if (csMgmt_xmit(pMgmt->pAdapter, pTxPacket) != CMD_STATUS_PENDING)
          return (false);
      return (true);
  //    return (CARDbSendPacket(pMgmt->pAdapter, pMSRRep, PKT_TYPE_802_11_MNG, uLength));
  
  }
  